Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2006
- 112 participants
- 190 discussions
15 Dec '06
On 12/15/06, Clinton Stimpson <cjstimpson(a)utwire.net> wrote:
> Hi,
>
> Here's a patch to make unimplemented functions return E_NOTIMPL instead
> of S_OK. Even dependent functions already return E_NOTIMPL. Also
> fixing tests to check that the return value is S_OK before testing the
> 'out' parameters.
> This fix allows piecemeal patches to follow with implementation for each
> function in a separate patch.
>
> Thanks,
> Clinton Stimpson
>
> ChangeLog
> Return E_NOTIMPL where appropriate.
> And only check out parameters when appropriate.
>
There are a couple things wrong with this patch. First, you've made
it so the tests won't be run for these functions (because they don't
return S_OK as it stands). Second, there are probably applications
that depend on these functions returning S_OK. You're really making
it a lot harder than it should be. Implement each function one at a
time. If tests start to succeed, just remove the todo_wine from them.
So the implemented function and removed/added go in one patch. You
just do that for each function you're implementing.
--
James Hawkins
2
1
Am Freitag 15 Dezember 2006 08:02 schrieb Dmitry Timoshkov:
> Hello,
>
> Changelog:
> ddraw: Fix warnings.
>
> ---
> dlls/ddraw/ddraw_thunks.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/dlls/ddraw/ddraw_thunks.c b/dlls/ddraw/ddraw_thunks.c
> index ef8af6b..99518f0 100644
> --- a/dlls/ddraw/ddraw_thunks.c
> +++ b/dlls/ddraw/ddraw_thunks.c
> @@ -112,7 +112,7 @@ IDirectDraw3Impl_AddRef(LPDIRECTDRAW3 iface)
> ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw3, iface);
> ULONG ref = InterlockedIncrement(&This->ref4);
>
> - TRACE("(%p) : incrementing IDirectDraw4 refcount from %lu.\n", This,
> ref -1); + TRACE("(%p) : incrementing IDirectDraw4 refcount from %u.\n",
> This, ref -1);
Sorry I forgot to check your original patch for this, but did you check if the
IDirectDraw3 refcount is bound to the IDirectDraw4 refcount? I'd suspect that
the IDirectDraw3 interface has its own reference count too. See
dlls/ddraw/tests/refcount.c
2
2
Onsdag 13 desember 2006 19:14, skrev Chris Morgan:
> If you didn't receive an email about how you haven't logged in in a
> while then it isn't likely that the appdb cleanup system removed your
> super maintainership. Could this possibly be related to the super
> maintainer changes you put in recently? Like if you process a
> submitted application does it remove your super maintainer status for
> some other apps?
>
> We unfortunately don't log events on the appdb. If we did we could log
> all kinds of stuff and go back and figure out when your entry was
> removed.
>
> Chris
I couldn't find anything suspicious in my changes, and everything was OK when
I was logged in yesterday. I applied as super maintainer for an app and
approved one in the queue, but that did not remove me. It seems like all the
removals (not just mine) happened between today and yesterday.
Regards,
Alexander N. Sørnes
>
> On 12/13/06, Alexander Nicolaysen Sørnes <alex(a)thehandofagony.com> wrote:
> > Hello,
> >
> > It seems like I have been removed from all the applications I was
> > previously a super maintainer of. All my non-super maintainerships seem
> > to be unaffected. Does anyone know the reason? Is it related to the
> > recent server problems?
> >
> >
> > Regards,
> >
> > Alexander N. Sørnes
> > AppDB Administrator
5
5
Re: usp10: implement ScriptStringAnalyse, ScriptStringFree, ScriptStringXtoCP, ScriptStringCPtoX
by Clinton Stimpson 14 Dec '06
by Clinton Stimpson 14 Dec '06
14 Dec '06
Hi,
Can I get some feedback on this patch?
It appears to have been rejected.
Thanks,
Clinton
Clinton Stimpson wrote:
>
> This patch implements ScriptStringAnalyse, ScriptStringFree,
> ScriptStringXtoCP, ScriptStringCPtoX.
>
> Also, many todo_wine's are removed.
>
>
> Thanks,
> Clinton Stimpson
>
> ChangeLog
> Implement ScriptStringAnalyse, ScriptStringFree,
> ScriptStringXtoCP, ScriptStringCPtoX
>
>
> ------------------------------------------------------------------------
>
> Index: dlls/usp10/usp10.c
> ===================================================================
> RCS file: /home/wine/wine/dlls/usp10/usp10.c,v
> retrieving revision 1.45
> diff -u -r1.45 usp10.c
> --- dlls/usp10/usp10.c 12 Dec 2006 20:30:48 -0000 1.45
> +++ dlls/usp10/usp10.c 13 Dec 2006 03:28:30 -0000
> @@ -73,6 +73,46 @@
> HDC hdc;
> } Scriptcache;
>
> +typedef struct {
> + int numGlyphs;
> + WORD* glyphs;
> + WORD* pwLogClust;
> + int* piAdvance;
> + SCRIPT_VISATTR* psva;
> + GOFFSET* pGoffset;
> + ABC* abc;
> +} StringGlyphs;
> +
> +typedef struct {
> + BOOL invalid;
> + HDC hdc;
> + int cItems;
> + int cMaxGlyphs;
> + SCRIPT_ITEM* pItem;
> + int numItems;
> + StringGlyphs* glyphs;
> + SIZE* sz;
> +} StringAnalysis;
> +
> +static void ME_StringAnalysisFree(StringAnalysis* analysis)
> +{
> + int i;
> + for(i=0; i<analysis->numItems; i++)
> + {
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].glyphs);
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].pwLogClust);
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].piAdvance);
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].psva);
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].pGoffset);
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs[i].abc);
> + }
> +
> + HeapFree(GetProcessHeap(), 0, analysis->glyphs);
> + HeapFree(GetProcessHeap(), 0, analysis->pItem);
> +
> + HeapFree(GetProcessHeap(), 0, analysis);
> +}
> +
> /***********************************************************************
> * DllMain
> *
> @@ -448,9 +488,16 @@
> const BYTE *pbInClass,
> SCRIPT_STRING_ANALYSIS *pssa)
> {
> - FIXME("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p): stub\n",
> - hdc, pString, cString, cGlyphs, iCharset, dwFlags,
> - iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
> + HRESULT hr;
> + StringAnalysis* analysis;
> + int numItemizedItems;
> + int i;
> + SCRIPT_CACHE* sc = 0;
> +
> + TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
> + hdc, pString, cString, cGlyphs, iCharset, dwFlags,
> + iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
> +
> if (1 > cString || NULL == pString) {
> return E_INVALIDARG;
> }
> @@ -458,7 +505,64 @@
> return E_PENDING;
> }
>
> - return E_NOTIMPL;
> + analysis = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
> + sizeof(StringAnalysis));
> +
> + analysis->hdc = hdc;
> + numItemizedItems = 255;
> + analysis->pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
> + numItemizedItems*sizeof(SCRIPT_ITEM)+1);
> +
> + hr = ScriptItemize(pString, cString, numItemizedItems, psControl,
> + psState, analysis->pItem, &analysis->numItems);
> +
> + while(hr == E_OUTOFMEMORY)
> + {
> + numItemizedItems *= 2;
> + HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, analysis->pItem,
> + numItemizedItems*sizeof(SCRIPT_ITEM)+1);
> + hr = ScriptItemize(pString, cString, numItemizedItems, psControl,
> + psState, analysis->pItem, &analysis->numItems);
> + }
> +
> + analysis->glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
> + sizeof(StringGlyphs)*analysis->numItems);
> + sc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SCRIPT_CACHE));
> +
> + for(i=0; i<analysis->numItems; i++)
> + {
> + int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
> + int numGlyphs = 1.5 * cChar + 16;
> + WORD* glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WORD)*numGlyphs);
> + WORD* pwLogClust = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WORD)*cChar);
> + int* piAdvance = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(int)*numGlyphs);
> + SCRIPT_VISATTR* psva = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SCRIPT_VISATTR)*cChar);
> + GOFFSET* pGoffset = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GOFFSET)*numGlyphs);
> + ABC* abc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ABC));
> + int numGlyphsReturned;
> +
> + /* FIXME: non unicode strings */
> + WCHAR* pStr = (WCHAR*)pString;
> + hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
> + cChar, numGlyphs, &analysis->pItem[i].a,
> + glyphs, pwLogClust, psva, &numGlyphsReturned);
> + hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
> + piAdvance, pGoffset, abc);
> +
> + analysis->glyphs[i].numGlyphs = numGlyphsReturned;
> + analysis->glyphs[i].glyphs = glyphs;
> + analysis->glyphs[i].pwLogClust = pwLogClust;
> + analysis->glyphs[i].piAdvance = piAdvance;
> + analysis->glyphs[i].psva = psva;
> + analysis->glyphs[i].pGoffset = pGoffset;
> + analysis->glyphs[i].abc = abc;
> + }
> +
> + HeapFree(GetProcessHeap(), 0, sc);
> +
> + *pssa = analysis;
> +
> + return S_OK;
> }
>
> /***********************************************************************
> @@ -489,9 +593,46 @@
> */
> HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
> {
> - FIXME("(%p), %d, %d, (%p): stub\n", ssa, icp, fTrailing, pX);
> - *pX = 0; /* Set a reasonable value */
> - return S_OK;
> + int i, j;
> + int runningX = 0;
> + int runningCp = 0;
> + StringAnalysis* analysis = ssa;
> + TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
> +
> + if(!ssa || !pX)
> + {
> + return 1;
> + }
> +
> + /* icp out of range */
> + if(icp < 0)
> + {
> + analysis->invalid = TRUE;
> + return E_INVALIDARG;
> + }
> +
> + for(i=0; i<analysis->numItems; i++)
> + {
> + for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
> + {
> + if(runningCp == icp && fTrailing == FALSE)
> + {
> + *pX = runningX;
> + return S_OK;
> + }
> + runningX += analysis->glyphs[i].piAdvance[j];
> + if(runningCp == icp && fTrailing == TRUE)
> + {
> + *pX = runningX;
> + return S_OK;
> + }
> + runningCp++;
> + }
> + }
> +
> + /* icp out of range */
> + analysis->invalid = TRUE;
> + return E_INVALIDARG;
> }
>
> /***********************************************************************
> @@ -500,19 +641,79 @@
> */
> HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
> {
> - FIXME("(%p), %d, (%p), (%p): stub\n", ssa, iX, piCh, piTrailing);
> - *piCh = 0; /* Set a reasonable value */
> - *piTrailing = 0;
> + StringAnalysis* analysis = ssa;
> + int i;
> + int j;
> + int runningX = 0;
> + int runningCp = 0;
> + int width;
> +
> + TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
> +
> + if(!ssa || !piCh || !piTrailing)
> + {
> + return 1;
> + }
> +
> + /* out of range */
> + if(iX < 0)
> + {
> + *piCh = -1;
> + *piTrailing = TRUE;
> return S_OK;
> + }
> +
> + for(i=0; i<analysis->numItems; i++)
> + {
> + for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
> + {
> + width = analysis->glyphs[i].piAdvance[j];
> + if(iX < (runningX + width))
> + {
> + *piCh = runningCp;
> + if((iX - runningX) > width/2)
> + *piTrailing = TRUE;
> + else
> + *piTrailing = FALSE;
> + return S_OK;
> + }
> + runningX += width;
> + runningCp++;
> + }
> + }
> +
> + /* out of range */
> + *piCh = analysis->pItem[analysis->numItems].iCharPos;
> + *piTrailing = FALSE;
> +
> + return S_OK;
> }
>
> /***********************************************************************
> * ScriptStringFree (USP10.@)
> *
> */
> -HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa) {
> - FIXME("(%p): stub\n",pssa);
> - return S_OK;
> +HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
> +{
> + StringAnalysis* analysis;
> + BOOL invalid;
> + TRACE("(%p)\n",pssa);
> +
> + if(!pssa)
> + return E_INVALIDARG;
> +
> + analysis = *pssa;
> + if(!analysis)
> + return E_INVALIDARG;
> +
> + invalid = analysis->invalid;
> +
> + ME_StringAnalysisFree(analysis);
> +
> + if(invalid)
> + return E_INVALIDARG;
> +
> + return S_OK;
> }
>
> /***********************************************************************
> Index: dlls/usp10/tests/usp10.c
> ===================================================================
> RCS file: /home/wine/wine/dlls/usp10/tests/usp10.c,v
> retrieving revision 1.30
> diff -u -r1.30 usp10.c
> --- dlls/usp10/tests/usp10.c 12 Dec 2006 20:30:48 -0000 1.30
> +++ dlls/usp10/tests/usp10.c 13 Dec 2006 03:28:30 -0000
> @@ -701,21 +701,21 @@
> hr = ScriptStringAnalyse( hdc, teststr, String, Glyphs, Charset, Flags,
> ReqWidth, &Control, &State, Dx, &Tabdef,
> &InClass, &ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
>
> /* test makes sure that a call with a valid pssa still works */
> hr = ScriptStringAnalyse( hdc, teststr, String, Glyphs, Charset, Flags,
> ReqWidth, &Control, &State, Dx, &Tabdef,
> &InClass, &ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> - todo_wine ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
> + ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> + ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
>
> if (hr == 0)
> {
> hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
> todo_wine ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
> hr = ScriptStringFree(&ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
> }
> }
>
> @@ -774,8 +774,8 @@
> hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
> ReqWidth, &Control, &State, NULL, &Tabdef,
> &InClass, &ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> - todo_wine ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
> + ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> + ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
> if (hr == 0)
> {
> /*
> @@ -792,25 +792,25 @@
> */
> fTrailing = FALSE;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
> - todo_wine ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> - todo_wine ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
> - todo_wine ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> + ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> + ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
> + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> iTrailing, X);
> fTrailing = TRUE;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
> - todo_wine ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
>
> /*
> * Check that character position returned by ScriptStringXtoCP in Ch matches the
> * one input to ScriptStringCPtoX. This means that the Cp to X position and back
> * again works
> */
> - todo_wine ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
> - todo_wine ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> + ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
> + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> iTrailing, X);
> }
>
> @@ -821,12 +821,12 @@
> fTrailing = TRUE;
> Cp = 3;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> X--; /* put X just inside the trailing edge */
> hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
> - todo_wine ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> - todo_wine ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
> - todo_wine ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
> + ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> + ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
> + ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
> iTrailing, X);
>
> /*
> @@ -837,12 +837,12 @@
> fTrailing = TRUE;
> Cp = 3;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> X++; /* put X just outside the trailing edge */
> hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
> - todo_wine ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> - todo_wine ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
> - todo_wine ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> + ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> + ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
> + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
> iTrailing, X);
>
> /*
> @@ -853,19 +853,19 @@
> fTrailing = FALSE;
> Cp = 3;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
> X--; /* put X just outside the leading edge */
> hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
> - todo_wine ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> - todo_wine ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
> - todo_wine ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
> + ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
> + ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
> + ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
> iTrailing, X);
>
> /*
> * Cleanup the the SSA for the next round of tests
> */
> hr = ScriptStringFree(&ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
>
> /*
> * Test to see that exceeding the number of chars returns E_INVALIDARG. First
> @@ -874,7 +874,7 @@
> hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
> ReqWidth, &Control, &State, NULL, &Tabdef,
> &InClass, &ssa);
> - todo_wine ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
> + ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
>
> /*
> * When ScriptStringCPtoX is called with a character position Cp that exceeds the
> @@ -884,13 +884,13 @@
> fTrailing = FALSE;
> Cp = String_len + 1;
> hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
> - todo_wine ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
> + ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
>
> hr = ScriptStringFree(&ssa);
> /*
> * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
> */
> - todo_wine ok(hr == E_INVALIDARG, "ScriptStringFree should return E_INVALIDARG not %08x\n", hr);
> + ok(hr == E_INVALIDARG, "ScriptStringFree should return E_INVALIDARG not %08x\n", hr);
> }
> }
>
>
>
> ------------------------------------------------------------------------
>
>
3
2
Hello!
I have a program that needs IoCompletion port to run. The program
crashes at startup because WINE head has only stubs for the functions. I
found a patch created by Robert Shearman which adds IoCompletion to
WINE. The patch is very old (2004?) and doesn't apply against the
current development version of wine.
I merged the patch manually into the source tree but my knowdledge of
WINE is limited (zero *g*). My patched source tree doesn't compile:
make[2]: Betrete Verzeichnis '/home/heimes/dev/misc/wine-io/dlls/winecrt0'
gcc -c -I. -I. -I../../include -I../../include -D__WINESRC__
-D_REENTRANT -fPIC -Wall -pipe -fno-strict-aliasing
-Wdeclaration-after-statement -Wwrite-strings -Wpointer-arith
-fno-stack-protector -o drv_entry.o drv_entry.c
In file included from drv_entry.c:23:
../../include/winternl.h:2377: error: expected declaration specifiers or
‘...’ before ‘LPOVERLAPPED’
../../include/winternl.h:2378: error: expected declaration specifiers or
‘...’ before ‘LPOVERLAPPED’
make[2]: *** [drv_entry.o] Fehler 1
I'm attaching my patch to this posting in the hope somebody with more
wisdom stands up. The patch has two ports (iofiles and new_iocompletion)
because git diff didn't include the new files although I did a git add.
bug report: http://bugs.winehq.org/show_bug.cgi?id=6155
iocompletion: original patch by Robert Shearman
iofiles + new_iocompletion: patches against GIT head
Thank you very much!
Christian
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/iocompletion.c wine/dlls/kernel/iocompletion.c
--- wine.orig/dlls/kernel/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/kernel/iocompletion.c 2005-05-04 14:08:38.000000000 -0400
@@ -0,0 +1,173 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "ntstatus.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iocompletion);
+
+HANDLE WINAPI CreateIoCompletionPort(
+ HANDLE FileHandle,
+ HANDLE ExistingCompletionPort,
+ ULONG_PTR CompletionKey,
+ DWORD NumberOfConcurrentThreads)
+{
+ HANDLE CompletionPort;
+ NTSTATUS Status;
+
+ TRACE("(%p, %p, %lx, %ld)\n",
+ FileHandle,
+ ExistingCompletionPort,
+ CompletionKey,
+ NumberOfConcurrentThreads);
+
+ if (((FileHandle == INVALID_HANDLE_VALUE) && (ExistingCompletionPort != NULL)) ||
+ (ExistingCompletionPort == INVALID_HANDLE_VALUE))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (ExistingCompletionPort == NULL)
+ {
+ Status = NtCreateIoCompletion(
+ &CompletionPort,
+ GENERIC_ALL, 0,
+ NumberOfConcurrentThreads);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ CompletionPort = ExistingCompletionPort;
+
+ if (FileHandle != INVALID_HANDLE_VALUE)
+ {
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_COMPLETION_INFORMATION CompletionInfo;
+ CompletionInfo.CompletionKey = CompletionKey;
+ CompletionInfo.CompletionPort = CompletionPort;
+
+ Status = NtSetInformationFile(
+ FileHandle,
+ &IoStatusBlock,
+ (PVOID)&CompletionInfo,
+ sizeof(FILE_COMPLETION_INFORMATION),
+ FileCompletionInformation);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return CompletionPort;
+}
+
+BOOL WINAPI GetQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ LPDWORD lpNumberOfBytesTransferred,
+ PULONG_PTR lpCompletionKey,
+ LPOVERLAPPED * lplpOverlapped,
+ DWORD dwMilliseconds)
+{
+ IO_STATUS_BLOCK CompletionBlock;
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %p, %p, %p, %ld)\n",
+ CompletionPort,
+ lpNumberOfBytesTransferred,
+ lpCompletionKey,
+ lplpOverlapped,
+ dwMilliseconds);
+
+ if (dwMilliseconds == INFINITE)
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ NULL);
+ else
+ {
+ LARGE_INTEGER WaitTime;
+ /* multiplying two LONGLONGs with at least one LONGLONG having its
+ * higher long part not zero makes the multiplying a bit harder,
+ * therefore we do an easy multiply and negate afterwards rather than
+ * making it a hard multiply by doing "* -10000"
+ */
+ WaitTime.QuadPart = (LONGLONG)dwMilliseconds * (LONGLONG)10000;
+ WaitTime.QuadPart = -WaitTime.QuadPart;
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ &WaitTime);
+ }
+ if (Status == STATUS_SUCCESS)
+ {
+ *lpNumberOfBytesTransferred = CompletionBlock.Information;
+ return TRUE;
+ }
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
+
+BOOL WINAPI PostQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ DWORD dwNumberOfBytesTransferred,
+ ULONG_PTR dwCompletionKey,
+ LPOVERLAPPED lpOverlapped)
+{
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %ld, %lx, %p)\n",
+ CompletionPort,
+ dwNumberOfBytesTransferred,
+ dwCompletionKey,
+ lpOverlapped);
+
+ Status = NtSetIoCompletion(
+ CompletionPort,
+ dwCompletionKey,
+ lpOverlapped, 0,
+ dwNumberOfBytesTransferred);
+
+ if (Status == STATUS_SUCCESS)
+ return TRUE;
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/kernel32.spec wine/dlls/kernel/kernel32.spec
--- wine.orig/dlls/kernel/kernel32.spec 2005-04-27 07:08:47.000000000 -0400
+++ wine/dlls/kernel/kernel32.spec 2005-05-04 13:58:00.000000000 -0400
@@ -657,7 +657,7 @@
@ stdcall PeekConsoleInputA(ptr ptr long ptr)
@ stdcall PeekConsoleInputW(ptr ptr long ptr)
@ stdcall PeekNamedPipe(long ptr long ptr ptr ptr)
-@ stub PostQueuedCompletionStatus
+@ stdcall PostQueuedCompletionStatus(ptr long long ptr)
@ stdcall PrepareTape(ptr long long)
@ stub PrivMoveFileIdentityW
@ stdcall Process32First (ptr ptr)
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/Makefile.in wine/dlls/kernel/Makefile.in
--- wine.orig/dlls/kernel/Makefile.in 2005-04-20 11:43:36.000000000 -0400
+++ wine/dlls/kernel/Makefile.in 2005-05-04 14:19:47.000000000 -0400
@@ -33,6 +33,7 @@
file.c \
file16.c \
format_msg.c \
+ iocompletion.c \
global16.c \
heap.c \
instr.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/sync.c wine/dlls/kernel/sync.c
--- wine.orig/dlls/kernel/sync.c 2005-04-24 13:36:34.000000000 -0400
+++ wine/dlls/kernel/sync.c 2005-05-04 19:33:16.000000000 -0400
@@ -1743,31 +1743,6 @@
/******************************************************************************
- * CreateIoCompletionPort (KERNEL32.@)
- */
-HANDLE WINAPI CreateIoCompletionPort(HANDLE hFileHandle, HANDLE hExistingCompletionPort,
- ULONG_PTR CompletionKey, DWORD dwNumberOfConcurrentThreads)
-{
- FIXME("(%p, %p, %08lx, %08lx): stub.\n",
- hFileHandle, hExistingCompletionPort, CompletionKey, dwNumberOfConcurrentThreads);
- return NULL;
-}
-
-
-/******************************************************************************
- * GetQueuedCompletionStatus (KERNEL32.@)
- */
-BOOL WINAPI GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
- PULONG_PTR pCompletionKey, LPOVERLAPPED *lpOverlapped,
- DWORD dwMilliseconds )
-{
- FIXME("(%p,%p,%p,%p,%ld), stub!\n",
- CompletionPort,lpNumberOfBytesTransferred,pCompletionKey,lpOverlapped,dwMilliseconds);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/******************************************************************************
* CreateJobObjectW (KERNEL32.@)
*/
HANDLE WINAPI CreateJobObjectW( LPSECURITY_ATTRIBUTES attr, LPCWSTR name )
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/iocompletion.c wine/dlls/ntdll/iocompletion.c
--- wine.orig/dlls/ntdll/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/ntdll/iocompletion.c 2005-05-04 20:05:27.000000000 -0400
@@ -0,0 +1,216 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+
+#include "ntdll_misc.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+
+extern int NTDLL_wait_reply( void *cookie );
+
+/**************************************************************************
+ * NtCreateIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [O]: the handle created
+ * DesiredAccess [I}: the access desired (e.g. GENERIC_ALL)
+ * Reserved [I}: unknown
+ * NumberOfConcurrentThreads [I]: the desired number of concurrent
+ * threads
+ * Returns:
+ * Status
+ * Notes:
+ * It is effectively a FIFO queue for data and
+ * a LIFO queue for threads to "minimize context switches".
+ * The aim is to keep a small number of threads constantly
+ * active.
+ * See:
+ * MSDN for CreateIoCompletionPort spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtCreateIoCompletion (
+ OUT PHANDLE CompletionPort,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG_PTR Reserved,
+ IN ULONG NumberOfConcurrentThreads
+ )
+ {
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %lx, %ld)\n",
+ CompletionPort,
+ DesiredAccess,
+ Reserved,
+ NumberOfConcurrentThreads);
+
+ if (Reserved != 0)
+ {
+ FIXME("Reserved != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (DesiredAccess && GENERIC_ALL)
+ DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
+
+ SERVER_START_REQ( create_io_completion )
+ {
+ req->access = DesiredAccess;
+ req->concurrent_threads = NumberOfConcurrentThreads;
+ ret = wine_server_call( req );
+ *CompletionPort = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtSetIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [I]: port to send data to
+ * CompletionKey [I}: user key to identify this set of data
+ * lpOverlapped [I}: OVERLAPPED structure to send to port
+ * NumberOfBytesTransferred [I}: unknown - seems to be set to zero always
+ * NumberOfBytesToTransfer [I]: Bytes to transfer in this packet of data
+ * Returns:
+ * Status
+ * See:
+ * MSDN for PostQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtSetIoCompletion(
+ IN HANDLE CompletionPort,
+ IN ULONG_PTR CompletionKey,
+ IN LPOVERLAPPED lpOverlapped,
+ IN ULONG NumberOfBytesTransferred, /* normally set to 0 */
+ IN ULONG NumberOfBytesToTransfer /* will become number of bytes transferred in the io operation */
+ )
+{
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %p, %ld, %ld)\n",
+ CompletionPort,
+ CompletionKey,
+ lpOverlapped,
+ NumberOfBytesTransferred,
+ NumberOfBytesToTransfer);
+
+ if (NumberOfBytesTransferred != 0)
+ {
+ FIXME("NumberOfBytesTransferred != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SERVER_START_REQ( set_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->completion_key = (void *)CompletionKey;
+ req->overlapped = lpOverlapped;
+ req->bytes_transferred = NumberOfBytesToTransfer;
+ ret = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtRemoveIoCompletion (NTDLL.@)
+ *
+ * See: MSDN for GetQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtRemoveIoCompletion (
+ IN HANDLE CompletionPort,
+ OUT PULONG_PTR CompletionKey,
+ OUT LPOVERLAPPED * lplpOverlapped,
+ OUT PIO_STATUS_BLOCK CompletionStatus,
+ IN PLARGE_INTEGER WaitTime
+ )
+{
+ NTSTATUS ret;
+ int cookie;
+
+ TRACE("(%p, %p, %p, %p, %p)\n",
+ CompletionPort,
+ CompletionKey,
+ lplpOverlapped,
+ CompletionStatus,
+ WaitTime);
+
+ for (;;)
+ {
+ SERVER_START_REQ( remove_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->cookie = &cookie;
+ NTDLL_get_server_timeout( &req->timeout, WaitTime );
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ if (ret == STATUS_PENDING)
+ ret = NTDLL_wait_reply( &cookie );
+ if (ret == STATUS_ABANDONED)
+ {
+ SERVER_START_REQ( remove_io_completion_assigned )
+ {
+ req->handle = CompletionPort;
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ }
+ break;
+ }
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/Makefile.in wine/dlls/ntdll/Makefile.in
--- wine.orig/dlls/ntdll/Makefile.in 2004-12-07 09:47:13.000000000 -0500
+++ wine/dlls/ntdll/Makefile.in 2005-05-04 14:25:17.000000000 -0400
@@ -18,6 +18,7 @@
file.c \
handletable.c \
heap.c \
+ iocompletion.c \
large_int.c \
loader.c \
loadorder.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/ntdll.spec wine/dlls/ntdll/ntdll.spec
--- wine.orig/dlls/ntdll/ntdll.spec 2005-04-22 17:17:16.000000000 -0400
+++ wine/dlls/ntdll/ntdll.spec 2005-05-04 14:24:47.000000000 -0400
@@ -86,7 +86,7 @@
@ stdcall NtCreateEvent(long long long long long)
@ stub NtCreateEventPair
@ stdcall NtCreateFile(ptr long ptr ptr long long long ptr long long ptr)
-@ stub NtCreateIoCompletion
+@ stdcall NtCreateIoCompletion(ptr long long long)
@ stdcall NtCreateKey(ptr long ptr long ptr long long)
@ stdcall NtCreateMailslotFile(long long long long long long long long)
@ stdcall NtCreateMutant(ptr long ptr long)
@@ -205,7 +205,7 @@
@ stdcall NtReleaseMutant(long ptr)
@ stub NtReleaseProcessMutant
@ stdcall NtReleaseSemaphore(long long ptr)
-@ stub NtRemoveIoCompletion
+@ stdcall NtRemoveIoCompletion(ptr ptr ptr ptr ptr)
@ stdcall NtReplaceKey(ptr long ptr)
@ stub NtReplyPort
@ stdcall NtReplyWaitReceivePort(ptr ptr ptr ptr)
@@ -234,7 +234,7 @@
@ stdcall NtSetInformationThread(long long ptr long)
@ stdcall NtSetInformationToken(long long ptr long)
@ stdcall NtSetIntervalProfile(long long)
-@ stub NtSetIoCompletion
+@ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stub NtSetLdtEntries
@ stub NtSetLowEventPair
@ stub NtSetLowWaitHighEventPair
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/sync.c wine/dlls/ntdll/sync.c
--- wine.orig/dlls/ntdll/sync.c 2005-04-24 13:35:53.000000000 -0400
+++ wine/dlls/ntdll/sync.c 2005-05-04 14:27:33.000000000 -0400
@@ -611,7 +611,7 @@
*
* Wait for a reply on the waiting pipe of the current thread.
*/
-static int wait_reply( void *cookie )
+int NTDLL_wait_reply( void *cookie )
{
int signaled;
struct wake_up_reply reply;
@@ -624,7 +624,7 @@
if (!reply.cookie) break; /* thread got killed */
if (reply.cookie == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */
- signaled = wait_reply( cookie );
+ signaled = NTDLL_wait_reply( cookie );
/* and now put the wrong one back in the pipe */
for (;;)
{
@@ -719,7 +719,7 @@
ret = wine_server_call( req );
}
SERVER_END_REQ;
- if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
+ if (ret == STATUS_PENDING) ret = NTDLL_wait_reply( &cookie );
if (ret != STATUS_USER_APC) break;
call_apcs( (flags & SELECT_ALERTABLE) != 0 );
if (flags & SELECT_ALERTABLE) break;
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/include/winbase.h wine/include/winbase.h
--- wine.orig/include/winbase.h 2005-04-25 12:23:32.000000000 -0400
+++ wine/include/winbase.h 2005-05-04 13:58:00.000000000 -0400
@@ -1602,6 +1602,7 @@
HANDLE WINAPI OpenWaitableTimerW(DWORD,BOOL,LPCWSTR);
#define OpenWaitableTimer WINELIB_NAME_AW(OpenWaitableTimer)
BOOL WINAPI PeekNamedPipe(HANDLE,PVOID,DWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI PostQueuedCompletionStatus(HANDLE,DWORD,ULONG_PTR,LPOVERLAPPED);
DWORD WINAPI PrepareTape(HANDLE,DWORD,BOOL);
BOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR,LPCSTR,HANDLE,PPRIVILEGE_SET,BOOL);
BOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR,LPCWSTR,HANDLE,PPRIVILEGE_SET,BOOL);
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/include/winternl.h wine/include/winternl.h
--- wine.orig/include/winternl.h 2005-04-27 04:14:18.000000000 -0400
+++ wine/include/winternl.h 2005-05-04 19:24:46.000000000 -0400
@@ -1467,7 +1467,6 @@
NTSTATUS WINAPI NtClose(HANDLE);
NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN);
NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
-NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,ULONG);
NTSTATUS WINAPI NtCreateKey(PHKEY,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG,ULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtCreateMutant(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,BOOLEAN);
@@ -1543,7 +1542,6 @@
NTSTATUS WINAPI NtReadVirtualMemory(HANDLE,const void*,void*,SIZE_T,SIZE_T*);
NTSTATUS WINAPI NtReleaseMutant(HANDLE,PLONG);
NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
-NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG,PULONG,PIO_STATUS_BLOCK,PLARGE_INTEGER);
NTSTATUS WINAPI NtReplaceKey(POBJECT_ATTRIBUTES,HKEY,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtResetEvent(HANDLE,PULONG);
NTSTATUS WINAPI NtRestoreKey(HKEY,HANDLE,ULONG);
@@ -1554,12 +1552,10 @@
NTSTATUS WINAPI NtSetDefaultUILanguage(LANGID);
NTSTATUS WINAPI NtSetEaFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG);
NTSTATUS WINAPI NtSetEvent(HANDLE,PULONG);
-NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
NTSTATUS WINAPI NtSetInformationKey(HKEY,const int,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG);
NTSTATUS WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,ULONG);
-NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG,ULONG,NTSTATUS,ULONG);
NTSTATUS WINAPI NtSetSecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
NTSTATUS WINAPI NtSetSystemTime(const LARGE_INTEGER*,LARGE_INTEGER*);
NTSTATUS WINAPI NtSetTimer(HANDLE, const LARGE_INTEGER*, PTIMERAPCROUTINE, PVOID, BOOLEAN, ULONG, BOOLEAN*);
@@ -1968,6 +1964,23 @@
NTSTATUS WINAPI LdrUnloadDll(HMODULE);
NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG);
+/*************************************************************************
+ * I/O completion functions and structures.
+ *
+ * These are not part of standard Winternl.h
+ */
+typedef struct _FILE_COMPLETION_INFORMATION {
+ HANDLE CompletionPort;
+ ULONG_PTR CompletionKey;
+} FILE_COMPLETION_INFORMATION;
+typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION;
+
+NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,ULONG_PTR,ULONG);
+NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,LPOVERLAPPED,ULONG,ULONG);
+NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,LPOVERLAPPED*,PIO_STATUS_BLOCK,PLARGE_INTEGER);
+NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
+
+
/* list manipulation macros */
#define InitializeListHead(le) (void)((le)->Flink = (le)->Blink = (le))
#define InsertHeadList(le,e) do { PLIST_ENTRY f = (le)->Flink; (e)->Flink = f; (e)->Blink = (le); f->Blink = (e); (le)->Flink = (e); } while (0)
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/iocompletion.c wine/server/iocompletion.c
--- wine.orig/server/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/server/iocompletion.c 2005-05-04 14:13:16.000000000 -0400
@@ -0,0 +1,282 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdio.h>
+
+#include "windef.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "wine/list.h"
+
+static void io_completion_dump( struct object *obj, int verbose );
+static void io_completion_destroy( struct object *obj );
+static int io_completion_signaled( struct object * obj, struct thread * thread );
+static int io_completion_satisfied( struct object * obj, struct thread * thread );
+
+extern void select_on( int count, void *cookie, const obj_handle_t *handles,
+ int flags, const abs_time_t *timeout );
+
+struct io_completion_data
+{
+ struct list entry;
+ unsigned int bytes_transferred;
+ void * completion_key;
+ void * overlapped;
+};
+
+struct io_completion_assigned_data
+{
+ struct list entry;
+ struct thread * thread;
+ struct io_completion_data * data;
+};
+
+struct io_completion_port
+{
+ struct object obj;
+ unsigned int concurrent_threads;
+ unsigned int max_concurrent_threads; /* FIXME: should we honour this? */
+ struct list data; /* fifo queue for io_completion_data */
+
+ struct list assigned_data; /* io_completion_assigned_data */
+
+ /* Used to determine whether we have initiated the select()
+ * through GetQueuedCompletionStatus or whether the client
+ * has done WaitForSingleObject */
+ int satisfied;
+};
+
+static const struct object_ops io_completion_ops =
+{
+ sizeof(struct io_completion_port), /* size */
+ io_completion_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ io_completion_signaled, /* signaled */
+ io_completion_satisfied, /* satisfied */
+ no_get_fd, /* get_fd */
+ io_completion_destroy /* destroy */
+};
+
+static void io_completion_dump( struct object *obj, int verbose )
+{
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ fprintf( stderr, "I/O completion port max_threads=%d\n",
+ port->max_concurrent_threads);
+}
+
+static void io_completion_destroy( struct object *obj )
+{
+ struct list * current;
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+
+ /* free data queue */
+ for (current = list_head(&port->data);
+ !list_empty(&port->data); current = list_head(&port->data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_data, entry) );
+ }
+
+ /* free assigned data queue */
+ for (current = list_head(&port->assigned_data);
+ !list_empty(&port->assigned_data); current = list_head(&port->assigned_data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry)->data );
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry) );
+ }
+}
+
+static int io_completion_signaled( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return !list_empty(&port->data);
+}
+
+static int io_completion_satisfied( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return port->satisfied;
+}
+
+static struct object * create_io_completion(unsigned int concurrent_threads)
+{
+ struct io_completion_port * port;
+ if (!(port = alloc_object( &io_completion_ops )))
+ {
+ return NULL;
+ }
+
+ list_init(&port->data);
+ list_init(&port->assigned_data);
+ port->concurrent_threads = 0;
+ port->max_concurrent_threads = concurrent_threads;
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+
+ return &port->obj;
+}
+
+static void assign_data(struct io_completion_port * port, struct thread * thread)
+{
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ struct io_completion_assigned_data * assigned_data;
+ if ((assigned_data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&assigned_data->entry);
+ assigned_data->data = data;
+ assigned_data->thread = thread;
+
+ list_add_head( &port->assigned_data, &assigned_data->entry );
+
+ list_remove( &data->entry );
+ }
+}
+
+DECL_HANDLER(create_io_completion)
+{
+ struct object * obj;
+
+ reply->handle = 0;
+ if ((obj = create_io_completion(req->concurrent_threads)) != NULL)
+ {
+ reply->handle = alloc_handle(current->process, obj, req->access | SYNCHRONIZE, FALSE /*inherit flag*/);
+ release_object( obj );
+ }
+}
+
+DECL_HANDLER(remove_io_completion)
+{
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_READ,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ if (!list_empty(&port->data)) /* there is waiting data */
+ {
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ reply->bytes_transferred = data->bytes_transferred;
+ reply->completion_key = data->completion_key;
+ reply->overlapped = data->overlapped;
+ /* remove the data from the completion port */
+ list_remove( &data->entry );
+ free( data );
+ }
+ else /* there is no waiting data */
+ {
+ port->satisfied = 0; /* don't abandon wait on the port */
+ select_on(1, req->cookie, &req->handle, SELECT_TIMEOUT, &req->timeout);
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(set_io_completion)
+{
+ struct io_completion_data * data;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ return;
+
+ if ((data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&data->entry);
+ data->bytes_transferred = req->bytes_transferred;
+ data->completion_key = req->completion_key;
+ data->overlapped = req->overlapped;
+
+ list_add_tail(&port->data, &data->entry);
+
+ if (port->obj.tail != NULL) /* there is a waiting thread */
+ {
+ struct wait_queue_entry * waiting = port->obj.tail;
+ assign_data( port, waiting->thread );
+ wake_thread( waiting->thread );
+ }
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(remove_io_completion_assigned)
+{
+ struct io_completion_assigned_data * assigned_data;
+ struct list * cursor;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ LIST_FOR_EACH(cursor, &port->assigned_data)
+ {
+ assigned_data = LIST_ENTRY(cursor, struct io_completion_assigned_data, entry);
+ if (assigned_data->thread == current)
+ {
+ reply->bytes_transferred = assigned_data->data->bytes_transferred;
+ reply->completion_key = assigned_data->data->completion_key;
+ reply->overlapped = assigned_data->data->overlapped;
+ list_remove( &assigned_data->entry );
+ free( assigned_data->data );
+ free( assigned_data );
+ return;
+ }
+ }
+
+ set_error(STATUS_INVALID_PARAMETER);
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/Makefile.in wine/server/Makefile.in
--- wine.orig/server/Makefile.in 2005-03-30 14:02:15.000000000 -0500
+++ wine/server/Makefile.in 2005-05-04 14:38:33.000000000 -0400
@@ -21,6 +21,7 @@
file.c \
handle.c \
hook.c \
+ iocompletion.c \
mailslot.c \
main.c \
mapping.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/request.h wine/server/request.h
--- wine.orig/server/request.h 2005-04-28 08:04:14.000000000 -0400
+++ wine/server/request.h 2005-05-04 14:40:31.000000000 -0400
@@ -280,6 +280,10 @@
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_next_hook);
+DECL_HANDLER(create_io_completion);
+DECL_HANDLER(set_io_completion);
+DECL_HANDLER(remove_io_completion);
+DECL_HANDLER(remove_io_completion_assigned);
DECL_HANDLER(create_class);
DECL_HANDLER(destroy_class);
DECL_HANDLER(set_class_info);
@@ -476,6 +480,10 @@
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_next_hook,
+ (req_handler)req_create_io_completion,
+ (req_handler)req_set_io_completion,
+ (req_handler)req_remove_io_completion,
+ (req_handler)req_remove_io_completion_assigned,
(req_handler)req_create_class,
(req_handler)req_destroy_class,
(req_handler)req_set_class_info,
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/thread.c wine/server/thread.c
--- wine.orig/server/thread.c 2005-04-24 13:35:52.000000000 -0400
+++ wine/server/thread.c 2005-05-04 14:41:21.000000000 -0400
@@ -533,7 +533,7 @@
}
/* select on a list of handles */
-static void select_on( int count, void *cookie, const obj_handle_t *handles,
+void select_on( int count, void *cookie, const obj_handle_t *handles,
int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
{
int ret, i;
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/trace.c wine/server/trace.c
--- wine.orig/server/trace.c 2005-04-28 08:04:14.000000000 -0400
+++ wine/server/trace.c 2005-05-04 14:32:57.000000000 -0400
@@ -2602,6 +2602,33 @@
fprintf( stderr, " client_ptr=%p", req->client_ptr );
}
+static void dump_remove_io_completion_request( const struct remove_io_completion_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " cookie=%p,", req->cookie );
+ fprintf( stderr, " timeout=" );
+ dump_abs_time( &req->timeout );
+}
+
+static void dump_remove_io_completion_reply( const struct remove_io_completion_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
+static void dump_remove_io_completion_assigned_request( const struct remove_io_completion_assigned_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_remove_io_completion_assigned_reply( const struct remove_io_completion_assigned_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
static void dump_set_class_info_request( const struct set_class_info_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@@ -2949,6 +2976,10 @@
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_next_hook_request,
+ (dump_func)dump_create_io_completion_request,
+ (dump_func)dump_set_io_completion_request,
+ (dump_func)dump_remove_io_completion_request,
+ (dump_func)dump_remove_io_completion_assigned_request,
(dump_func)dump_create_class_request,
(dump_func)dump_destroy_class_request,
(dump_func)dump_set_class_info_request,
@@ -3142,6 +3173,10 @@
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_next_hook_reply,
+ (dump_func)dump_create_io_completion_reply,
+ (dump_func)0,
+ (dump_func)dump_remove_io_completion_reply,
+ (dump_func)dump_remove_io_completion_assigned_reply,
(dump_func)0,
(dump_func)dump_destroy_class_reply,
(dump_func)dump_set_class_info_reply,
@@ -3335,6 +3370,10 @@
"start_hook_chain",
"finish_hook_chain",
"get_next_hook",
+ "create_io_completion",
+ "set_io_completion",
+ "remove_io_completion",
+ "remove_io_completion_assigned",
"create_class",
"destroy_class",
"set_class_info",
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel32/iocompletion.c wine/dlls/kernel32/iocompletion.c
--- wine.orig/dlls/kernel32/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/kernel32/iocompletion.c 2005-05-04 14:08:38.000000000 -0400
@@ -0,0 +1,173 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "ntstatus.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iocompletion);
+
+HANDLE WINAPI CreateIoCompletionPort(
+ HANDLE FileHandle,
+ HANDLE ExistingCompletionPort,
+ ULONG_PTR CompletionKey,
+ DWORD NumberOfConcurrentThreads)
+{
+ HANDLE CompletionPort;
+ NTSTATUS Status;
+
+ TRACE("(%p, %p, %lx, %ld)\n",
+ FileHandle,
+ ExistingCompletionPort,
+ CompletionKey,
+ NumberOfConcurrentThreads);
+
+ if (((FileHandle == INVALID_HANDLE_VALUE) && (ExistingCompletionPort != NULL)) ||
+ (ExistingCompletionPort == INVALID_HANDLE_VALUE))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (ExistingCompletionPort == NULL)
+ {
+ Status = NtCreateIoCompletion(
+ &CompletionPort,
+ GENERIC_ALL, 0,
+ NumberOfConcurrentThreads);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ CompletionPort = ExistingCompletionPort;
+
+ if (FileHandle != INVALID_HANDLE_VALUE)
+ {
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_COMPLETION_INFORMATION CompletionInfo;
+ CompletionInfo.CompletionKey = CompletionKey;
+ CompletionInfo.CompletionPort = CompletionPort;
+
+ Status = NtSetInformationFile(
+ FileHandle,
+ &IoStatusBlock,
+ (PVOID)&CompletionInfo,
+ sizeof(FILE_COMPLETION_INFORMATION),
+ FileCompletionInformation);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return CompletionPort;
+}
+
+BOOL WINAPI GetQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ LPDWORD lpNumberOfBytesTransferred,
+ PULONG_PTR lpCompletionKey,
+ LPOVERLAPPED * lplpOverlapped,
+ DWORD dwMilliseconds)
+{
+ IO_STATUS_BLOCK CompletionBlock;
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %p, %p, %p, %ld)\n",
+ CompletionPort,
+ lpNumberOfBytesTransferred,
+ lpCompletionKey,
+ lplpOverlapped,
+ dwMilliseconds);
+
+ if (dwMilliseconds == INFINITE)
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ NULL);
+ else
+ {
+ LARGE_INTEGER WaitTime;
+ /* multiplying two LONGLONGs with at least one LONGLONG having its
+ * higher long part not zero makes the multiplying a bit harder,
+ * therefore we do an easy multiply and negate afterwards rather than
+ * making it a hard multiply by doing "* -10000"
+ */
+ WaitTime.QuadPart = (LONGLONG)dwMilliseconds * (LONGLONG)10000;
+ WaitTime.QuadPart = -WaitTime.QuadPart;
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ &WaitTime);
+ }
+ if (Status == STATUS_SUCCESS)
+ {
+ *lpNumberOfBytesTransferred = CompletionBlock.Information;
+ return TRUE;
+ }
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
+
+BOOL WINAPI PostQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ DWORD dwNumberOfBytesTransferred,
+ ULONG_PTR dwCompletionKey,
+ LPOVERLAPPED lpOverlapped)
+{
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %ld, %lx, %p)\n",
+ CompletionPort,
+ dwNumberOfBytesTransferred,
+ dwCompletionKey,
+ lpOverlapped);
+
+ Status = NtSetIoCompletion(
+ CompletionPort,
+ dwCompletionKey,
+ lpOverlapped, 0,
+ dwNumberOfBytesTransferred);
+
+ if (Status == STATUS_SUCCESS)
+ return TRUE;
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/iocompletion.c wine/dlls/ntdll/iocompletion.c
--- wine.orig/dlls/ntdll/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/ntdll/iocompletion.c 2005-05-04 20:05:27.000000000 -0400
@@ -0,0 +1,216 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+
+#include "ntdll_misc.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+
+extern int NTDLL_wait_reply( void *cookie );
+
+/**************************************************************************
+ * NtCreateIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [O]: the handle created
+ * DesiredAccess [I}: the access desired (e.g. GENERIC_ALL)
+ * Reserved [I}: unknown
+ * NumberOfConcurrentThreads [I]: the desired number of concurrent
+ * threads
+ * Returns:
+ * Status
+ * Notes:
+ * It is effectively a FIFO queue for data and
+ * a LIFO queue for threads to "minimize context switches".
+ * The aim is to keep a small number of threads constantly
+ * active.
+ * See:
+ * MSDN for CreateIoCompletionPort spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtCreateIoCompletion (
+ OUT PHANDLE CompletionPort,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG_PTR Reserved,
+ IN ULONG NumberOfConcurrentThreads
+ )
+ {
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %lx, %ld)\n",
+ CompletionPort,
+ DesiredAccess,
+ Reserved,
+ NumberOfConcurrentThreads);
+
+ if (Reserved != 0)
+ {
+ FIXME("Reserved != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (DesiredAccess && GENERIC_ALL)
+ DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
+
+ SERVER_START_REQ( create_io_completion )
+ {
+ req->access = DesiredAccess;
+ req->concurrent_threads = NumberOfConcurrentThreads;
+ ret = wine_server_call( req );
+ *CompletionPort = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtSetIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [I]: port to send data to
+ * CompletionKey [I}: user key to identify this set of data
+ * lpOverlapped [I}: OVERLAPPED structure to send to port
+ * NumberOfBytesTransferred [I}: unknown - seems to be set to zero always
+ * NumberOfBytesToTransfer [I]: Bytes to transfer in this packet of data
+ * Returns:
+ * Status
+ * See:
+ * MSDN for PostQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtSetIoCompletion(
+ IN HANDLE CompletionPort,
+ IN ULONG_PTR CompletionKey,
+ IN LPOVERLAPPED lpOverlapped,
+ IN ULONG NumberOfBytesTransferred, /* normally set to 0 */
+ IN ULONG NumberOfBytesToTransfer /* will become number of bytes transferred in the io operation */
+ )
+{
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %p, %ld, %ld)\n",
+ CompletionPort,
+ CompletionKey,
+ lpOverlapped,
+ NumberOfBytesTransferred,
+ NumberOfBytesToTransfer);
+
+ if (NumberOfBytesTransferred != 0)
+ {
+ FIXME("NumberOfBytesTransferred != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SERVER_START_REQ( set_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->completion_key = (void *)CompletionKey;
+ req->overlapped = lpOverlapped;
+ req->bytes_transferred = NumberOfBytesToTransfer;
+ ret = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtRemoveIoCompletion (NTDLL.@)
+ *
+ * See: MSDN for GetQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtRemoveIoCompletion (
+ IN HANDLE CompletionPort,
+ OUT PULONG_PTR CompletionKey,
+ OUT LPOVERLAPPED * lplpOverlapped,
+ OUT PIO_STATUS_BLOCK CompletionStatus,
+ IN PLARGE_INTEGER WaitTime
+ )
+{
+ NTSTATUS ret;
+ int cookie;
+
+ TRACE("(%p, %p, %p, %p, %p)\n",
+ CompletionPort,
+ CompletionKey,
+ lplpOverlapped,
+ CompletionStatus,
+ WaitTime);
+
+ for (;;)
+ {
+ SERVER_START_REQ( remove_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->cookie = &cookie;
+ NTDLL_get_server_timeout( &req->timeout, WaitTime );
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ if (ret == STATUS_PENDING)
+ ret = NTDLL_wait_reply( &cookie );
+ if (ret == STATUS_ABANDONED)
+ {
+ SERVER_START_REQ( remove_io_completion_assigned )
+ {
+ req->handle = CompletionPort;
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ }
+ break;
+ }
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/iocompletion.c wine/server/iocompletion.c
--- wine.orig/server/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/server/iocompletion.c 2005-05-04 14:13:16.000000000 -0400
@@ -0,0 +1,282 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdio.h>
+
+#include "windef.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "wine/list.h"
+
+static void io_completion_dump( struct object *obj, int verbose );
+static void io_completion_destroy( struct object *obj );
+static int io_completion_signaled( struct object * obj, struct thread * thread );
+static int io_completion_satisfied( struct object * obj, struct thread * thread );
+
+extern void select_on( int count, void *cookie, const obj_handle_t *handles,
+ int flags, const abs_time_t *timeout );
+
+struct io_completion_data
+{
+ struct list entry;
+ unsigned int bytes_transferred;
+ void * completion_key;
+ void * overlapped;
+};
+
+struct io_completion_assigned_data
+{
+ struct list entry;
+ struct thread * thread;
+ struct io_completion_data * data;
+};
+
+struct io_completion_port
+{
+ struct object obj;
+ unsigned int concurrent_threads;
+ unsigned int max_concurrent_threads; /* FIXME: should we honour this? */
+ struct list data; /* fifo queue for io_completion_data */
+
+ struct list assigned_data; /* io_completion_assigned_data */
+
+ /* Used to determine whether we have initiated the select()
+ * through GetQueuedCompletionStatus or whether the client
+ * has done WaitForSingleObject */
+ int satisfied;
+};
+
+static const struct object_ops io_completion_ops =
+{
+ sizeof(struct io_completion_port), /* size */
+ io_completion_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ io_completion_signaled, /* signaled */
+ io_completion_satisfied, /* satisfied */
+ no_get_fd, /* get_fd */
+ io_completion_destroy /* destroy */
+};
+
+static void io_completion_dump( struct object *obj, int verbose )
+{
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ fprintf( stderr, "I/O completion port max_threads=%d\n",
+ port->max_concurrent_threads);
+}
+
+static void io_completion_destroy( struct object *obj )
+{
+ struct list * current;
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+
+ /* free data queue */
+ for (current = list_head(&port->data);
+ !list_empty(&port->data); current = list_head(&port->data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_data, entry) );
+ }
+
+ /* free assigned data queue */
+ for (current = list_head(&port->assigned_data);
+ !list_empty(&port->assigned_data); current = list_head(&port->assigned_data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry)->data );
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry) );
+ }
+}
+
+static int io_completion_signaled( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return !list_empty(&port->data);
+}
+
+static int io_completion_satisfied( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return port->satisfied;
+}
+
+static struct object * create_io_completion(unsigned int concurrent_threads)
+{
+ struct io_completion_port * port;
+ if (!(port = alloc_object( &io_completion_ops )))
+ {
+ return NULL;
+ }
+
+ list_init(&port->data);
+ list_init(&port->assigned_data);
+ port->concurrent_threads = 0;
+ port->max_concurrent_threads = concurrent_threads;
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+
+ return &port->obj;
+}
+
+static void assign_data(struct io_completion_port * port, struct thread * thread)
+{
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ struct io_completion_assigned_data * assigned_data;
+ if ((assigned_data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&assigned_data->entry);
+ assigned_data->data = data;
+ assigned_data->thread = thread;
+
+ list_add_head( &port->assigned_data, &assigned_data->entry );
+
+ list_remove( &data->entry );
+ }
+}
+
+DECL_HANDLER(create_io_completion)
+{
+ struct object * obj;
+
+ reply->handle = 0;
+ if ((obj = create_io_completion(req->concurrent_threads)) != NULL)
+ {
+ reply->handle = alloc_handle(current->process, obj, req->access | SYNCHRONIZE, FALSE /*inherit flag*/);
+ release_object( obj );
+ }
+}
+
+DECL_HANDLER(remove_io_completion)
+{
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_READ,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ if (!list_empty(&port->data)) /* there is waiting data */
+ {
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ reply->bytes_transferred = data->bytes_transferred;
+ reply->completion_key = data->completion_key;
+ reply->overlapped = data->overlapped;
+ /* remove the data from the completion port */
+ list_remove( &data->entry );
+ free( data );
+ }
+ else /* there is no waiting data */
+ {
+ port->satisfied = 0; /* don't abandon wait on the port */
+ select_on(1, req->cookie, &req->handle, SELECT_TIMEOUT, &req->timeout);
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(set_io_completion)
+{
+ struct io_completion_data * data;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ return;
+
+ if ((data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&data->entry);
+ data->bytes_transferred = req->bytes_transferred;
+ data->completion_key = req->completion_key;
+ data->overlapped = req->overlapped;
+
+ list_add_tail(&port->data, &data->entry);
+
+ if (port->obj.tail != NULL) /* there is a waiting thread */
+ {
+ struct wait_queue_entry * waiting = port->obj.tail;
+ assign_data( port, waiting->thread );
+ wake_thread( waiting->thread );
+ }
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(remove_io_completion_assigned)
+{
+ struct io_completion_assigned_data * assigned_data;
+ struct list * cursor;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ LIST_FOR_EACH(cursor, &port->assigned_data)
+ {
+ assigned_data = LIST_ENTRY(cursor, struct io_completion_assigned_data, entry);
+ if (assigned_data->thread == current)
+ {
+ reply->bytes_transferred = assigned_data->data->bytes_transferred;
+ reply->completion_key = assigned_data->data->completion_key;
+ reply->overlapped = assigned_data->data->overlapped;
+ list_remove( &assigned_data->entry );
+ free( assigned_data->data );
+ free( assigned_data );
+ return;
+ }
+ }
+
+ set_error(STATUS_INVALID_PARAMETER);
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+}
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in
index c725509..be5da9e 100644
--- a/dlls/kernel32/Makefile.in
+++ b/dlls/kernel32/Makefile.in
@@ -35,6 +35,7 @@ C_SRCS = \
file.c \
file16.c \
format_msg.c \
+ iocompletion.c \
global16.c \
heap.c \
instr.c \
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 7502bb8..76ee2dc 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -828,6 +828,7 @@ # @ stub NumaVirtualQueryNode
@ stdcall PeekConsoleInputA(ptr ptr long ptr)
@ stdcall PeekConsoleInputW(ptr ptr long ptr)
@ stdcall PeekNamedPipe(long ptr long ptr ptr ptr)
+# PATCH: @ stdcall PostQueuedCompletionStatus(ptr long long ptr)
@ stdcall PostQueuedCompletionStatus(long long ptr ptr)
@ stdcall PrepareTape(ptr long long)
@ stub PrivCopyFileExW
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index eaa0f70..c517744 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1766,41 +1766,6 @@ BOOL WINAPI SetMailslotInfo( HANDLE hMai
return TRUE;
}
-
-/******************************************************************************
- * CreateIoCompletionPort (KERNEL32.@)
- */
-HANDLE WINAPI CreateIoCompletionPort(HANDLE hFileHandle, HANDLE hExistingCompletionPort,
- ULONG_PTR CompletionKey, DWORD dwNumberOfConcurrentThreads)
-{
- FIXME("(%p, %p, %08lx, %08x): stub.\n",
- hFileHandle, hExistingCompletionPort, CompletionKey, dwNumberOfConcurrentThreads);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return NULL;
-}
-
-
-/******************************************************************************
- * GetQueuedCompletionStatus (KERNEL32.@)
- */
-BOOL WINAPI GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
- PULONG_PTR pCompletionKey, LPOVERLAPPED *lpOverlapped,
- DWORD dwMilliseconds )
-{
- FIXME("(%p,%p,%p,%p,%d), stub!\n",
- CompletionPort,lpNumberOfBytesTransferred,pCompletionKey,lpOverlapped,dwMilliseconds);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-BOOL WINAPI PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytes,
- ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped)
-{
- FIXME("%p %d %08lx %p\n", CompletionPort, dwNumberOfBytes, dwCompletionKey, lpOverlapped );
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
/******************************************************************************
* CreateJobObjectW (KERNEL32.@)
*/
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 37b18f1..7496930 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -21,6 +21,7 @@ C_SRCS = \
file.c \
handletable.c \
heap.c \
+ iocompletion.c \
large_int.c \
loader.c \
loadorder.c \
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 803ed53..baf5ff8 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -124,6 +124,7 @@ # @ stub NtCreateDebugObject
@ stdcall NtCreateEvent(long long long long long)
@ stub NtCreateEventPair
@ stdcall NtCreateFile(ptr long ptr ptr long long long ptr long long ptr)
+# PATCH: @ stdcall NtCreateIoCompletion(ptr long long long)
@ stdcall NtCreateIoCompletion(ptr long ptr long)
# @ stub NtCreateJobObject
# @ stub NtCreateJobSet
@@ -328,6 +329,7 @@ # @ stub NtSetInformationJobObject
@ stdcall NtSetInformationThread(long long ptr long)
@ stdcall NtSetInformationToken(long long ptr long)
@ stdcall NtSetIntervalProfile(long long)
+# PATCH: @ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stub NtSetLdtEntries
@ stub NtSetLowEventPair
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 852bfde..bc0470b 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -618,7 +618,7 @@ NTSTATUS WINAPI NtSetTimerResolution(IN
*
* Wait for a reply on the waiting pipe of the current thread.
*/
-static int wait_reply( void *cookie )
+int NTDLL_wait_reply( void *cookie )
{
int signaled;
struct wake_up_reply reply;
@@ -631,7 +631,7 @@ static int wait_reply( void *cookie )
if (!reply.cookie) break; /* thread got killed */
if (reply.cookie == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */
- signaled = wait_reply( cookie );
+ signaled = NTDLL_wait_reply( cookie );
/* and now put the wrong one back in the pipe */
for (;;)
{
@@ -726,7 +726,7 @@ NTSTATUS NTDLL_wait_for_multiple_objects
ret = wine_server_call( req );
}
SERVER_END_REQ;
- if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
+ if (ret == STATUS_PENDING) ret = NTDLL_wait_reply( &cookie );
if (ret != STATUS_USER_APC) break;
call_apcs( (flags & SELECT_ALERTABLE) != 0 );
if (flags & SELECT_ALERTABLE) break;
diff --git a/include/winternl.h b/include/winternl.h
index 19b2ac9..d27d4f2 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1763,7 +1763,6 @@ NTSTATUS WINAPI NtCreateDirectoryObject
NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN);
NTSTATUS WINAPI NtCreateEventPair(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
-NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,ULONG);
NTSTATUS WINAPI NtCreateKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG,ULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtCreateMutant(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,BOOLEAN);
@@ -1882,7 +1881,6 @@ NTSTATUS WINAPI NtReadVirtualMemory(HAN
NTSTATUS WINAPI NtRegisterThreadTerminatePort(HANDLE);
NTSTATUS WINAPI NtReleaseMutant(HANDLE,PLONG);
NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
-NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,PIO_STATUS_BLOCK,PULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtReplaceKey(POBJECT_ATTRIBUTES,HANDLE,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtReplyPort(HANDLE,PLPC_MESSAGE);
NTSTATUS WINAPI NtReplyWaitReceivePort(HANDLE,PULONG,PLPC_MESSAGE,PLPC_MESSAGE);
@@ -1904,14 +1902,12 @@ NTSTATUS WINAPI NtSetEvent(HANDLE,PULON
NTSTATUS WINAPI NtSetHighEventPair(HANDLE);
NTSTATUS WINAPI NtSetHighWaitLowEventPair(HANDLE);
NTSTATUS WINAPI NtSetHighWaitLowThread(VOID);
-NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
NTSTATUS WINAPI NtSetInformationKey(HANDLE,const int,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG);
NTSTATUS WINAPI NtSetInformationProcess(HANDLE,PROCESS_INFORMATION_CLASS,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,ULONG);
NTSTATUS WINAPI NtSetIntervalProfile(ULONG,KPROFILE_SOURCE);
-NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,PIO_STATUS_BLOCK,ULONG,ULONG);
NTSTATUS WINAPI NtSetLdtEntries(ULONG,LDT_ENTRY,ULONG,LDT_ENTRY);
NTSTATUS WINAPI NtSetLowEventPair(HANDLE);
NTSTATUS WINAPI NtSetLowWaitHighEventPair(HANDLE);
@@ -2367,11 +2363,21 @@ NTSTATUS WINAPI LdrQueryProcessModuleInf
NTSTATUS WINAPI LdrUnloadDll(HMODULE);
NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG);
+/*************************************************************************
+ * I/O completion functions and structures.
+ *
+ * These are not part of standard Winternl.h
+ */
typedef struct _FILE_COMPLETION_INFORMATION {
HANDLE CompletionPort;
ULONG_PTR CompletionKey;
} FILE_COMPLETION_INFORMATION;
typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION;
+NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,ULONG_PTR,ULONG);
+NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,LPOVERLAPPED,ULONG,ULONG);
+NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,LPOVERLAPPED*,PIO_STATUS_BLOCK,PLARGE_INTEGER);
+NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
+
/* list manipulation macros */
#define InitializeListHead(le) (void)((le)->Flink = (le)->Blink = (le))
diff --git a/server/Makefile.in b/server/Makefile.in
index f62bd1d..2c0daa4 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -24,6 +24,7 @@ C_SRCS = \
file.c \
handle.c \
hook.c \
+ iocompletion.c \
mailslot.c \
main.c \
mapping.c \
diff --git a/server/request.h b/server/request.h
index 8cfeccd..c6b6a8b 100644
--- a/server/request.h
+++ b/server/request.h
@@ -302,6 +302,10 @@ DECL_HANDLER(remove_hook);
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_hook_info);
+DECL_HANDLER(create_io_completion);
+DECL_HANDLER(set_io_completion);
+DECL_HANDLER(remove_io_completion);
+DECL_HANDLER(remove_io_completion_assigned);
DECL_HANDLER(create_class);
DECL_HANDLER(destroy_class);
DECL_HANDLER(set_class_info);
@@ -521,6 +525,10 @@ static const req_handler req_handlers[RE
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_hook_info,
+ (req_handler)req_create_io_completion,
+ (req_handler)req_set_io_completion,
+ (req_handler)req_remove_io_completion,
+ (req_handler)req_remove_io_completion_assigned,
(req_handler)req_create_class,
(req_handler)req_destroy_class,
(req_handler)req_set_class_info,
diff --git a/server/thread.c b/server/thread.c
index 05cf3cd..8581b0b 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -548,7 +548,7 @@ static int signal_object( obj_handle_t h
}
/* select on a list of handles */
-static void select_on( int count, void *cookie, const obj_handle_t *handles,
+void select_on( int count, void *cookie, const obj_handle_t *handles,
int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
{
int ret, i;
diff --git a/server/trace.c b/server/trace.c
index b128ad5..1dd2f1b 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2975,6 +2975,33 @@ static void dump_destroy_class_reply( co
fprintf( stderr, " client_ptr=%p", req->client_ptr );
}
+static void dump_remove_io_completion_request( const struct remove_io_completion_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " cookie=%p,", req->cookie );
+ fprintf( stderr, " timeout=" );
+ dump_abs_time( &req->timeout );
+}
+
+static void dump_remove_io_completion_reply( const struct remove_io_completion_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
+static void dump_remove_io_completion_assigned_request( const struct remove_io_completion_assigned_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_remove_io_completion_assigned_reply( const struct remove_io_completion_assigned_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
static void dump_set_class_info_request( const struct set_class_info_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@@ -3456,6 +3483,10 @@ static const dump_func req_dumpers[REQ_N
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_hook_info_request,
+ (dump_func)dump_create_io_completion_request,
+ (dump_func)dump_set_io_completion_request,
+ (dump_func)dump_remove_io_completion_request,
+ (dump_func)dump_remove_io_completion_assigned_request,
(dump_func)dump_create_class_request,
(dump_func)dump_destroy_class_request,
(dump_func)dump_set_class_info_request,
@@ -3672,6 +3703,10 @@ static const dump_func reply_dumpers[REQ
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_hook_info_reply,
+ (dump_func)dump_create_io_completion_reply,
+ (dump_func)0,
+ (dump_func)dump_remove_io_completion_reply,
+ (dump_func)dump_remove_io_completion_assigned_reply,
(dump_func)0,
(dump_func)dump_destroy_class_reply,
(dump_func)dump_set_class_info_reply,
@@ -3888,6 +3923,10 @@ static const char * const req_names[REQ_
"start_hook_chain",
"finish_hook_chain",
"get_hook_info",
+ "create_io_completion",
+ "set_io_completion",
+ "remove_io_completion",
+ "remove_io_completion_assigned",
"create_class",
"destroy_class",
"set_class_info",
1
0
Re: oleaut32: use setlocale() around sprintfW to force use of period as decimal separator (RESEND)
by Alexandre Julliard 14 Dec '06
by Alexandre Julliard 14 Dec '06
14 Dec '06
Alex Villacís Lasso <a_villacis(a)palosanto.com> writes:
> @@ -4159,7 +4161,9 @@
> {
> WCHAR buff[256];
>
> + setlocale(LC_ALL, "C");
> sprintfW( buff, szFloatFormatW, fltIn );
> + setlocale(LC_ALL, "");
> return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
You can't do that, setlocale() affects the whole process. In any case
we shouldn't need to go through a string to convert a float to a
decimal.
--
Alexandre Julliard
julliard(a)winehq.org
2
4
On 14.12.2006 00:21, Jacek Caban wrote:
> --- a/dlls/mshtml/resource.h
> +++ b/dlls/mshtml/resource.h
> @@ -28,6 +28,9 @@
>
> #define IDS_MESSAGE_BOX_TITLE 2213
>
> +#define IDS_PRINT_HEADER_TEMPLATE 8403
> +#define IDS_PRINT_FOOTER_TEMPLATE 8404
> +
Could it be you forgot to submit the .rc file changes for these new strings?
-f.r.
2
2
Re: [1/2] tests: Add skip_wine, a standard way to skip tests that would cause Wine to crash.
by Alexandre Julliard 14 Dec '06
by Alexandre Julliard 14 Dec '06
14 Dec '06
Francois Gouget <fgouget(a)free.fr> writes:
> Currently there is no standard way of adding a test that works on
> Windows but is known to cause Wine to crash. For instance this is
> the case for bug 6827:
>
> Bug 6827: The SimSig installer crashes
> http://bugs.winehq.org/show_bug.cgi?id=6827
>
> This essentially means that such tests just don't get written, or get
> put inside '#if 0' or 'if (0)' sections so that they are never executed,
> not even on Windows. This means we won't get good Windows coverage until
> Wine has been 'fixed'.
It's not really better with skip_wine; since the test will never be
run on Wine it's useless for regression testing, and we won't even
notice when the bug gets fixed. If the test doesn't crash on Windows,
the right way is to fix Wine to not crash either, that's usually not
too hard (making the test succeed may be harder, but that's why we
have todo_wine).
--
Alexandre Julliard
julliard(a)winehq.org
2
2
On Thu, Dec 14, 2006 at 11:41:25AM +0100, Colin Pitrat wrote:
> Change Log:
> Add an iterator to _xmlnodemap struct
> Implement nextNode function that give nodes one by one
> Implement resetNode that reset the iterator
>
> It's my first patch, so please tell me if something is wrong. I saw on
> http://www.winehq.com/site/sending_patches that I should write a test
> case, but I don't know how to do this (do I need windows ? because I
> don't have it).
Yes, you really should write a test for this. For this dll you could
even use a (legal) native version of msxml3.dll run under Wine.
Some specific points about your patch:
* You seem to have your editor set to display tabs as width 4, please
don't do this. Don't use tabs at all and use 4 spaces per indent level.
* You don't initialize the iterator member of xmlnodemap, this should
be done in create_nodemap.
Huw.
--
Huw Davies
huw(a)codeweavers.com
1
0
Ulrich Czekalla <ulrich.czekalla(a)utoronto.ca> writes:
> diff --git a/dlls/dxguid/dxguid.c b/dlls/dxguid/dxguid.c
> index c2c102f..7ea8d17 100644
> --- a/dlls/dxguid/dxguid.c
> +++ b/dlls/dxguid/dxguid.c
> @@ -44,3 +44,4 @@
> #include "ddrawi.h"
> #include "dxfile.h"
> #include "d3drm.h"
> +#include "ddrawex.h"
There's no ddrawex.h in your patch (note that there isn't one either
in recent SDKs, so you may want to keep these definitions private).
--
Alexandre Julliard
julliard(a)winehq.org
1
0