Why is Minidump file contents wrong for only 1 process? - winapi

Situation:
We have an MFC/C++ Visual Studio (2005) application consisting of a lot of executables and a lot of dlls, all using MFC and interconnected with DCOM. Some are running on a controller (w2012) which controls slave computers running on WES2009.
The problem:
For diagnostic purposes we are embedding minidumps in all of our processes. This mechanism works fine in all processes except for one: the GUI exe. All processes including the GUI make dmp files BUT the dmp file contents of the GUI seems to be different/wrong. When I intentionally crash our application with e.g. a null pointer dereference, all dmp files of all processes/dlls (except GUI) point to the cause (the null pointer dereference)! The dmp file of the GUI process is created and can be openend in Visual Studio but non of the threads point to the cause (the null pointer dereference). Also windbg does not find the cause! The strange thing is that when we manually use WriteStackDetails() to dump the callstack it returns the correct problematic line! So why can't MinidumpWriteDump() do the same for only this one process? What could be the discriminating factor? Anyone any idea?
What we tried:
We tried crashes in all other process and dlls and they all seem to work ok except the GUI process! Unicode / non-Unicode does not seem to matter. A seperate test application works well, also when I link our production code library which contains the UnhandledExceptionFilter() and MinidumpWriteDump(). Crashes in sub(-sub) dlls does not seem to matter. The project settings wrt exception handling appear to be all the same. Anyone any idea?
Some more info and remarks:
Our production code (controller and slaves) is running in separate virtual boxes for development purposes.
yes we understand that the minidump should ideally be created from another process (some example somewhere? wrt process querying and security?) but doing it in-process seems to work 'always ok' for now. So we accept the risk for now that it might hang in rare situations.
What I mean with the dmp file contents is different/wrong is the following:
For our non-GUI exe we get the following OK thread / callstack information:
0xC0000005: Access violation reading location 0x00000000.
Studio automatically opens the correct source and the "breakpoint" is set to the faulty line of code.
In the Call stack tab I see my own functions in my own dll which has caused the crash: my null pointer dereference.
In the Threads tab I also see my active thread and Location which points also to the faulty function which crashed.
So all is fine and usable in this situation! Super handy functionality!
For our GUI exe, which links to the same production library code wrt MinidumpWriteDump() and ExceptionHandlingFiler() code, we get the following NOK thread / callstack information:
Unhandled exception at 0x77d66e29 (ntdll.dll) in our_exe_pid_2816_tid_2820_crash.dmp: 0xC0150010: The activation context being deactivated is not active for the current thread of execution
Visual Studio 2005 does not show my faulty code as being the cause!
In the Call stack tab I don't see my own faulty function.
The Call stack tab shows that the problem is in ntdll.dll!RtlDeactivateActivationContextUnsafeFast()
The top most function call which is shown of our code is in a totally different gui helper dll, which is not related to my intentionally introduced crash!
The Threads tab also shows the same.
For both situations I use the same visual studio 2005 (running on w7) with the same settings for symbol paths!!! Also visual studio 2017 cannot analyze the 'wrong' dmp files. In between of both test above, there is no rebuild so no mismatch occurs between exe/dlls and pdbs. In one situation it works fine and in another not!?!
The stripped-down-to-essentials code we use is shown below
typedef BOOL (_stdcall *tMiniDumpWriteDump)(HANDLE hProcess, DWORD dwPid, HANDLE hFile,
MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
TCHAR CCrashReporter::s_szLogFileNameDmp[MAX_PATH];
CRITICAL_SECTION CCrashReporter::s_csGuard;
LPTOP_LEVEL_EXCEPTION_FILTER CCrashReporter::s_previousFilter = 0;
HMODULE CCrashReporter::s_hDbgHelp = 0;
tMiniDumpWriteDump CCrashReporter::s_fpMiniDumpWriteDump = 0;
CCrashReporter::CCrashReporter()
{
LoadDBGHELP();
s_previousFilter = ::SetUnhandledExceptionFilter(UnhandledExceptionFilter);
::InitializeCriticalSection(&s_csGuard);
}
CCrashReporter::~CCrashReporter()
{
::SetUnhandledExceptionFilter(s_previousFilter);
...
if (0 != s_hDbgHelp)
{
FreeLibrary(s_hDbgHelp);
}
::DeleteCriticalSection(&s_csGuard);
}
LONG WINAPI CCrashReporter::UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
::EnterCriticalSection(&s_csGuard);
...
GenerateMinidump(pExceptionInfo, s_szLogFileNameDmp);
::LeaveCriticalSection(&s_csGuard);
return EXCEPTION_EXECUTE_HANDLER;
}
void CCrashReporter::LoadDBGHELP()
{
/* ... search for dbghelp.dll code ... */
s_hDbgHelp = ::LoadLibrary(strDBGHELP_FILENAME);
if (0 == s_hDbgHelp)
{
/* ... report error ... */
}
if (0 != s_hDbgHelp)
{
...
s_fpMiniDumpWriteDump = (tMiniDumpWriteDump)GetProcAddress(s_hDbgHelp, "MiniDumpWriteDump");
if (!s_fpMiniDumpWriteDump)
{
FreeLibrary(s_hDbgHelp);
}
else
{
/* ... log ok ... */
}
}
}
void CCrashReporter::GenerateMinidump(const PEXCEPTION_POINTERS pExceptionInfo,
LPCTSTR pszLogFileNameDmp)
{
HANDLE hReportFileDmp(::CreateFile(pszLogFileNameDmp, GENERIC_WRITE, 0, 0,
CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0));
if (INVALID_HANDLE_VALUE != hReportFileDmp)
{
MINIDUMP_EXCEPTION_INFORMATION stMDEI;
stMDEI.ThreadId = ::GetCurrentThreadId();
stMDEI.ExceptionPointers = pExceptionInfo;
stMDEI.ClientPointers = TRUE;
if(!s_fpMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
hReportFileDmp, MiniDumpWithIndirectlyReferencedMemory,
&stMDEI, 0, 0))
{
/* ... report error ...*/
}
else
{
/* ... report ok ... */
}
::CloseHandle(hReportFileDmp);
}
else
{
/* ... report error ...*/
}
}

Related

Debugging in Visual Studio 2013 is very slow because of FileNotFoundException

I develop in Visual Studio (with monogame for Windows Phone 8.1). When I launch my app with "Run without debug" it starts pretty fast, but in debug it launches very slow (about 5 minutes, not counting build time!). The problem I see (beyound slow loading external symbols) is that my app loads many graphics files, but before load a picture it searches its hd version, its hd and localized version, and only localized. Most files don't have hd versions, some of them localized, some are not. So in log I see many messages:
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll
A first chance exception of type 'System.IO.FileNotFoundException' occurred in MonoGame.Framework.DLL
Of course when starting w/o debugging all that debug stuff is not working and app launches fast.
The only way to check if file is in Content folder is trying to open it (TitleContainer.OpenStream) and catching an exception. So I can't avoid generating those exceptions. How can I speed-up debug launch disabling somehow this stupid slow FileNotFoundException handling?
In my case with annoying exception handling I solved problem by preloading filenames recursively and then searching in stringlist:
private static List<string> mContentFilenames = new List<string>();
private static void preloadContentFilenamesRecursive(StorageFolder sf)
{
var files = sf.GetFilesAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (files != null)
{
foreach (var f in files)
{
mContentFilenames.Add(f.Path.Replace('\\','/'));
}
}
var folders = sf.GetFoldersAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (folders != null)
{
foreach (var f in folders)
{
preloadContentFilenamesRecursive(f);
}
}
}
private static void preloadContentFilenames()
{
if (mContentFilenames.Count > 0)
return;
var installed_loc = Windows.ApplicationModel.Package.Current.InstalledLocation;
var content_folder = installed_loc.GetFolderAsync("Content").AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (content_folder != null)
preloadContentFilenamesRecursive(content_folder);
}
private static bool searchContentFilename(string name)
{
var v = from val in mContentFilenames where val.EndsWith(name.Replace('\\', '/')) select val;
return v.Any();
}
Update
But use this code only when debugger is attached. I underestimated microsoft workers - they are happy to turn your debugging to hell. Their lame error handling and lack of isFileExist function makes you to recursively check files to implement isFileExist without an exception yourself, but - surprize - if debugger is not attached, this code makes app silently exit whithout any exception. And before app crashes it check random number of files, so the problem is not in particular method - it just "can't check many files", how many - varies from time to time.
Taking into account that VS crashes in 50% of cases launching any (small or big) app on real WP8.1 device, and the fact that there is no access to device filesystem, imagine how it was difficult to find the root of crashes. I've spent almost a day for that!
Btw, after all those twenty years working with windows, windows store and windows phone apps I'd really like to meet someone from msft just to look in the eye. To see what is it - stupidity or sadism? Do they really hate us, developers? Why?

Trying to set ProcessStrictHandleCheckPolicy returns 87 - Incorrect Function

I am trying to use SetProcessMitigationPolicy on Windows 10 to enable the ProcessStrictHandleCheckPolicy:
The process will receive a fatal error if it manipulates a handle that is not valid.
As a general rule, strict handle checking cannot be turned off once it is turned on. Therefore, when calling the SetProcessMitigationPolicy function with this policy, the values of the RaiseExceptionOnInvalidHandleReference and HandleExceptionsPermanentlyEnabled substructure members must be the same. It is not possible to enable invalid handle exceptions only temporarily.
I can enable a number of the other mitigations:
ProcessDynamicCodePolicy: The dynamic code policy of the process. When turned on, the process cannot generate dynamic code or modify existing executable code.
ProcessExtensionPointDisablePolicy: Contains process mitigation policy settings for legacy extension point DLLs.
ProcessSignaturePolicy: The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).
ProcessFontDisablePolicy: The policy regarding font loading for the process. When turned on, the process cannot load non-system fonts.
ProcessImageLoadPolicy: The policy regarding image loading for the process, which determines the types of executable images that are allowed to be mapped into the process. When turned on, images cannot be loaded from some locations, such a remote devices or files that have the low mandatory label.
But ProcessStrictHandleCheckPolicy:
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy;
policy.RaiseExceptionOnInvalidHandleReference = 1;
policy.HandleExceptionsPermanentlyEnabled = 1;
BOOL res = SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, policy, sizeof(policy));
if (!res)
RaiseLastWin32Error();
fails with error code 87:
ERROR_INVALID_PARAMETER
The parameter is incorrect
What is wrong?
Bonus Chatter
The ProcessDynamicCodePolicy policy prevents an embedded web browser from running Javascript:
ProhibitDynamicCode: Set (0x1) to prevent the process from generating dynamic code or modifying existing executable code; otherwise leave unset (0x0).
AllowThreadOptOut: Set (0x1) to allow threads to opt out of the restrictions on dynamic code generation by calling the SetThreadInformation function with the ThreadInformation parameter set to ThreadDynamicCodePolicy; otherwise leave unset (0x0). You should not use the AllowThreadOptOut and ThreadDynamicCodePolicy settings together to provide strong security. These settings are only intended to enable applications to adapt their code more easily for full dynamic code restrictions.
More Bonuser
I'm actually in Delphi, so the syntax is different from the above C/C++/C# pseudo-code:
type
//ProcessStrictHandleCheckPolicy - The process will receive a fatal error if it manipulates an invalid handle. Useful for preventing downstream problems in a process due to handle misuse.
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY = record
Flags: DWORD;
//DWORD RaiseExceptionOnInvalidHandleReference : 1;
//DWORD HandleExceptionsPermanentlyEnabled : 1;
//DWORD ReservedFlags : 30;
end;
procedure SetMitigationPolicy;
var
policy: PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY;
res: BOOL;
begin
policy.Flags := $00000002;
res := SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, #policy, sizeof(policy));
if not res then
RaiseLastWin32Error;
end;
It doesn't change the question:
sometimes when i post Delphi code, and it's not strictly Delphi related, i get comments that i should have included the Delphi tag
sometimes when i post Delphi code, and it's not strictly Delphi related, i get comments that i should not have included the Delphi tag
rolls the dice
Don't include delphi delphi-xe6 tags.
Bonus Reading
How to electrify your own fence: ProcessStrictHandleCheckPolicy
From the PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY documentation:
As a general rule, strict handle checking cannot be turned off once it is turned on. Therefore, when calling the SetProcessMitigationPolicy function with this policy, the values of the RaiseExceptionOnInvalidHandleReference and HandleExceptionsPermanentlyEnabled substructure members must be the same. It is not possible to enable invalid handle exceptions only temporarily.
When you wrote:
policy.Flags := $00000002;
You only set the HandleExceptionsPermanentlyEnabled flag, but not the RaiseExceptionOnInvalidHandleReference flag. It should be this instead, which sets both flags:
policy.Flags := $00000003;
I'm fairly sure that you never actually ran your C++ code because it does not compile. If you fix the obvious compilation errors, then it will run successfully.
#define _WIN32_WINNT 0x0602
#include <Windows.h>
#include <Processthreadsapi.h>
#include <iostream>
int main()
{
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
policy.RaiseExceptionOnInvalidHandleReference = 1;
policy.HandleExceptionsPermanentlyEnabled = 1;
BOOL res = SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, &policy,
sizeof(policy));
DWORD err = 0;
if (!res)
err = GetLastError();
std::cout << res << ", " << err;
}
This program outputs 1, 0 as expected. If you add
policy.Flags = 0x00000002;
immediately before the call to SetProcessMitigationPolicy, then the output is 0, 87.

Native' has exited with code 1 (0x1)

hi i have been using Visula studio 2008 i was able to build the code and while debugging my project in release mode i am getting this error
how to get rid of this "Native' has exited with code 1 (0x1)" Error
lst_0704.exe': Loaded 'C:\lst\bin\lst_0704.exe', Symbols loaded.
lst_0704.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll'
lst_0704.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll'
lst_0704.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll'
The program '[6480] lst_0704.exe: Native' has exited with code 1 (0x1).
i have tried to change my project to debug mode as suggested in one of MSDN blogs but i am still getting this error
will there be any issue with command line arguments given in project properties?
This line does not necessarily indicate an error:
The program '[6480] lst_0704.exe: Native' has exited with code 1 (0x1).
It just means that your program's process (lst_0704.exe) has exited, presumably because you asked it to do so. The "native" part means that your application is compiled to native code, as opposed to managed code. And it's also telling you that the return code was 1.
Traditionally, when an application exits normally without any errors, it will return a code of 0. But that is not strictly required. There is really nothing in the operating system itself that checks these return codes—it is up to you to do so if you care.
I can't tell you exactly why your application is returning a code of 1 on exit, because you haven't posted any of your code. But my psychic powers tell me that there is probably a return 1; statement (or its functional equivalent) at the end of your main method. If you want the application to exit with a return code of 0, you'll need to change that to return 0;.
In Windows applications (as opposed to Console applications), the return code is typically the wParam of the WM_QUIT message that causes the application to terminate. In other words, the main message loop will look something like this:
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// An error occurred
}
else
{
// Process the message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// GetMessage returned WM_QUIT, so return the exit code.
return msg.wParam;
You cause the generation of the WM_QUIT message by calling the PostQuitMessage function, which takes a single parameter that specifies the exit code. That is the one that gets passed as the wParam and returned as the process's exit code. Again, it does not matter what code you return here, but it is traditionally 0 if the code is exiting normally with no errors.
This exact error, but with a different underlying cause, was preventing me from starting execution of a new project. There were no other errors, exceptions, or any other indications about what was wrong.
My cause turned out to be due to creating the project as a console application, then switching it to a Windows application. The startup code is different and incompatible between the two types of projects. Replacing Program.cs with its static Main() method and modifying its namespaces, etc., from another project created as a Windows application resolved my error.
I hope this helps someone else who is confused by this unhelpful error message.

OpenGL suppresses exceptions in MFC dialog-based application

I have an MFC-driven dialog-based application created with MSVS2005. Here is my problem step by step. I have button on my dialog and corresponding click-handler with code like this:
int* i = 0;
*i = 3;
I'm running debug version of program and when I click on the button, Visual Studio catches focus and alerts "Access violation writing location" exception, program cannot recover from the error and all I can do is to stop debugging. And this is the right behavior.
Now I add some OpenGL initialization code in the OnInitDialog() method:
HDC DC = GetDC(GetSafeHwnd());
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat = ChoosePixelFormat(DC, &pfd);
SetPixelFormat(DC, pixelformat, &pfd);
HGLRC hrc = wglCreateContext(DC);
ASSERT(hrc != NULL);
wglMakeCurrent(DC, hrc);
Of course this is not exactly what I do, it is the simplified version of my code. Well now the strange things begin to happen: all initialization is fine, there are no errors in OnInitDialog(), but when I click the button... no exception is thrown. Nothing happens. At all. If I set a break-point at the *i = 3; and press F11 on it, the handler-function halts immediately and focus is returned to the application, which continue to work well. I can click button again and the same thing will happen.
It seems like someone had handled occurred exception of access violation and silently returned execution into main application message-receiving cycle.
If I comment the line wglMakeCurrent(DC, hrc);, all works fine as before, exception is thrown and Visual Studio catches it and shows window with error message and program must be terminated afterwards.
I experience this problem under Windows 7 64-bit, NVIDIA GeForce 8800 with latest drivers (of 11.01.2010) available at website installed. My colleague has Windows Vista 32-bit and has no such problem - exception is thrown and application crashes in both cases.
Well, hope good guys will help me :)
PS The problem originally where posted under this topic.
Ok, I found out some more information about this. In my case it's windows 7 that installs KiUserCallbackExceptionHandler as exception handler, before calling my WndProc and giving me execution control. This is done by ntdll!KiUserCallbackDispatcher. I suspect that this is a security measure taken by Microsoft to prevent hacking into SEH.
The solution is to wrap your wndproc (or hookproc) with a try/except frame so you can catch the exception before Windows does.
Thanks to Skywing at http://www.nynaeve.net/
We've contacted nVidia about this
issue, but they say it's not their
bug, but rather the Microsoft's. Could
you please tell how you located the
exception handler? And do you have
some additional information, e.g. some
feedbacks from Microsoft?
I used the "!exchain"-command in WinDbg to get this information.
Rather than wrapping the WndProc or hooking all WndProcs, you could use Vectored Exception Handling:
http://msdn.microsoft.com/en-us/library/ms679274.aspx
First, both behaviors are correct. Dereferencing a null pointer is "undefined behavior", not a guaranteed access violation.
First, find out whether this is related to exception throwing or only to accessing memory location zero (try a different exception).
If you configure Visual Studio to stop on first-chance access violations, does it break?
Call VirtualQuery(NULL, ...) before and after glMakeCurrent and compare. Maybe the nVidia OpenGL drivers VirtualAlloc page zero (a bad idea, but not impossible or illegal).
I found this question when I was looking at a similar problem. Our problem turned out to be silent consumption of exceptions when running a 32-bit application on 64-bit Windows.
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
There’s a fix available from Microsoft, though deploying it is somewhat challenging if you have multiple target platforms:
http://support.microsoft.com/kb/976038
Here's an article on the subject describing the behavior:
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
This thread on stack overflow also describes the problem I was experiencing:
Exceptions silently caught by Windows, how to handle manually?

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