I have a small code which parse a event viewer of the system to find required data. Now this code works fine when .exe is created but not in .dll.
How do i listen to an event which i have subscribed for inside a dll.
Are there any better way to implement EvtSubscribe() and SubscriptionCallback() in .dll ?
Full Source Code on Github
Is this behaviour because i have skipped DllMain() function?
main()
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hSubscription = NULL;
hSubscription = EvtSubscribe(NULL, NULL, pwsPath, pwsQuery, NULL, NULL,
(EVT_SUBSCRIBE_CALLBACK)SubscriptionCallback, EvtSubscribeStartAtOldestRecord);
if (NULL == hSubscription)
{
//some code
return;
}
Callback
gets called when .exe is build but not in .dll
// The callback that receives the events that match the query criteria.
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
switch (action)
{
//some code
case EvtSubscribeActionDeliver:
if (ERROR_SUCCESS != (status = PrintEvent(hEvent)))
{
goto cleanup;
}
break;
}
cleanup:
return status; // The service ignores the returned status.
}
DWORD PrintEvent(EVT_HANDLE hEvent)
{
// print
}
I think you need to double check the call EvtClose. If you call this, the subscription callback will not be called.
There is nothing to do with DllMain.
Related
Background:
Application Type: Win32 Application
Language: C++ (with C functions as well)
Problem: Want to use main Window Handle in another file.
Update 1: Using a TCP server in another thread. This server receives information from a client and then needs to start a timer in the program.
Project Layout:
Main File: main.cpp/main.h which has WinMain, WndProc, etc.
Other Generated Files: Resource.h, main.rc, stdafx.h etc generated by Visual Studio
Self Made Files: functions.cpp/functions.h & calculation.cpp/calculation.h
Update 1: Server thread is in the main.cpp file and the call to start the timer is made on the server thread. I also updated some of the code to more accurately reflect what I have.
Info:
Can I call SetTimer(hwnd, TIMER_INT, TIMER_INTERVAL, NULL) in the calculation.cpp file in some way and make the TIMER_INT timer trigger in the WndProc for WM_TIMER?
So for example (of course foo is defined in calculation.h, etc. for other functions).
//calculation.cpp
void foo(HWND hwnd)
{
SetTimer(hwnd, TIMER_INT, TIMER_INTERVAL, NULL);
}
//functions.cpp
void ThreadStart()
{
/* This code initializes a working server that is visible to main.cpp */
/* The Server socket and Accept socket are extern for main.cpp */
}
//main.cpp
HWND hwnd;
int WinMain(...)
{
//... Set hwnd here
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, ...)
{
static PARAMS params; //Thread params
switch(message)
{
case WM_CREATE:
//This initializes a blocking Server (which works)
params.hwnd = hWnd;
params.bContinue = TRUE;
_beginthread(ThreadServer, 0, ¶ms);
break;
case WM_TIMER:
case TIMER_INT:
MessageBox(NULL, L"Timer was triggered from foo", L"FOO", NULL);
//continuous messageboxes will appear based on TIMER_INTERVAL if it works...
break;
break;
}
}
void ThreadServer(PVOID pvoid)
{
ThreadStart(); //calls accept() until client connects
while(1)
{
memset(&RecvBuffer[0], 0, 512 * sizeof(RecvBuffer[0])); //Clear recv
TCPServer.iRecv = recv(AcceptSocket, RecvBuffer, iRecvBuffer, 0);
if(strlen(RecvBuffer) > 1){
memset(&SendBuffer[0], 0, 512 * sizeof(SendBuffer[0]));
//Clears SendBuffer
std::string retString = "";
retString = process(RecvBuffer); //processes RecvBuffer
if(condition == true){
foo(hwnd);
}
if(strlen(retString.c_str()) > 0){
TCPServer.iSend = send(AcceptSocket, retString.c_str(), strlen(retString.c_str()), 0);
}else{
retString = "";
TCPServer.iSend = send(AcceptSocket, retString.c_str(), strlen(retString.c_str()), 0);
}
if(TCPServer.iSend == SOCKET_ERROR){
break;
}
}
//Determine if socket fails and breaks if failure occurs
//*
memset(&SendBuffer[0], 0, 512 * sizeof(SendBuffer[0]));
TCPServer.iSend = send(AcceptSocket, SendBuffer, iSendBuffer, 0);
if(TCPServer.iSend == SOCKET_ERROR){
break;
}//*/
Sleep(1);
}
}
The issue is trying to pass a reference to hwnd to calculation.cpp from the server thread. I can pass hwnd to the function foo(HWND), but the timer does not set. Is there a way to set a timer in a separate thread or is this not possible? Is there any other workaround to this with using winsock and a server?
As the document state that you can't create a timer for a window from a different thread. For you the different thread is the server thread.
Maybe you can post WM_TIMER message (PostMessage) to the main thread from the server thread when the timer timeout.
Or you need Synchronization Objects for threads synchronicity.
I'm trying to create an application that will be notified about each active window change in Windows so it could do some tasks like detecting window titles, therefore "punishing" bad people accessing bad content on our PC machines. So, this is really important for the application because it's purpose is to log "bad" applications from history.
So, in my main function, I started a thread for my WindowLogger.
windowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WindowLogger,
(LPVOID) argv[0], 0, NULL );
if (windowThread)
{
// Also a bit of protection here..
return WaitForSingleObject(windowThread, INFINITE);
}
Then, here is my WindowLogger procedure:
// Function called by main function to install hook
DWORD WINAPI
WindowLogger(LPVOID lpParameter)
{
HHOOK hWinHook;
HINSTANCE hExe = GetModuleHandle(NULL);
if (!hExe)
{
return 1;
}
else
{
hWinHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, hExe, 0);
MSG msg;
// I AM UNSURE ABOUT THIS PART..
// Probably wrong code :D ..
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == HCBT_ACTIVATE) {
// my code to log the window name
}
}
UnhookWindowsHookEx(hWinHook);
}
return 0;
}
And finally, my CBTProc callback function, it logs the windows using my log() function:
LRESULT CALLBACK
CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HCBT_ACTIVATE:
{
HWND foreground = GetForegroundWindow();
char window_title[50];
if (foreground)
GetWindowText(foreground, window_title, 25);
log("|");
log(&window_title[0]);
log("|");
}
}
}
So I had debugged the program and what I figured out is that hWinHook becomes NULL after SetWindowsHookEx() -- this is what probably causes my program to mailfunction..
.. Can you help me out with this?
Thanks in advance.
Passing 0 for the dwThreadId parameter to SetWindowsHookEx is used to register a hook for all threads in the system, i.e. a global hook. However to do this, your hook code needs to be located within a DLL (so that the DLL can be mapped into the address space of other processes). Since your hook code is in your main executable rather than a DLL the call is failing.
The MIDL compiler generates code for a proxy/stub with registration routines that write to HKEY_LOCAL_MACHINE. Is there any way (preferably without hacking the MIDL-generated code and without bypassing all that generated code in favor of custom code) to register a MIDL-generated p/s in HKEY_CURRENT_USER?
Also: Will this work if both the p/s and the COM server are registered per-user like this? I just found (after a very frustrating 48 hours) that a p/s registered machine-wide will not work correctly if the COM server is registered per-user. Specifically, the asynchronous call logic (ICallFactory::CreateCall) of the p/s will fail under these circumstances.
Using RegOverridePredefKey is the right answer.
Then register with:
regsvr32 /n /i:user C:\src\myCode.dll
With "/i:user", regsvr32 calls your the "DllInstall" function instead of DllRegisterServer.
Example implementation of DllInstall:
extern "C" STDAPI DllInstall(BOOL bInstall, _In_opt_ LPCWSTR pszCmdLine)
{
HRESULT hr = E_FAIL;
static const wchar_t szUserSwitch[] = L"user";
if (pszCmdLine != NULL)
{
if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0)
{
ATL::AtlSetPerUserRegistration(true); // is this really needed??
}
}
LSTATUS status = RegCreateKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Classes", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hkcu_classes, &disposition);
if (status == ERROR_SUCCESS)
{
status = RegOverridePredefKey(HKEY_CLASSES_ROOT, hkcu_classes);
}
hr = HRESULT_FROM_NT(status);
if (SUCCEEDED(hr))
{
if (bInstall)
{
hr = DllRegisterServer();
if (FAILED(hr))
{
DllUnregisterServer();
}
}
else
{
hr = DllUnregisterServer();
}
}
}
I have a fairly complex requirement. My STA COM object is implemented in a DLL (can't move it to out-of-process EXE). By the means of DllSurrogate I am hosting my object in a dllhost.exe process. My object has an UI attached to it (a plain modeless dialog) but I need the PreTranslateAccelerator mechanism in order for some shortcuts to work, etc. Since COM activates my object and hosts it in the default dllhost.com, I am obviously not controlling the message pump.
Is there still a way to pre-translate messages in this scenario? I doubt COM has foreseen such a specific scenario but maybe I am missing something.
Okay here it is. I hope I didn't leave out anything important. Basically, I have created a custom CMyComCreator instead of the default one. Instead of just creating a COM object and returning an interface pointer, I spin a worker UiThread. I use MyData structure to pass data across threads. Once the worker thread has finished setting up, I use the CComGITPtr to transfer the marshalled interface pointer from the UiThread back to the main. The consumers (out-of-process) end up with interface pointers that talk directly to the UiThread bypassing the main thread. You may think of CMyDialog as a modeless dialog which sends a PostQuitMessage on destruction to terminate the message loop. That's all. May look cumbersome but it works good.
struct MyData
{
ATL::CComGITPtr<IUnknown> Unk;
ATL::CEvent Event;
HRESULT hr;
MyData() : hr(E_OUTOFMEMORY), Event(FALSE, FALSE) { }
};
static CMessageLoop * MessageLoop;
class CMyComCreator
{
public:
static HRESULT WINAPI CreateInstance(
_In_opt_ void* pv,
_In_ REFIID riid,
_COM_Outptr_ LPVOID* ppv)
{
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
HRESULT hRes = E_OUTOFMEMORY;
MyData* data = NULL;
ATLPREFAST_SUPPRESS(6014 28197)
/* prefast noise VSW 489981 */
ATLTRY(data = _ATL_NEW MyData)
ATLPREFAST_UNSUPPRESS()
if (data != NULL)
{
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, UiThread, (void *)data, 0, NULL);
if (thread)
{
WaitForSingleObject(data->Event, INFINITE);
CloseHandle(thread);
hRes = data->hr;
if (SUCCEEDED(hRes))
{
ATL::CComPtr<IUnknown> unk;
hRes = data->Unk.CopyTo(&unk);
if (SUCCEEDED(hRes))
{
hRes = unk->QueryInterface(riid, ppv);
}
}
}
delete data;
}
return hRes;
}
};
typedef CMyComCreator _CreatorClass;
static unsigned __stdcall UiThread(void * param)
{
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
MyData * data = (MyData *)param;
ATL::CComObject<CMyDialog> * bb;
data->hr = ATL::CComObject<CMyDialog>::CreateInstance(&bb);
ATL::CComPtr<IUnknown> unk((IDispatch *) bb);
data->Unk = unk;
unk.Release();
data->Event.Set();
if (SUCCEEDED(data->hr))
{
CMessageLoop theLoop;
MessageLoop = &theLoop;
int nRet = theLoop.Run();
MessageLoop = NULL;
}
CoUninitialize();
return 0;
}
I needed to pack everything in a single DLL.
In which case, DllSurrogate is not the only way of doing this. There's also Rundll32:
INFO: Windows Rundll and Rundll32 Interface
This would allow you to run your own message loop inside the DLL's EntryPoint and have complete control over message processing, including PreTranslateMessage. You can copy the message loop logic from an ATL EXE server.
Bear in mind, there's still 32-bit and 64-bit version of "RunDll32.exe" in every 64-bit Windows OS. Use the one which matches the bit-ness of your DLL.
i am trying to hook CopyItems function ,its working fine but when i am trying to call Real CopyItems Function in the Callback function it is getting crash , my code is as below, please help me.
PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
return *(PVOID*)(*(DWORD*)intf + methodIndex * 4);
}
typedef HRESULT (WINAPI *CopyItemsNext)(IUnknown *punkItems,IShellItem *psiDestinationFolder);
CopyItemsNext Real_CopyItems = NULL;
CopyItemsNext Actual_CopyItems;
HRESULT WINAPI CopyItemsCallback(IUnknown *punkItems,IShellItem *psiDestinationFolder)
{
MessageBoxW(NULL,L"CopyItems Function Called", L"HookedCopyItemS", MB_OK);
return Real_CopyItems(punkItems, psiDestinationFolder);
}
HRESULT WINAPI CoCreateInstanceCallback(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
{
const char *IFileOperation_GUID = "{3AD05575-8857-4850-9277-11B85BDB8E09}";
char GUIDString[64];
HRESULT HR = Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
sprintf_s(GUIDString,64, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\0",
rclsid.Data1, rclsid.Data2, rclsid.Data3,
rclsid.Data4[0], rclsid.Data4[1],
rclsid.Data4[2], rclsid.Data4[3],
rclsid.Data4[4], rclsid.Data4[5],
rclsid.Data4[6], rclsid.Data4[7]);
if(strcmp(GUIDString, IFileOperation_GUID) == 0)
{
MessageBoxA(NULL, "IFileOperation_GUID Found", GUIDString, MB_OK);
if(Real_CopyItems == NULL)
{
Actual_CopyItems = (CopyItemsNext)GetInterfaceMethod(*ppv, 17);
MessageBoxA(NULL,"AFTER GetInterfaceMethod", "TEST", MB_OK);
if (MH_CreateHook(Actual_CopyItems, &CopyItemsCallback, reinterpret_cast<void**>(&Real_CopyItems)) != MH_OK)
{
MessageBoxW(NULL, L"Failed CreateHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
}
if (MH_EnableHook(Actual_CopyItems) != MH_OK)
{
MessageBoxW(NULL, L"Failed EnableHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
}
}
}
return HR;
}
//DllMain Function
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (MH_Initialize() != MH_OK)
{
MessageBoxW(NULL, L"Failed Initialize", L"Info!", MB_ICONWARNING|MB_OK);
}
if (MH_CreateHook(&CoCreateInstance, &CoCreateInstanceCallback, reinterpret_cast<void**>(&Real_CoCreateInstance)) != MH_OK)
{
MessageBoxW(NULL,L"Failed MH_CreateHook CoCreateInstance",L"Info!",MB_ICONWARNING|MB_OK);
}
if (MH_EnableHook(&CoCreateInstance) != MH_OK)
{
MessageBoxW(NULL,L"Failed MH_EnableHook StartDocA",L"Info!",MB_ICONWARNING|MB_OK);
}
break;
case DLL_PROCESS_DETACH:
if (MH_Uninitialize() != MH_OK)
{
}
if (MH_DisableHook(Actual_CopyItems) != MH_OK)
{
}
if (MH_DisableHook(&CoCreateInstance) != MH_OK)
{
}
break;
}
return TRUE;
}
In the above code inside the CopyItemsCallback function i am displaying Message box just to confirm weather the function is getting hook r not ,so i got that message box after that i am calling Real CopyItems Function but there it is getting crash so please check what is the problem with my code .
IFileOperation::CopyItems is a COM method, not a regular Win32 function, so you need to treat it differently than CoCreateInstance, which is a plain Win32 API.
When you call a COM method using C++ syntax, what you don't see is the "this" pointer (same as the interface pointer) being passed behind the scenes as a hidden parameter. But if you want to call a COM method using C-style code, you have to deal with this manually.
So your definition of the CopyItems function should instead look something like this:
typedef HRESULT (STDMETHODCALLTYPE *CopyItemsNext)(IFileOperation * pThis, IUnknown *punkItems, IShellItem *psiDestinationFolder);
...and when you call through to the 'real' one, you'll have to pass that pThis as the first parameter.
Note that this trick is specific to COM, you can't in general treat C++ methods this way. It just happens that COM was designed to be usable from plain C, so COM requires that the 'this' pointer is passed just as a normal parameter would be. (COM methods are marked with STDMETHODCALLTYPE which is what tells the compiler to treat them differently than methods without that.) However, for non-COM C++ classes, a compiler might do something else, such as passing the this pointer in a register.
--
By the way, note that the DWORD in your GetInterfaceMethod will only work on 32-bit windows; use DWORD_PTR if you want a type that is always the size of a pointer and which will then work with either 32-bit or 64-bit code.