[prev in list] [next in list] [prev in thread] [next in thread] 

List:       wine-devel
Subject:    Re: implementing DllCanUnloadNow questions
From:       James Hawkins <truiken () gmail ! com>
Date:       2004-11-30 23:33:20
Message-ID: 22821af30411301533a9f6b20 () mail ! gmail ! com
[Download RAW message or body]

On Tue, 30 Nov 2004 15:34:50 -0600, Robert Shearman <rob@codeweavers.com> wrote:
> James Hawkins wrote:
> 
> >I would like to work on the DllCanUnloadNow janitorial task, but I was
> >wondering if there are any patches or examples of dll's that correctly
> >implement this so that I can do it right.
> >
> >
> 
> I don't know of any examples so far, but Mike Hearn and I will be
> tackling OLE soon, so that will involve cleaning up ole32. However, that
> probably won't happen until we've done some groundwork on COM first, so
> feel free to beat us to it and make a shining example of a DLL that
> correctly implements DllCanUnloadNow.
> 
> 
> 
> >Is LockServer(TRUE/FALSE) the same as this example?
> >
> >static HRESULT WINAPI SFCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
> >       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
> >       FIXME("(%p)->(%d),stub!\n",This,dolock);
> >       return S_OK;
> >}
> >
> >If they are the same, what is needed to complete this stub?  I would
> >think that there would be a refCount variable that is incremented if
> >dolock is true and decremented if dolock is false.  Also, should the
> >LockServer functions be listed in the spec files of the dlls?
> >
> >
> 
> No, the LockServer functions are part of IClassFactory vtables. Only
> DllCanUnloadNow needs to be exported.
> 
> >After implementing LockServer, it should be an easy matter to do a
> >check for refCount == 0 to see if the dll can be unloaded or not.  Am
> >I heading in the right direction?
> >
> >
> 
> To implement DllCanUnloadNow properly you need to do the following:
> 1. Add a variable "LONG cLocks" and two function for manipulating it:
> void LockModule()
> {
>     InterlockedIncrement(&cLocks);
> }
> 
> void UnlockModule()
> {
>     InterlockedDecrement(&cLocks);
> }
> 2. Increment cLocks on construction of every heap object:
> static HRESULT Example_Construct(...)
> {
> ...
>     LockModule();
>     return S_OK;
> }
> 3. Decrement cLocks on destruction of every heap object:
> static ULONG Example_Release(...)
> {
>     ...
>     res = InterlockedDecrement(&This->cRefs);
>     if (!res)
>     {
>        /* Free object's resources, including memory, etc. */
>        UnlockModule();
>     }
> }
> 4. For non-heap based objects (commonly objects with no state, like
> IClassFactory):
> static ULONG Example_AddRef(...)
> {
>     LockModule();
>     return 2; /* non-heap object */
> }
> 
> static ULONG Example_Release(...)
> {
>     UnlockModule();
>     return 1;
> }
> 5. Implement IClassFactory_LockServer's as follows:
> HRESULT WINAPI Example_LockServer(...)
> {
>     if (bLock)
>        LockModule();
>     else
>        UnlockModule();
>     return S_OK;
> }
> 6. Then implement DllCanUnloadNow:
> HRESULT WINAPI DllCanUnloadNow()
> {
>     return cLocks > 0 : S_FALSE : S_OK;
> }
> 
> Rob
> 

Attached is my beginning attempts at adding DllCanUnloadNow to msi. 
There are a couple questions I have though.

> static HRESULT Example_Construct(...)
> {
> ...
>     LockModule();
>     return S_OK;
> }

Is _Construct the same as _AddRef()?  I'm thinking it's not.  If it
isn't, I need to add a MSI_Construct to msi.  What are the parameters
to the Construct function and what would usually go in the place of
the "..."?

> static ULONG Example_Release(...)
> {
>     ...
>     res = InterlockedDecrement(&This->cRefs);
>     if (!res)
>     {
>        /* Free object's resources, including memory, etc. */
>        UnlockModule();
>     }
> }

> static ULONG Example_Release(...)
> {
>     UnlockModule();
>     return 1;
> }

Are these _Release's referring to the same function?  If not, what is
the difference?  If so, which one should be implemented and what
usually goes in the place of the "..."?

-- 
James Hawkins

["msi-dllcanunloadnow.diff" (text/x-patch)]

Index: dlls/msi/msi.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.c,v
retrieving revision 1.42
diff -u -r1.42 msi.c
--- dlls/msi/msi.c	7 Oct 2004 03:06:50 -0000	1.42
+++ dlls/msi/msi.c	1 Dec 2004 00:29:19 -0000
@@ -42,6 +42,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
+/* for reference counting */
+LONG cLocks = 0;
+
 /*
  * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
  *  which is a problem because LPCTSTR isn't defined when compiling wine.
@@ -1567,12 +1570,32 @@
   return S_OK;
 }
 
+void LockModule()
+{
+  InterlockedIncrement(&cLocks);
+}
+
+void UnlockModule()
+{
+  InterlockedDecrement(&cLocks);
+}
+
+HRESULT WINAPI MSI_LockServer(LPCLASSFACTORY iface,BOOL bLock)
+{
+  if (bLock)
+    LockModule();
+  else
+    UnlockModule();
+
+  return S_OK;
+}
+
 /******************************************************************
  *		DllCanUnloadNow (MSI.@)
  */
 BOOL WINAPI MSI_DllCanUnloadNow(void)
 {
-  return S_FALSE;
+  return (cLocks > 0) ? S_FALSE : S_OK;
 }
 
 UINT WINAPI MsiEnumRelatedProductsA (LPCSTR lpUpgradeCode, DWORD dwReserved,


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic