ChangeLog: In the global interface table: * Print warnings when things go wrong * Alter the way we do refcounting * Don't release the stream on retrieval, just rewind it instead. * Implement thread safety
Index: dlls/ole32/git.c =================================================================== RCS file: /home/wine/wine/dlls/ole32/git.c,v retrieving revision 1.4 diff -u -r1.4 git.c --- dlls/ole32/git.c 17 Jun 2003 03:57:18 -0000 1.4 +++ dlls/ole32/git.c 21 Aug 2003 13:45:33 -0000 @@ -26,6 +26,8 @@ #include "config.h" +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include <assert.h> #include <stdlib.h> #include <stdio.h> @@ -55,7 +57,7 @@ typedef struct StdGITEntry { DWORD cookie; - IID iid; /* IID of the interface */ + IID iid; /* IID of the interface */ IStream* stream; /* Holds the marshalled interface */ struct StdGITEntry* next; @@ -98,6 +100,16 @@ StdGlobalInterfaceTable_GetInterfaceFromGlobal }; +static CRITICAL_SECTION git_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &git_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": global interface table") } +}; +static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + + /*** * Let's go! Here is the constructor and destructor for the class. * @@ -107,13 +119,11 @@ void* StdGlobalInterfaceTable_Construct() { StdGlobalInterfaceTableImpl* newGIT; - TRACE("constructing\n"); - newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl)); if (newGIT == 0) return newGIT; newGIT->lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; - newGIT->ref = 0; /* Initialise the reference count */ + newGIT->ref = 1; /* Initialise the reference count */ newGIT->firstEntry = NULL; /* we start with an empty table */ newGIT->lastEntry = NULL; newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */ @@ -128,6 +138,7 @@ FIXME("Revoke held interfaces here\n"); HeapFree(GetProcessHeap(), 0, self); + StdGlobalInterfaceTableInstance = NULL; } /*** @@ -139,12 +150,15 @@ StdGITEntry* e; TRACE("iface=%p, cookie=0x%x\n", iface, (UINT)cookie); - + + EnterCriticalSection(&git_section); e = self->firstEntry; while (e != NULL) { if (e->cookie == cookie) return e; e = e->next; } + LeaveCriticalSection(&git_section); + TRACE("Entry not found\n"); return NULL; } @@ -169,21 +183,21 @@ } else return E_NOINTERFACE; /* Now inc the refcount */ - /* we don't use refcounts for now: StdGlobalInterfaceTable_AddRef(iface); */ + StdGlobalInterfaceTable_AddRef(iface); return S_OK; } ULONG WINAPI StdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface) { StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - self->ref++; + /* InterlockedIncrement(self->ref); */ return self->ref; } ULONG WINAPI StdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface) { StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - self->ref--; + /* InterlockedDecrement(self->ref); */ if (self->ref == 0) { /* Hey ho, it's time to go, so long again 'till next weeks show! */ StdGlobalInterfaceTable_Destroy(self); @@ -208,10 +222,13 @@ if (pUnk == NULL) return E_INVALIDARG; /* marshal the interface */ + TRACE("About to marshal the interface\n"); hres = CoMarshalInterThreadInterfaceInStream(riid, pUnk, &stream); if (hres) return hres; entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); if (entry == NULL) return E_OUTOFMEMORY; + + EnterCriticalSection(&git_section); entry->iid = *riid; entry->stream = stream; @@ -227,7 +244,10 @@ /* and return the cookie */ *pdwCookie = entry->cookie; - TRACE("Cookie is 0x%ld\n", entry->cookie); + + LeaveCriticalSection(&git_section); + + TRACE("Cookie is 0x%lx\n", entry->cookie); return S_OK; } @@ -242,12 +262,18 @@ TRACE("Entry not found\n"); return E_INVALIDARG; /* not found */ } - + + /* Free the stream */ + IStream_Release(entry->stream); + /* chop entry out of the list, and free the memory */ + EnterCriticalSection(&git_section); if (entry->prev) entry->prev->next = entry->next; else self->firstEntry = entry->next; if (entry->next) entry->next->prev = entry->prev; else self->lastEntry = entry->prev; + LeaveCriticalSection(&git_section); + HeapFree(GetProcessHeap(), 0, entry); return S_OK; } @@ -255,17 +281,36 @@ HRESULT WINAPI StdGlobalInterfaceTable_GetInterfaceFromGlobal(IGlobalInterfaceTable* iface, DWORD dwCookie, REFIID riid, void **ppv) { StdGITEntry* entry; HRESULT hres; - - TRACE("dwCookie=0x%lx, riid=%s\n", dwCookie, debugstr_guid(riid)); + LARGE_INTEGER move; + LPUNKNOWN lpUnk; + + TRACE("dwCookie=0x%lx, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); if (entry == NULL) return E_INVALIDARG; - if (!IsEqualIID(&entry->iid, &riid)) return E_INVALIDARG; - + if (!IsEqualIID(&entry->iid, riid)) { + WARN("entry->iid (%s) != riid\n", debugstr_guid(&entry->iid)); + return E_INVALIDARG; + } + TRACE("entry=%p\n", entry); + /* unmarshal the interface */ - hres = CoGetInterfaceAndReleaseStream(entry->stream, riid, *ppv); - if (hres) return hres; + hres = CoUnmarshalInterface(entry->stream, riid, &lpUnk); + if (hres) { + WARN("Failed to unmarshal stream\n"); + return hres; + } + + /* rewind stream, in case it's used again */ + move.s.LowPart = 0; + move.s.HighPart = 0; + IStream_Seek(entry->stream, move, STREAM_SEEK_SET, NULL); + + /* addref it */ + IUnknown_AddRef(lpUnk); + *ppv = lpUnk; + TRACE("ppv=%p\n", ppv); return S_OK; }