C++ Windows: Access same variable from main process and CallWndProc process - c++

I have a single-file DLL that receives and stores a _bstr_t as a global variable, then sets a Windows hook for the WH_CALLWNDPROC procedure.
In the CallWndProc function, I attempt to read the _bstr_t, but it has no value.
I printed out the variable's address from both functions and they are different.
This is not surprising as I think that the CallWndProc function is called in a different process' thread.
My question is, what is the easiest and best way to share the variable between them?
I am trying to avoid having to use ATL COM to store it for inter-process access.
Example code:
// foo.cpp
#include <comutil.h>
static HHOOK g_hook = NULL;
static _bstr_t shared = "";
static LRESULT WINAPI CallWndProc(int nHookCode, WPARAM wParam, LPARAM lParam) {
if (nHookCode == 12345) {
// Do something with '_bstr_t shared'
shared += " bar";
return 0;
}
return CallNextHookEx(g_hook, nHookCode, wParam, lParam);
}
extern "C" __declspec(dllexport) void _stdcall Do(char* someStr, long handle) {
shared = someStr;
DWORD threadId = GetWindowThreadProcessId((HWND) handle, &process);
HINSTANCE hInst = GetModuleHandle("foo.dll");
g_hook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, hInst, thread);
// Check value of '_bstr_t shared', or call a COM function to store it somewhere.
// However, the value of 'shared' does not include the string appended in CallWndProc.
}
Extra info:
DLL is called by Java using JNI.
DLL is built as a multi-threaded DLL.

I went with the ATL COM approach to act as a global store of values.
Not my ideal solution, but a workable one.
However, I think Hans Passant's comment on the question is a better way of doing it since it does not require a separate process to be running.

Related

Is it safe to call std::thread::join function under Win32 DLL_PROCESS_DETACH? [duplicate]

I've stumbled upon an unexpected behavior of Windows thread mechanism when DLL is unloaded. A have a pack of worker thread objects and I'm trying to finish them graciously when DLL is unloaded (via DllMain DLL_PROCESS_DETACH). The code is very simple (I do send an event to finish the thread's wait loop):
WaitForSingleObject( ThrHandle, INFINITE );
CloseHandle( ThrHandle );
Yet the WaitForSingleObject hangs the whole thing. It works fine if I perform it before DLL is unloaded. How this behavior can be fixed?
You can't wait for a thread to exit in DllMain(). Unless the thread had already exited by the time the DLL_PROCESS_DETACH was received, doing so will always deadlock. This is the expected behaviour.
The reason for this is that calls to DllMain() are serialized, via the loader lock. When ExitThread() is called, it claims the loader lock so that it can call DllMain() with DLL_THREAD_DETACH. Until that call has finished, the thread is still running.
So DllMain is waiting for the thread to exit, and the thread is waiting for DllMain to exit, a classic deadlock situation.
See also Dynamic-Link Library Best Practices on MSDN.
The solution is to add a new function to your DLL for the application to call before unloading the DLL. As you have noted, your code already works perfectly well when called explicitly.
In the case where backwards compatibility requirements make adding such a function impossible, and if you must have the worker threads, consider splitting your DLL into two parts, one of which is dynamically loaded by the other. The dynamically loaded part would contain (at a minimum) all of the code needed by the worker threads.
When the DLL that was loaded by the application itself receives DLL_PROCESS_DETACH, you just set the event to signal the threads to exit and then return immediately. One of the threads would have to be designated to wait for all the others and then free the second DLL, which you can do safely using FreeLibraryAndExitThread().
(Depending on the circumstances, and in particular if worker threads are exiting and/or new ones being created as part of regular operations, you may need to be very careful to avoid race conditions and/or deadlocks; this would likely be simpler if you used a thread pool and callbacks rather than creating worker threads manually.)
In the special case where the threads do not need to use any but the very simplest Windows APIs, it might be possible to use a thread pool and work callbacks to avoid the need for a second DLL. Once the callbacks have exited, which you can check using WaitForThreadpoolWorkCallbacks(), it is safe for the library to be unloaded - you do not need to wait for the threads themselves to exit.
The catch here is that the callbacks must avoid any Windows APIs that might take the loader lock. It is not documented which API calls are safe in this respect, and it varies between different versions of Windows. If you are calling anything more complicated than SetEvent or WriteFile, say, or if you are using a library rather than native Windows API functions, you must not use this approach.
I have such problem when I try to inject code into another desktop process, WaitForSingleObject will cause the deadlock inside my thread. I solved the issue by trapping the window's default message procedure, hope it helps for others.
#define WM_INSIDER (WM_USER + 2021)
WNDPROC prev_proc = nullptr;
HWND FindTopWindow(DWORD pid)
{
struct Find { HWND win; DWORD pid; } find = { nullptr, pid };
EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
auto p = (Find*)(lParam);
DWORD id;
if (GetWindowThreadProcessId(hwnd, &id) && id == p->pid) {
// done
p->win = hwnd;
return FALSE;
}
// continue
return TRUE;
}, (LPARAM)&find);
return find.win;
}
// thread entry
int insider(void *)
{
// do whatever you want as a normal thread
return (0);
}
LRESULT CALLBACK insider_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HANDLE t;
switch (uMsg) {
case WM_INSIDER:
t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)insider, 0, 0, NULL);
CloseHandle(t);
break;
}
return CallWindowProc(prev_proc, hwnd, uMsg, wParam, lParam);
}
void setup() {
auto pid = GetCurrentProcessId();
auto win = FindTopWindow(pid);
prev_proc = (WNDPROC)SetWindowLongPtr(win, GWL_WNDPROC, (LONG_PTR)&insider_proc);
// signal to create thread later
PostMessage(win, WM_INSIDER, 0, 0);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
setup();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

global variable in dll inconsistent?

I am creating a (temporary) log file from a dll. But the global variable I defined seem to be inconsistent.
Here is how I define variables in dll's main cpp file.
char * g_bfr;
__declspec(dllexport) CMemFile memFile;
Then in DllMain function:
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("UTLADO.DLL Initializing!\n");
g_bfr = new char[1000]();
memFile.Attach((BYTE*)g_bfr, 1000 );
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(AcnDll, hInstance))
return 0;
new CDynLinkLibrary(AcnDll);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("UTLADO.DLL Terminating!\n");
delete[] g_bfr;
// Terminate the library before destructors are called
AfxTermExtensionModule(AcnDll);
}
return 1; // ok
}
The problem is when I use the memFile in the dll to write log to memory, somewhere down the road, it becomes bad as if newly declared (uninitialized). See the where file positions/size are all reset.
What makes thing weirder is when I set breakpoint in DllMain, inside case DLL_PROCESS_ATTACH, it never breaks there (like never called) but the initialization does work! Breakpoint in case DLL_PROCESS_DETACH does work and is called only when I close application.
So, in a nutshell, it appears that memFile gets created another time during course of the application but should it? How can I make sure I only have one instance of the global variable in the dll?
After you have finished using the DLL, try using the FreeLibrary function.
However, this method has not been considered for concurrent use.
enter link description here

Easyhook: unmanaged hooking, how to call original function / change return status?

So I have a hook function at winspool.drv!WritePrinter, which is successfully hooked with unmanaged C++ remotely injected to spoolsv.exe.
Currently, the hook seems to either replace original function, or corrupt the stack in an undetectable way: after hooking, WritePrinter calls result in no printer activity outside the hook.
I've figured out there's at least one way to call original function, so-called LhGetOldProc. However, using it leads to crashes, don't sure if this is easyhook-related error or it's just bad casting.
So, how do I properly call original function in Easyhook unmanaged version?
Hook callback with LhGetOldProc:
UCHAR *uc = NULL;
LhGetOldProc(hhW, &uc);
typedef BOOL (*wp)(_In_ HANDLE, _In_ LPVOID, _In_ DWORD cbBuf, _Out_ LPDWORD);
wp my_wp = reinterpret_cast<wp>(reinterpret_cast<long>(uc)); // http://stackoverflow.com/questions/1096341/function-pointers-casting-in-c
BOOL res ;
if (my_wp == 0x0) {
return -1;
} else {
res = my_wp(hPrinter, pBuf, cbBuf, pcWritten); // crash
}
Hook code:
HMODULE hSpoolsv = LoadLibraryA("winspool.drv");
TRACED_HOOK_HANDLE hHook = new HOOK_TRACE_INFO();
NTSTATUS NtStatus;
UNICODE_STRING* NameBuffer = NULL;
HANDLE hRemoteThread;
FORCE(LhInstallHook(GetProcAddress(hSpoolsv, "WritePrinter"), WritePrinterHookA, 0x0, hHook));
ULONG ACLEntries[1] = { (ULONG) - 1 };
FORCE(LhSetExclusiveACL(ACLEntries, 1, hHook));
hhW = hHook;
TIL: in 2013, CodePlex (where EasyHook discussion list is) doesn't accept third level domains for e-mail when registering with Microsoft account. Not going to use Firebug to bypass the form.
The stack gets corrupted because your function pointer has the wrong calling convention.
The default calling convention is __cdecl which expects the caller to clean the stack.
typedef BOOL (* wp)(_In_ HANDLE ....);
equals:
typedef BOOL (__cdecl* wp)(_In_ HANDLE ...);
but the winapi functions use __stdcall calling convention which expects the callee to clean the stack.
you will have to typedef a __stdcall function:
typedef BOOL (__stdcall* wp)(_In_ HANDLE ....);

MFC extension dll resources loading problems

I have built the folowing configuration:
A) MFC Extension DLL having 2 MFC dialogs.
B) MFC regular dll that uses DLL A functions.
C) win32 application (NON MFC) calling for function from DLL B
When calling functions from DLL B that inside call functions from DLL A to display a dialog an error occurs due to the fact that resource can not be found.
I have digged to find the exact root cause and themain reson seems to be the fact that the module context is set to the calling dll B rather than to the DLL A, which contains the dialog resource.
Inside DllMain the initialization is done as described in the MSDN:
static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
Hinstance = hInstance; //save instance for later reuse
// Extension DLL one-time initialization
if (AfxInitExtensionModule(extensionDLL,hInstance) == 0)
{
AfxMessageBox("Error on init AfxInitExtensionModule!");
return 0;
}
// Insert this DLL into the resource chain
new CDynLinkLibrary(extensionDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
Release();
}
return 1;
}
One workarround that i've found was to store the hInstance parameter received from DLLMain: extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
and inside DLL A when functions are called, I save current handle and set new handle the handle received from DllMain:
DLL A function1(............)
{
HINSTANCE HinstanceOld = AfxGetResourceHandle();
AfxSetResourceHandle(CErrohInstance);
.......
//display dialog
.....
AfxSetResourceHandle(HinstanceOld);
}
By using this workarround It still causses assertion but the dialogs are shown.
What should be the normal way of solving this problem?
You have to insert the resources of the extension DLL into the resource chain of the regular DLL, not the EXE. Just create a function in the extension DLL and call it in the InitInstance method of the regular DLL, like this:
void initDLL()
{
new CDynLinkLibrary(extensionDLL);
}
You say "module context" but in fact the terminus technicus is "module state".
AFAICS this is the relatively standard (i.e., most frequently occurring) MFC module state related use case here, namely: entering via callbacks / public exported APIs into internal implementation area.
AFX_MANAGE_STATE directly mentions this use case: "If you have an exported function in a DLL"
At this point, the module state that is currently active is the one of the calling party, which is not the one which is needed within implementation scope.
Since implementation scope knows that it needs a different module state (and it is the one to know which is the correct one!), it needs to temporarily switch to the correct one, to achieve having any module state related lookup (precisely: resource instance lookup) done within the correct instance scope.
And this needs to be done not manually via AfxSetModuleState(), but rather via the properly lifetime-scoped (guarantees proper destruction, at whichever cancellation points may exist, be it return or exception or whatever) mechanism of AFX_MANAGE_STATE macro.
IOW, implementation likely needs to strongly resemble something like:
BOOL MyPublicAPIOrCallback()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // ensure locally expected module state within this externally-invoked handling scope
some_handling_which_does_resource_lookup_or_whatever;
}
Dont know if you have already found the solution, if not You can try using
AfxFindResourceHandle
before accessing the problematic resource in Dll A.
I have add this lines in my DLLMain and now I don't have problems to use resources that are in other DLL's called by my DLL, like dialogs.
This is the Code:
static AFX_EXTENSION_MODULE CODIAbantailDLLDLL = { NULL, NULL };
AplicacionBase theApp;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Quitar lo siguiente si se utiliza lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// ******** VERY IMPORTANT ***********************
// IF you doesn't put this, when you call other DLL that has
// its owns resources (dialogs for instance), it crash
CoInitialize(NULL);
AfxWinInit(hInstance, NULL, ::GetCommandLine(), 0);
AfxEnableControlContainer();
//**************************************************
TRACE0("Inicializando CODIAbantailDLL.DLL\n");
// Inicialización única del archivo DLL de extensión
if (!AfxInitExtensionModule(CODIAbantailDLLDLL, hInstance))
return 0;
new CDynLinkLibrary(CODIAbantailDLLDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("Finalizando CODIAbantailDLL.DLL\n");
// Finalizar la biblioteca antes de llamar a los destructores
AfxTermExtensionModule(CODIAbantailDLLDLL);
}
return 1; // aceptar
}

Variable keeps getting set to NULL after function in DLL

I need valid data to be in the global variable QObject *p. However, assigning anything to this variable inside of a function works within the scope of the function, but after the function returns, p is set back to NULL, even though p is global. Here is my code:
#include ... // various includes
// p is NULL
QObject *p;
HHOOK hhk;
BOOL WINAPI DllMain(__in HINSTANCE hinstDLL, __in DWORD fdwReason, __in LPVOID lpvReserved)
{
return TRUE;
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MOUSEHOOKSTRUCT *mouseInfo = (MOUSEHOOKSTRUCT*)lParam;
QMouseEvent::Type type;
QPoint pos = QPoint(mouseInfo->pt.x, mouseInfo->pt.y);
Qt::MouseButton bu;
Qt::MouseButtons bus;
Qt::KeyboardModifiers md = Qt::NoModifier;
... // very large switch statement
// here is where i need some valid data in p
QCoreApplication::postEvent(p, new QMouseEvent(type, pos, bu, bus, md));
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// note: MOUSEHOOKSHARED_EXPORT is the same as __declspec(dllexport)
// this function is called by the application that loads the dll
extern "C" MOUSEHOOKSHARED_EXPORT void install(QObject *mParent, DWORD threadID, HINSTANCE hInst)
{
p = mParent; // p is assigned here and keeps the value of mParent untill the function returns
hhk = SetWindowsHookEx(WH_MOUSE, MouseProc, hInst, threadID);
} // after this function returns, p is NULL
extern "C" MOUSEHOOKSHARED_EXPORT void uninstall()
{
UnhookWindowsHookEx(hhk);
}
I have tried various data structure "workarounds" such as using struct typedef etc... i can't seem to get this to work. All i need is for p to retain the value of mParent.
EDIT:
Here is where i execute install()
// EarthWidget is a class that is derived from QWidget(which is derived from QObject)
void EarthWidget::LoadAll()
{
HINSTANCE DLLinst = LoadLibrary("MouseHook.dll");
... // get functions in DLL using GetProcAddress & typedefs, etc...
// i pass in 'this' as mParent
install(this, GetWindowThreadProcessId((HWND)earthplugin->GetRenderHwnd(), NULL), DLLinst);
// note that GetWindowThreadProcessId does work and does return a valid thread id, so no problem there
}
EDIT:
Found out what was wrong. The this pointer becomes out of scope when install is executed, therefore mParent, being a QObject, initializes itself to NULL. Thus p becomes NULL. this comes back into scope when install returns, however, at a completely different memory address. The solution, after extensive debugging and headaches, would be to create a class member function that takes a QObject as a parameter and passes that into install instead of this. Whatever you pass into that function must last as long as you need the DLL to last. That, or, you can create your own copy constructor that performs a deep copy.
Are you exporting the global in the DLL and then importing it in the program? If you are not, or not doing it correctly, you probably have two p objects: one in the DLL and one in the program. You can confirm this by checking the address of p.
Rather than a global variable consider using an exported function in the DLL that returns the needed reference/pointer. At the very least name it something more descriptive (unless it was just renamed for the purpose of asking this question).
Is your call to install actually happening in the dll address space (in the debugger, step into the call and check the addresses in the callstack)? Is install defined in a header file or is that extract from a source file? If in a header, it's been inlined into your exe so the dll version of p is never set. This would happen without any linker warning since there are two independent binaries using the same source.
Is MOUSEHOOKSHARED_EXPORT defined in your app? Probably needs to be MOUSEHOOKSHARED_IMPORT for the app (but not the dll).
You're creating a shallow copy of that parameter mParent. At some point, that pointer must be getting set to null (or you're passing it as null), which will result in p also becoming null.