Windbg find missing dlls - windows

Background:
I am writing a app using an open source library. This open source libarary comes with many plugin dlls. Some of which we are using in our project (NOT all of them).
While in developement, we just consumed the library as a whole and everything worked fine.
Now when we are trying to build a shippable binary package, seems like we need to sort things out and find only those plugin binaries (dlls) from the open source lib which are in use.
These library comes with 100 of plugin dlls. During runtime, we just using a primary lib plugin dlls, which in turn loads up other dlls (Curently when we run the App, it loads both essential or non-essential dlls). We need to find out a way how to only pack those dlls which we are using in the code. And since these are plugins only, if the primary dll don't finds the non-essential dlls, then it is completely fine (App won't crash). We just have to help it locate the essential ones (without that pur either won't work or will crash).
Approach:
In order to find only the essential dlls, what I have done is removed all the dlls from the path and started placing one dlls each time to check, until our App start working. The problem is that with this approach it is going to take a long time. Rather than randomly picking each dlls I trying to use WinDbg to find out which missing dlls has caused the failure.
Question:
Is there a way in Windbg to identify from a dump, to see which missing dll has caused failure?

Your Question As it Appears is Ambiguous.
Most of commenters have provided you hints For a live Debugging Session Like.
Ldr Snaps
ProcMon
Etw Traces
you seem to have asked For looking at it in a dump
Question: Is there a way in Windbg to identify from a dump, to see which missing dll has caused failure?
a plugin by its nature will be allowed to fail gracefully By its Parent Binary and as such it will Create an Unload Event
This Will Be reflected in the dump by lm Command
the Unloaded Modules will be listed at the end of Module List
:\>cdb -c "lm;q" -z c:\odbgdmp.dmp |awk "/Unloaded/,/quit/"
Unloaded modules:
66940000 66957000 OllyDumpEx_Imm17.dll
quit:
ntdll maintains an array 0x40 last unloaded dlls windbg Retrieves this from the same place as the below code does.
#include <stdio.h>
#include <windows.h>
typedef struct _RTL_UNLOAD_EVENT_TRACE {
PVOID BaseAddress;SIZE_T SizeOfImage;ULONG Sequence;ULONG TimeDateStamp;
ULONG CheckSum;WCHAR ImageName[32];
} RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
typedef VOID (WINAPI* RtlGetUnloadEventTraceEx) (
_Out_ PULONG *ElementSize,_Out_ PULONG *ElementCount,_Out_ PVOID *EventTrace
);
RtlGetUnloadEventTraceEx evt;
int main(void) {
//ollydbg plugin wont load in curproc will create an unloaded mod event
LoadLibraryA("OllyDumpEx_Od20.dll");
HMODULE nt=LoadLibraryA("ntdll.dll");
if(nt != NULL){
evt=(RtlGetUnloadEventTraceEx)GetProcAddress(nt,
"RtlGetUnloadEventTraceEx");
PULONG elsiz = NULL, elcnt = NULL;PVOID evarr = NULL;
evt(&elsiz,&elcnt,&evarr);
printf("%p %p %p\n" , elsiz,elcnt,evarr);
printf("%x %x %x\n" , *elsiz,*elcnt,*(int*)evarr);
PRTL_UNLOAD_EVENT_TRACE u1=((PRTL_UNLOAD_EVENT_TRACE)(*(int*)evarr));
printf("bas\t%p\nsiz\t%x\nSeq\t%x\nstamp\t%x\nCsum\t%x\nname\t%S\n",
u1->BaseAddress,u1->SizeOfImage,u1->Sequence,u1->TimeDateStamp,
u1->CheckSum,u1->ImageName);
}
return 0;
}
on executing
:\>UnloadModList.exe
7706CDA0 7706CD9C 77067144
5c 40 1fafd8
base 676F0000
size 19000
Seq 0
stamp 55953f77
Chksum 12b14
imgname OllyDumpEx_Od20.dll
corroboration of dll details which failed to load
:\>dumpbin /headers OllyDumpEx_Od20.dll | grep -iE "CheckSum|Stamp|size of image|image base"
55953F77 time date stamp Thu Jul 2 19:11:11 2015
6A680000 image base (6A680000 to 6A698FFF)
19000 size of image
12B14 checksum

Related

In which cases is the dynamic CRT not already initialized on call to user supplied DllMain?

Preamble: This question is specifically concerned with, and only with, the behavior of the dynamic CRT used through /MD. It does not question the validity of any other recommendations wrt. DllMain.
As we've been told: (ref: Dynamic-Link Library Best Practices, MSDN, May 17, 2006)
You should never perform the following tasks from within DllMain:
...
Use the memory management function from the dynamic C Run-Time (CRT). If the CRT DLL is not initialized, calls to these functions can cause the process to crash.
...
Others have questioned this already (as in: questioned the validity of the argument) and since we helpfully get an answer there, we can clearly see one rather simple case where this could potentially cause troubles:
You are working from the assumption that the entrypoint for a DLL is always _DllMainCRTStartup. This is not the case, it is merely the linker's default. It can be anything a programmer wants it to be, swiftly and easily changed with the linker's /ENTRYPOINT option. There is nothing that Microsoft can do to prevent this.
So these are the elements of this question:
Is there any other situation when linking /MD and not supplying a custom /ENTRYPOINT, where the dynamic CRT ought to not be fully initialized?
Specifically, if all DLL loading only done through "static dependencies", i.e. no explicit LoadLibrarycalls at all, just link time DLL dependencies.
Bonus: The MS docs specifically call out "memory management function", but as far as I can tell, if the CRT is not initialized, potentially any CRT function should be unsafe. Why call out memory management functions in this way?
No.3:
Wrt. to the custom ENTRYPOINT: I don't quite see how this can be such an important scenario that it need be included in the not-do-in-DllMain list without further qualification. IFF I supply a custom entry point, I'm responsible for correctly initializing the CRT, or the CRT will not work properly anywhere in my program, not just DllMain. Why call out the DllMain part specifically?
This leads me back to Q.1, namely if this is the only scenario where this is problematic for the dynamic CRT. A clarification or eye-opener why this would be more important for DllMain that for other parts of the DLL, or what I might miss here, would be appreciated.
Bonus links:
When are global objects constructed and destructed by Visual C++?
DllMain : a horror story
Calling LoadLibrary from DllMain
Rationale: I feel I should add this for context: I am asking this because we have massive amounts of code doing things via global C++ object constructors. Things that actually broke have been vetted out over the years (like concurrent LoadLibrary, thread sync, etc.), but all the code is full of std C++ and CRT functions, that happily have been working for years on Windows XP, 7 and Windows 10 without any known hiccups. While I'm not one to cry "but it just works", I have to do an engineering judgment here on whether there is any short-to-medium value in trying to "fix" this. Therefore, I would appreciate if the soapbox answers could be left in their boxes.
Is there any other situation when linking /MD and not supplying a
custom /ENTRYPOINT, where the dynamic CRT ought to not be fully
initialized?
first some notation:
X have static import (depends on) Y and Z : X[ Y, Z]
X entry point : X_DllMain
X_DllMain call LoadLibrary(Y) : X<Y>
when we use /MD - we use crt in separate DLL(s). initialized in this context mean that entry point(s) of crt DLL(s) already called. so question can be more general and clear:
are from X[Y] => Y_DllMain called before X_DllMain ?
in general case no. because can be circular dependency, when Y[X] or Y[Z[X]].
most known example user32[gdi32], and gdi32[user32] or in win10 depends on gdi32[gdi32full[user32]] . so user32_DllMain or gdi32_DllMain must be called first ? however obvious that any crt DLL(s) not depends on our custom DLL. so let exclude circular dependency case.
when loader load module X - it load all it dependency modules (and it dependency - this is recursive process), if it already not in memory, then loader build call graph, and begin call modules entry points. obvious if A[B], loader always try call B_DllMain before A_DllMain (except circular dependency when order of calls is undefined). but which modules will be in call graph ? all X dependency modules ? of course no. some of this modules can already be in memory (loaded) when we begin load X. so it entry points already called, with DLL_PROCESS_ATTACH and must not be called second time now. this strategy used in xp, vista, win7:
when we load X:
load or locate in memory all it dependency modules
call entry points of new loaded (after X) modules only.
if A[B] - call B_DllMain before A_DllMain
example: loaded X[Y[W[Z]], Z]
//++begin load X
Z_DllMain
W_DllMain
Y_DllMain
X_DllMain
// --end load X
but this scenario not take in account next case - some module can be already in memory, but it entry point yet not called. how this can happen ?
this can happen in case some module entry point call LoadLibrary.
example - loaded X[Y<W[ Z]>, Z]
//++begin load X
Y_DllMain
//++begin load W
W_DllMain
//--end load W
Z_DllMain
X_DllMain
// --end load X
so W_DllMain will be called before Z_DllMain, despite W[Z]. exactly because this not recommended call LoadLibrary from DLL entry point.
but from Dynamic-Link Library Best Practices
This can cause a deadlock or a crash.
the words about deadlock not true - of course any deadlock can not be basically. where ? how ? we already hold loader lock inside DLL entry point and this lock can be acquired recursively. crash really can be (before win8).
or another false:
Call ExitThread. Exiting a thread during DLL detach can cause the
loader lock to be acquired again, causing a deadlock or a crash.
can cause the loader lock to be acquired again - not can but always
causing a deadlock - false - we already hold this lock
a crash - no any crash will be, else one false
but which is really will be - thread exit without free loader lock. it became busy forever. as result any new thread creation or exit, any new DLL load or unload, or just ExitProcess call - hung, when try acquire loader lock. so deadlock here really will be, but not during Call ExitThread - latter.
and of course interesting note - the windows itself call LoadLibrary from DllMain - user32.dll always call LoadLibrary for imm32.dll from it entry point (still true and on win10)
but begin from win8 (or win8.1) loader became more smart on handle dependency modules. now 2 is changed
2. call entry points of new loaded (after X) modules or if module yet not initialized.
so in modern windows (8+) for load X[Y<W[Z]>, Z]
//++begin load X
Y_DllMain
//++begin load W
Z_DllMain
W_DllMain
//--end load W
X_DllMain
// -- end load X
the Z initialization will be moved to W load call graph. as result all will be correct now.
for test this we can build next solution: test.exe[ kernel32, D1< D2[kernel32, msvcrt] >, msvcrt ]
D2 import from kernel32 and msvcrt only and export SomeFunc
D1 import only from kernel32 and call LoadLibraryW(L"D2") from it entry point, and then call D2.SomeFunc
test.exe import from kernel32, D1 and msvcrt
(exactly in this order ! this is critical important - D1 must be before msvcrt in import, for this need set D1 before msvcrt in linker command line)
as result D1 entry point will be called before msvcrt. this is normal - D1 not depends on msvcrt
but when D1 load D2 from it entry point, became interesting
code for D2.dll ( /NODEFAULTLIB kernel32.lib msvcrt.lib )
#include <Windows.h>
extern "C"
{
__declspec(dllimport) int __cdecl sprintf(PSTR buf, PCSTR format, ...);
}
BOOLEAN WINAPI MyEp( HMODULE , DWORD ul_reason_for_call, PVOID )
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
OutputDebugStringA("D2.DllMain\n");
}
return TRUE;
}
INT_PTR WINAPI SomeFunc()
{
__pragma(message(__FUNCDNAME__))
char buf[32];
// this is only for link to msvcrt.dll
sprintf(buf, "D2.SomeFunc\n");
OutputDebugStringA(buf);
return 0;
}
#ifdef _WIN64
#define FuncName "?SomeFunc##YA_JXZ"
#else
#define FuncName "?SomeFunc##YGHXZ"
#endif
__pragma(comment(linker, "/export:" FuncName ",#1,NONAME,PRIVATE"))
code for D1.dll ( /NODEFAULTLIB kernel32.lib )
#include <Windows.h>
#pragma warning(disable : 4706)
BOOLEAN WINAPI MyEp( HMODULE hmod, DWORD ul_reason_for_call, PVOID )
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
OutputDebugStringA("D1.DllMain\n");
if (hmod = LoadLibraryW(L"D2"))
{
if (FARPROC fp = GetProcAddress(hmod, (PCSTR)1))
{
fp();
}
}
}
return TRUE;
}
INT_PTR WINAPI SomeFunc()
{
__pragma(message(__FUNCDNAME__))
OutputDebugStringA("D1.SomeFunc\n");
return 0;
}
#ifdef _WIN64
#define FuncName "?SomeFunc##YA_JXZ"
#else
#define FuncName "?SomeFunc##YGHXZ"
#endif
__pragma(comment(linker, "/export:" FuncName ",#1,NONAME"))
code for exe ( /NODEFAULTLIB kernel32.lib D1.lib msvcrt.lib )
#include <Windows.h>
extern "C"
{
__declspec(dllimport) int __cdecl sprintf(PSTR buf, PCSTR format, ...);
}
__declspec(dllimport) INT_PTR WINAPI SomeFunc();
void ep()
{
char buf[32];
// this is only for link to msvcrt.dll
sprintf(buf, "exe entry\n");
OutputDebugStringA(buf);
ExitProcess((UINT)SomeFunc());
}
output for xp:
LDR: D1.dll loaded - Calling init routine
D1.DllMain
Load: D2.dll
LDR: D2.dll loaded - Calling init routine
D2.DllMain
D2.SomeFunc
LDR: msvcrt.dll loaded - Calling init routine
exe entry
D1.SomeFunc
for win7:
LdrpRunInitializeRoutines - INFO: Calling init routine for DLL "D1.dll"
D1.DllMain
Load: D2.dll
LdrpRunInitializeRoutines - INFO: Calling init routine for DLL "D2.DLL"
D2.DllMain
D2.SomeFunc
LdrpRunInitializeRoutines - "msvcrt.dll"
exe entry
D1.SomeFunc
in both case call flow is the same - D2.DllMain called before msvcrt entry point, despite D2[msvcrt]
but on win8.1 and win10 - call flow is another:
LdrpInitializeNode - INFO: Calling init routine for DLL "D1.dll"
D1.DllMain
LdrpInitializeNode - INFO: Calling init routine for DLL "msvcrt.dll"
LdrpInitializeNode - INFO: Calling init routine for DLL "D2.DLL"
D2.DllMain
D2.SomeFunc
exe entry
D1.SomeFunc
the D2 entry point called after msvcrt initialization.
so what is conclusion?
if when module X[Y] is loaded and no not initialized Y in memory - Y_DllMain will be called before X_DllMain. or in another words - if nobody call LoadLibrary(X) (or LoadLibrary(Z[X]) ) from DLL entry point. so if your DLL will be loaded "normal" way (not by call LoadLibrary from DllMain or injected from driver on some dll load event) - you can be sure that crt entry point already called (crt initialized)
more - if you run on win8.1+ - and X[Y] is loaded - Y_DllMain will be always called before X_DllMain.
now about custom /ENTRYPOINT in your dll.
even if you use crt in separate DLLs - some small crt code will be statically linked to your module DllMainCRTStartup - which call your function DllMain (this is not a entry point) by name. so in case dynamic crt - we really have 2 crt parts - main part in separate DLLs and it will be initialized before your DLL entry point is called (if not special case which i describe higher and win7,vista,xp). and small static part (code inside your module). when this static part will be called already full depend from you. this part DllMainCRTStartup do some internal initializations, initialize global objects in your code (initterm) and call DllMain, after it return (on dll detach) call destructors for globals..
if you set custom entry point in DLL - at this point crt in separate DLLs already initialized, but your static crt no (as and global objects). from this custom entry point you will be need call DllMainCRTStartup

Resolving Error R6016 - Not enough space for thread data

My statically-linked Visual C++ 2012 program sporadically generates a CRTL error: "R6016 - Not enough space for thread data".
The minimal documentation from Microsoft says this error message is generated when a new thread is spawned, but not enough memory can be allocated for it.
However, my code only explicitly spawns a new thread in a couple of well-defined cases, neither of which are occurring here (although certainly the Microsoft libraries internally spawn threads at well). One user reported this problem when the program was just existing in the background.
Not sure if it's relevant, but I haven't overridden the default 1MB reserved stack size or heap size, and the total memory in use by my program is usually quite small (3MB-10MB on a system with 12GB actual RAM, over half of which is unallocated).
This happens very rarely (so I can't track it down), and it's been reported on more than one machine. I've only heard about this on Windows 8.1, but I wouldn't read too much into that.
Is there some compiler setting somewhere that might influence this error? Or programming mistake?
This turned out to be caused by calling CreateThread rather than _beginthread. Microsoft documentation in the Remarks section states that CreateThread causes conflicts when using the CRT library, and indeed, once we made the change, we never saw that error again.
You have to call TlsAlloc in DllMain if the Windows version is Vista or higher .
implicit TLS handling was rewritten in Windows Vista [...]
threadprivate and __declspec(thread) should function correctly in
run-time loaded DLLs since then.
BOOL APIENTRY DllMain(HINSTANCE hinstDll, DWORD fdwReason,
LPVOID lpvReserved)
{
static BOOL fFirstProcess = TRUE;
BOOL fWin32s = FALSE;
DWORD dwVersion = GetVersion();
static DWORD dwIndex;
if ( !(dwVersion & 0x80000000) && LOBYTE(LOWORD(dwVersion))<4 )
fWin32s = TRUE;
if (dwReason == DLL_PROCESS_ATTACH) {
if (fFirstProcess || !fWin32s) {
dwIndex = TlsAlloc();
}
fFirstProcess = FALSE;
}
}
kb 118816
When a program is started the size of the TLS is determined by taking
into account the TLS size required by the executable as well as the
TLS requirements of all other implicitly loaded DLLs. When you load
another DLL dynamically with LoadLibrary or unload it with
FreeLibrary, the system has to examine all running threads and to
enlarge or compact their TLS storage accordingly.
Your DLL code should be modified to use such TLS functions as TlsAlloc, and to allocate TLS if the DLL is loaded with LoadLibrary. Or, the DLL that is using __declspec(thread) should only be implicitly loaded into the application.
Bottom line: LoadLibrary ain't thread-safe.
I discovered that process is in 32 bit.
In this case I increase memory to process with the command
bcdedit /set increaseuserva 3072

DRIVER_OBJECT.DriverSection

Does anyone have an idea what is the structure of the DriverSection pointer in the x64 bit version of win7. In 32 bit I used the following:
typedef struct _KLDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
PVOID ExceptionTable;
ULONG ExceptionTableSize;
//ULONG padding1;
PVOID GpValue;
PVOID NonPagedDebugInfo;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT __Unused5;
PVOID SectionPointer;
ULONG CheckSum;
//ULONG Padding2;
PVOID LoadedImports;
PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
And everything was working but on x64 it is crashing when trying to dereference the LIST_ENTRY. Any pointers/tips would be greatly appreciated
And everything was working but on x64 it is crashing when trying to dereference the LIST_ENTRY. Any pointers/tips would be greatly appreciated
If you can hook up a kernel debugger, you can verify whether or not the DriverSection object matches your definition. To do this, pick a driver you wish to debug - I tend to use a simple one I have. Load its symbols by fixing the symbol path to include its pdb, then break into windbg or kd and type:
.reload
To reload the symbols. Then you can load the driver with:
sc start drivername
having created its service assuming it is a legacy driver. Type:
bu drivername!DriverEntry
to set a breakpoint on the DriverEntry for this module. The difference between bp and bu is that bu breakpoints are evaluated and set on module load. Currently, of course, DriverEntry won't be called, but if we reload the driver it will:
sc stop drivername
sc start drivername
Now your breakpoint should be hit and rcx will contain the DRIVER_OBJECT structure, since it is a pointer argument and pointer/integer arguments are passed in rcx,rdx,r8,r9 according to the Windows ABI. So, you can print out the driver object structure with:
dt _DRIVER_OBJECT (address of rcx)
Which will give you a pointer to the driver section. Then, type:
dt _LDR_DATA_TABLE_ENTRY (driver section object pointer)
This should give you your driver section object. _LDR_DATA_TABLE_ENTRY is actually present in the Windows symbols, so this will work.
Using the debugger, you should be able to dereference the LIST_ENTRY pointers (.flink and .blink) successfully (try dpps on the address of the _LDR_DATA_TABLE_ENTRYstructure, for example). If you do it successfully, one of those addresses will resolve tont!PsLoadedModuleList`.
What I'm trying to say is that in a roundabout way, is that:
Either there is a bug in your code somewhere, or
You've hit upon a synchronisation issue. Remember, this structure is supposed to be opaque and we're not supposed to be modifying it in any way. It's also liable to change on us, and we don't know where the lock for synchronising access to it is.
If you are certain 1 is not the case, it is likely 2 is. Luckily, Microsoft actually provided a function to get the information from these structures called AuxKlibQueryModuleInformation(). You do need to add an extra library to your driver, but that's not the end of the world. Include Aux_klib.h. There's also a code sample on the MSDN page showing how to use it - it's pretty straightforward.

How to conditionally execute function if operating system supports it?

I'd like to build an application that invokes CancelIoEx on Windows Vista and newer (where it is supported) and does something else on Windows XP (where it is not).
What happens if I compile the application under Windows 7 but run it under Windows XP? What will happen at runtime? Will I get some sort of load error?
How do I get my application to pick one code path or another (avoiding load errors) depending on what operating system is being used at runtime? Please provide sample code.
UPDATE: Please note that the DLL exists on Windows XP but the function does not.
Yes, an application that references a non-existent DLL export will fail to load.
Adding code to take different paths based on the OS version won't help much, because you'll still have the reference to the non-existent function.
Instead, you need to resolve the reference at run-time.
One option is Delay Load Import (with the /DELAYLOAD linker flag), but I don't think this is supported for the core system DLLs (like kernel32).
The other is to use LoadLibrary and GetProcAddress. The code is something like this, though in reality you'd do the lookup once when your app starts, not each time you call the function.
// Declare type of pointer to CancelIoEx function
typedef BOOL (WINAPI *CancelIoExType)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
// Load module; won't fail because it's already imported
HMODULE hKernel32 = LoadLibrary(L"kernel32.dll");
// Look up function address
CancelIoExType pCancelIoEx = (CancelIoExType)GetProcAddress(hKernel32, "CancelIoEx");
// Do something with it
if (pCancelIoEx)
{
// Function exists so call it
pCancelIoEx(hMyFile, pMyOverlapped);
}
else
{
// Function doesn't exist
}
In order to resolve a symbol at runtime, you need to use LoadLibrary and GetProcAddress:
HMODULE kernel32 = LoadLibrary("kernel32.dll");
BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED) = GetProcAddress(kernel32, "CancelIoEx");
In the case that CancelIoEx is not available, you will get NULL back from GetProcAddress. Once you have the pointer (you only need to do the above once), you can call it normally with:
pCancelIoEx(h, &lp);

Problems using wxWidgets (wxMSW) within multiple DLL instances

Preface
I'm developing VST-plugins which are DLL-based software modules and loaded by VST-supporting host applications. To open a VST-plugin the host applications loads the VST-DLL and calls an appropriate function of the plugin while providing a native window handle, which the plugin can use to draw it's GUI. I managed to port my original VSTGUI
code to the wxWidgets-Framework and now all my plugins run under wxMSW and wxMac but I still have problems under wxMSW to find a correct way to open and close the plugins and I am not sure if this is a wxMSW-only issue.
Problem
If I use any VST-host application I can open and close multiple instances of one of my VST-plugins without any problems. As soon as I open another of my VST-plugins besides my first VST-plugin and then close all instances of my first VST-plugin the application crashes after a short amount of time within the wxEventHandlerr::ProcessEvent function telling me that the wxTheApp object isn't valid any longer during execution of wxTheApp->FilterEvent (see below). So it seems to be that the wxTheApp objects was deleted after closing all instances of the first plugin and is no longer available for the second plugin.
bool wxEvtHandler::ProcessEvent(wxEvent& event)
{
// allow the application to hook into event processing
if ( wxTheApp )
{
int rc = wxTheApp->FilterEvent(event);
if ( rc != -1 )
{
wxASSERT_MSG( rc == 1 || rc == 0,
_T("unexpected wxApp::FilterEvent return value") );
return rc != 0;
}
//else: proceed normally
}
....
}
Preconditions
1.) All my VST-plugins a dynamically linked against the C-Runtime and wxWidgets libraries. With regard to the wxWidgets
forum this seemed to be the best way to run multiple instances of the software side by side.
2.) The DllMain of each VST-Plugin is defined as follows:
// WXW
#include "wx/app.h"
#include "wx/defs.h"
#include "wx/gdicmn.h"
#include "wx/image.h"
#ifdef __WXMSW__
#include <windows.h>
#include "wx/msw/winundef.h"
BOOL APIENTRY DllMain
( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
wxInitialize();
::wxInitAllImageHandlers();
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
wxUninitialize();
break;
}
return TRUE;
}
#endif // __WXMSW__
class Application : public wxApp {};
IMPLEMENT_APP_NO_MAIN(Application)
Question
How can I prevent this behavior respectively how can I properly handle the wxTheApp object if I have multiple instances
of different VST-plugins (DLL-modules), which are dynamically linked against the C-Runtime and wxWidgets libraries?
Best reagards, Steffen
We had similar issues using a LSP created with wxWidgets when an wxWidgets application loaded our DLL. Check for NULL == wxTheApp before calling ::wxInitialize().
Pseudo code:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason) {
case DLL_PROCESS_ATTACH :
if(NULL == wxTheApp) {
::wxInitialize();
}
break;
}
}
Also, I suggest doing as little possible in your DllMain() as possible, e.g. move wxInitAllImageHandlers() elsewhere if possible. Additionally, you may wish to track if you called ::wxInitialize() to pair up with ::wxUninitialize()
I encountered a similar issue but with Acrobat plugins.
While adjusting our Acrobat plugins to Acrobat X (10) we had to remove code related to ADM (Acrobat Dialog Manager - Used to be a cross-platform GUI framework on Acrobat 7, 8 & 9. Removed with Acrobat X) and use a different GUI framework.
Acrobat SDK comes with samples of using wxWidgets as a cross-platform framework so we headed that way (we support MAC & Windows).
The plugin architecture of Acrobat is very similar to the one you described above: dlls (for Acrobat plugins the binary file extension is *.api) which are dynamically loaded by a main process (exe) and their functions are being called in a documented, pre-defined order.
Because the Acrobat wxWidgets example was written with 2.8.12 and due to the fact that this is the stable version we decided to NOT use the 2.9.x ongoing version.
So we statically linked our plugins (total of 3 different plugins) to the wx2.8.12 libs and found out that if 3 of them are installed, the two that were loaded last were not functioning. By that I mean - Our custom wxFrames, wxWindows & wxDialogs belonging to these two plugins were all messed up (like someone tried to erase them, with rubber :-)).
Digging deeply we narrowed it down to the fact that the first plugin being loaded, initializes wxWidgets and the latter do not, even though the explicit call to wxInitialize(). Something there went wrong....
Here I forgot to mention - In an Acrobat plugin you cannot change the DllMain() function, so the initialization of wx is done in a "Plugin Init() function".
Just to be clear - The wx libs are statically linked to the *.api files, so each should have a "copy" of its own and not influence on each other.
Using Google for 2-3 FULL days I managed to find this post
,which suggested to apply this patch (for 2.8x ONLY!!!). I believe (or hope) that the 2.9.x version does not suffer from this issue (didn't have the chance to check it).
BTW - The patch is only one file which is very clear, so reading the code to understand it and to be calm that it does no harm is pretty easy.
I hope others using wx 2.8.x and suffering from the same issue will find this.
Omri

Resources