implementing DllCanUnloadNow questions

Robert Shearman rob at codeweavers.com
Wed Dec 1 10:53:25 CST 2004


James Hawkins wrote:

>On Tue, 30 Nov 2004 15:34:50 -0600, Robert Shearman <rob at 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 "..."?
>  
>

The _Construct function has a similar purpose to the C++ constructor, 
except that we usually allocate the memory in _Construct as well 
(whereas the C++ normally compiler does this). The parameters and return 
value vary according to the situation. If the object has a number of 
properties that are set up at creation time, then these should be passed 
to the constructor.

>>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 "..."?
>  
>

The difference is that the first one is a heap based object, so it does 
the ref-counting itself, whereas the second is a non-heap based object 
where it makes no sense to keep an internal ref-count so UnlockModule is 
always called (and LockModule is always called in AddRef).

>------------------------------------------------------------------------
>
>@@ -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;
>+}
>+
>  
>

Not quite right. The _LockServer method should be the one included in 
the IClassFactory implementation's vtable and I don't see this in this 
patch.

Rob



More information about the wine-devel mailing list