Archive: DB call from plugin inside a custom PRE function


DB call from plugin inside a custom PRE function
I have a custom page with a create and leave function. It is right before my MUI_PAGE_INSTFILES page.
In the create function, I make a call to my plugin dll.
The plugin creates a connection to a database with CDatabase::OpenEx() and executes some SQL.
Everything on the custom page works fine - callbacks, leave function is called, etc...
Then the INSTFILES page is shown, but everything is grayed out/frozen, I cannot even close the setup dialog without killing the process. The details button and listbox are not shown yet either.
I placed a messagebox into my -pre Section, but code never reaches this point.

It seems so strange that simply opening a connection to a db in my plugin causes this effect downstream. I removed every line in my plugin function except the opening and closing of the db - I have stepped over it, it runs fine with no exceptions thrown. If I remove the db.openex call, it runs fine. If I remove the line that calls this plugin in my nsi script, it installs fine.

Anybody seen anything like this?


You may need to use the adsize statement and declare enough memory for your plugin to run properly. What I believe is happening is that everything your plugin is doing is being placed in the installers stack, and therefore corrupting everything when it returns to the installer. By declaring a chunk of memory for your plugin to run in may resolve this issue.


My plugin is huge, and I already make many calls to it without any trouble. I had narrowed the culprit down to a call to comctrl.dll from User32.dll. However, your tip led me to look in a different place. I was focusing on memory/stack usage, but the addsize statement deals with disk space.
I then ran across the FileBufSize statement, which was defaulted to 32 mb for the compiler. Being used for both input and output, it might reach a size of 64 mb... but
my Setup.exe was compiling to well over 40 mb.

I doubled my FileBufSize to be 64mb, and !BAM! it works.
Amazing.

Thanks for the lead,
-Coho


hahaha.... I hate it when I speak too soon. My C++ pugin and my script were out of synch, and this problem is not yet fixed.
I now believe it has something to do with the Windows Side by Side architechure (support for older versions of C++). SxS is Kinda like .NET's GAC, but for C++.

Anyways, NSIS loads this SxS version of comctl32.dll:

C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.1515_x-ww_7bb98b8a\comctl32.dll

for use with its dialogs. When I make a call to CDatabase::OpenEx, this one is loaded:

c:\Windows\System32\comctl32.dll

and then unloaded. I believe these both cannot be loaded in memory at the same time - ? - and the SxS is possibly unloaded. Since my failure is a call from User32 to comctrl32, with a response of "Function not found", I believe the SxS is either unloaded, or User32.dll tries to look in the other comctrl32 for a function that no longer exists in memory.

I will try to load the SxS comctl32 library back after my db call, then I will try to reload User32 if that fails.

I'll write back with my findings.


Ok, now it really works. I scattered a bunch of GetModuleHandle calls in my plugin:

HMODULE hm;

hm = GetModuleHandle( _T("comctl32.dll") );

hm = GetModuleHandle( _T("C:\\WINDOWS\\WinSxS\\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.1515_x-ww_7bb98b8a\\comctl32.dll") );

hm = GetModuleHandle( _T("C:\\WINDOWS\\system32\\comctl32.dll") );

And found out that both comctl32s can be loaded at once.

Status before my CDatabase::OpenEx call.
Just DLL name: loaded, and gets the SxS one.
SxS specific: loaded, and gets same handle.
Windows32 path: not loaded.

After my Db call.
DLL name only: loaded (SxS).
SxS name: same handle.
Windows32 path: loaded with diff handle.

After my CDatabase object goes out of scope.
DLL Name: SxS still loaded
SxS Name: still loaded
Windows32 path: no longer loaded.

I thus thought User32.dll was calling into the unloaded comctl32.dll
But no, freeing and reloading user32 it did not help.

If I add the line...

hm = LoadLibrary( _T("C:\\WINDOWS\\system32\\comctl32.dll") );

...it is fixed. For reals this time. Apparently MUI_PAGE_INSTFILES needs this version of comctl32.dll loaded, and thinks it is still loaded after the db call - even though the db call loads then unloads it.
So the fix is to manually load it after my CDatabase object goes out of scope.

I think this is an NSIS bug - why does this page not load the dll it needs? It is not loaded to begin with... Does the reference count for this dll get set improperly?

-Coho


NSIS does not load or unload any DLL for any page (besides the plug-in itself of course...). NSIS has imports from comctl32.dll and a manifest file that tells Windows to load comctl32.dll version 6, if available.

If getting unloaded by your DLL causes comctl32.dll version 5 to freezee NSIS, you can keep your DLL loaded with /NOUNLOAD the installation finishes.


I use /NOUNLOAD for all my dll calls, but this is not the issue. The destructor for my CDatabase object unloads the current windows version of comctl32.dll because the CDatabase object is the one that loads it. So the comctl32.dll gets unloaded even if my dll is still loaded.
-
Somehow, even though one version of comctl32.dll is loaded (the SxS one), when CDatabase loads and unloads the other comctl32.dll, NSIS breaks because it tries to call into the unloaded one. I'm not sure how NSIS keeps track of which dlls to use, but it seems to either become confused or it confuses Windows somehow.


NSIS doesn't handle DLL loading. Windows loader does this according to the IAT of the PE.