From: win32 on 29 Jun 2010 17:21 Hi. I am facing strange problem with object Event while global hook WH_CBT is installed and when an USB flash drive is inserted. The bug reveals itself only when compiling in VS6+SP6 and does not appear in VS 2008. Alas, I need this project compiled only in VS6. Here is the code: #pragma data_seg(".shared") HHOOK g_hook=NULL; #pragma data_seg() #pragma comment(linker, "/SECTION:.shared,RWS") HINSTANCE g_hInstance; LRESULT CALLBACK HookFunc(int nCode, WPARAM wParam,LPARAM lParam){ return CallNextHookEx(g_hook, nCode, wParam, lParam); } extern "C" __declspec(dllexport) void InitHook(){ g_hook=SetWindowsHookEx(WH_CBT,HookFunc,g_hInstance,0); MSG msg; int ret; // setting message loop while((ret=GetMessage(&msg,0,0,0))!=0){ if(ret==-1){ } else { DispatchMessage(&msg); } } } unsigned WINAPI MyThread(void *p){ HANDLE hEvent=CreateEvent(NULL,false,false,"myevent"); DWORD dwErr=GetLastError(); if(dwErr==ERROR_ALREADY_EXISTS){ // if this code deleted SetEvent(hEvent); // the bug Sleep(3000); // does not appear } WaitForSingleObject(hEvent,INFINITE); // waiting infinite CloseHandle(hEvent); ExitProcess(0); // exiting process return 0; } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if(ul_reason_for_call==DLL_PROCESS_ATTACH){ g_hInstance=(HINSTANCE)hModule; char szFileName[MAX_PATH]; GetModuleFileName(NULL,szFileName,MAX_PATH); strlwr(szFileName); BOOL bOk=false; if(strstr(szFileName,"notepad")!=NULL || strstr(szFileName,"rundll32")!=NULL) bOk=true; if(bOk){ UINT uid; HANDLE hTh=(HANDLE)_beginthreadex(NULL,0,MyThread,NULL,0,&uid); CloseHandle(hTh); } return bOk; } else if(ul_reason_for_call==DLL_PROCESS_DETACH){ UnhookWindowsHookEx(g_hook); } return TRUE; } In short my app is: - a dll that is spawned by rundll32.exe and installs WH_CBT hook - in order that rundll32 process will not finish we set message loop(GetMessage\DispathMessage) - for DllMain we create thread in which some event is created and then we put infinite wait on it - when notepad is executed our dll is injected into it Take a look on this part of our thread's code: DWORD dwErr=GetLastError(); if(dwErr==ERROR_ALREADY_EXISTS){ SetEvent(hEvent); Sleep(3000); } It is not important what sense does this code make. It is more important that when the only one instance of rundll32 process is launched (the event named 'myevent' is not opened or created anywhere) the function GetLastError cannot return ERROR_ALREADY_EXISTS (a priori no event with such name!), that is why two calls - SetEvent and Sleep are never executed. And it is true, these two calls do not take place and execution goes to WaitForSingleObject. Here we have infinite wait. And now! As soon as we insert our flash drive into USB port by some fantastic way the event hEvent is signalled and the call WaitForSingleObject is finished with WAIT_OBJECT_0 code. In essence, the code mentioned above makes the following sense: if another one instance of rundll32 is launched and our dll is injected in it then we have to terminate the preceding instance. And in preceding instance there is a wait on hEvent. This event gets signalled if GetLastError returns ERROR_ALREADY_EXISTS in new process. Then we will have an infinite wait in new process until another one instance of rundll32 with our dll injected is launched. And so on. The most interesting thing is that there is no bug with flash drive when the code is compiled in VS2008. Try to compile in VC6 (I have SP6 installed) and run the dll from the command prompt: rundll32.exe c: \project\some\debug\prg.dll,InitHook. And then insert an USB flash drive. And you will see that our rundll32.exe process will terminate. If I change the message loop while((ret=GetMessage(&msg,0,0,0))!=0){ if(ret==-1){ } else { DispatchMessage(&msg); } } to Sleep(INFINITE); the situatuon will not change - after the flash drive insertion the event is signalled and that's it. And now focus. Delete the code: DWORD dwErr=GetLastError(); if(dwErr==ERROR_ALREADY_EXISTS){ SetEvent(hEvent); Sleep(3000); } And the bug disappears! What we have? Some fantom code executes the part of code post factum (or spawns the thread once again) and since the event named 'myevent' already exists GetLastError returns ERROR_ALREADY_EXISTS and the call to SetEvent(hEvent) is executed. By the way if we delete SetEvent(hEvent) then bug disappears too. Also there is no bug detected if I remove the hook logic (if I do not call SetWindowsHookEx). But why VS2008 is not exposed to the bug? My OS is Windows XP SP3. Thanks in advanced for the answers.
From: David Schwartz on 29 Jun 2010 18:58 I would bet you $100 to your $5 that the reason the event is being signaled is because your code to signal it is running. That's why it doesn't get signaled if you remove that code. DS
From: win32 on 30 Jun 2010 05:48 On 30 иÑн, 01:58, David Schwartz <dav...(a)webmaster.com> wrote: > I would bet you $100 to your $5 that the reason the event is being > signaled is because your code to signal it is running. That's why it > doesn't get signaled if you remove that code. > > DS I have been investigating and you're true - simply after the flash drive is inserted a new process rundll32 is initiated to show the dialog box(so that a user may choose what to do with flash!). But I could not guess the reason just because I have disabled the dialog box. Anyway the rundll32 process is launched and quickly terminated, and of course DllMain is executed (dll is loaded into another rundll32...) and the thread is spawned so that the event is signalled! Thanx to all for attention!
From: Ulrich Eckhardt on 30 Jun 2010 08:45 win32 wrote: > Anyway the rundll32 process is launched and quickly terminated, and of > course DllMain is executed (dll is loaded into another rundll32...) > and the thread is spawned so that the event is signalled! Just wondering, but isn't it Evil Foobar(tm) to spawn a thread in DllMain()? Or am I missing an exception to that rule here? Uli -- Sator Laser GmbH Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
|
Pages: 1 Prev: Detect if a window is fully exposed. Next: the general serve is not sufficient |