letting a DLL call a exe function with function pointer - c++

Can anyone tell me what I'm doing wrong?
I'm trying to run a custom main on a different thread.
This is the code.
.exe
main.cpp
#include "dll_class.h"
#include <iostream>
int main(void);
DllClass object(main);
int main(void)
{
std::cout << "Enter the main code.\n";
std::getchar();
}
.dll
dll_class.h
#include "platform.h"
#include <iostream>
class DLL_API DllClass //DLL_API is just a macro for import and export.
{
public:
DllClass(int(*main)(void))
{
std::cout << "Start application.\n";
platform = new Platform(main);
}
~DllClass(void)
{
delete platform;
}
private:
Platform* platform;
};
platform.h
class DLL_API Platform
{
public:
Platform(main_t main_tp);
~Platform(void){}
};
platform.cpp
#include "platform.h"
#include "Windows.h"
#include <iostream>
HHOOK hookHandle;
int(*main_p)(void);//This will hold a the main function of the the .exe.
LRESULT CALLBACK keyHandler(int nCode, WPARAM wParam, LPARAM lParam);
DWORD WINAPI callMain(_In_ LPVOID lpParameter)
{
std::cout << "Calling the main function.\n";
main_p();
return 0;
}
Platform::Platform(int(*main_tp)(void))
{
main_p = main_tp;
CreateThread(NULL, 0, callMain, NULL, 0, NULL);
std::cout << "Setting hooks.\n";
hookHandle = SetWindowsHookEx(WH_MOUSE_LL, keyHandler, NULL, 0);
std::cout << "Enter message loop.\n";
MSG message;
while(GetMessage(&message, (HWND)-1, 0, 0) != 0){
TranslateMessage( &message );
DispatchMessage( &message );
}
}
LRESULT CALLBACK keyHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
std::cout << "Inside the hook function.\n" << std::endl;
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
}
It runs great, till a certain moment.
This is the output.
Start application.
Setting hooks.
Calling the main function.
Enter message loop.
Inside the hook function. (A lot of times of course).
but it never says:
Enter the main code.
Is it impossible to let dll call a exe function?

It is very much POSSIBLE to call a function in the executable file from a shared library. However, the C standard, as mentioned in the other answer, doesn't allow you to call main. This has to do with the fact that the C runtime [to guard against language lawyers: insert "sometimes" here] relies on a certain order of things, and if you try to call main before the C runtime has done the right initialization BEFORE main, you get problems.
If your goal is to actually subvert what main does, then you will have to find a different way of achieving this - at least if you expect it to work for more than one particular executable.

The C++ standard doesn't allow calling main() or taking its address, which is what you're doing here. See this thread which quotes line and verse. So, what you're doing is undefined.

Related

Implementing a keyboard hook under windows produces massive bugs

I tried to implement a basic hook under windows.
While it technically works (my handle gets called) it produces massive bugs, that i do not know how to fix.
When I run the programm and try to write something in the firefox.exe searchbar or the explorer.exe addres bar the programs crash.
That is the code i currently tried. I stripped everything unnecessary but it still doesnt work
main.cc
#include <iostream>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
int main (int argc, char** argv){
HINSTANCE dll = NULL;
HOOKPROC proc = NULL;
HHOOK hook = NULL;
MSG msg;
BOOL b_ret = FALSE;
dll = LoadLibraryA("hookdll.dll");
if (dll == NULL) {
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
return 1;
}
proc = (HOOKPROC)GetProcAddress(dll, "KeyboardHook");
if (proc == NULL) {
FreeLibrary(dll);
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
return 1;
}
hook = SetWindowsHookEx(WH_CALLWNDPROC, proc, dll, 0);
if (hook == NULL) {
FreeLibrary(dll);
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
return 1;
}
while (GetMessage(&msg, NULL, WH_KEYBOARD, WM_KEYLAST) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hook);
FreeLibrary(dll);
return 0;
}
And in the DLL:
hooks.h
#ifndef __LOG_DLL_HOOKS_H__
#define __LOG_DLL_HOOKS_H__
#include <iostream>
#include <fstream>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
extern "C" LRESULT CALLBACK KeyboardHook(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam);
#endif // !__LOG_DLL_HOOKS_H__
hooks.cc
#include "Hooks.h"
extern "C" LRESULT CALLBACK KeyboardHook(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam) {
if (code == HC_ACTION) {
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
As you can see it barely does anything.
I worked with the official windows docs and did everything the right way (or so i thought)
The only thing that could make a difference is the return value of KeyboardHook, but
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644984(v=vs.85) states that:
If code is less than zero, the hook procedure must return the value returned by CallNextHookEx.
If code is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns;
I read that as: "Return CallNextHookEx either way", which i did.
Thanks for any answeres
Well, for starters, why are you using a keyboard function for a window procedure hook? I think you meant to use WH_KEYBOARD instead of WH_CALLWNDPROC when calling SetWindowsHookEx().
Also, your GetMessage() call is wrong, because WH_KEYBOARD is not a message identifier. You would need to use WM_KEYFIRST instead, to match your use of WM_KEYLAST (since you are clearly only interested in dispatching keyboard messages).
However, you are setting the dwThreadId parameter of SetWindowsHookEx() to 0, which means you are hooking not just your own thread but all threads of all processes globally. A WH_KEYBOARD hook runs in the context of the thread that installs it, which means internally the OS will have to delegate the hooked keyboard messages of those other threads to your thread, and it does that by sending messages to your thread. But, your message loop is not going to be processing any of those messages because it is filtering for only keyboard messages (of which it will never receive, since your thread has no UI of its own).
With all of that said, try this instead:
#include <iostream>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
int main (){
HINSTANCE dll = LoadLibraryA("hookdll.dll");
if (dll == NULL) {
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
return 1;
}
HOOKPROC proc = (HOOKPROC) GetProcAddress(dll, "KeyboardHook");
if (proc == NULL) {
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
FreeLibrary(dll);
return 1;
}
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, proc, dll, 0);
if (hook == NULL) {
std::cerr << "WinAPI Error: " << GetLastError() << "\n";
FreeLibrary(dll);
return 1;
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hook);
FreeLibrary(dll);
return 0;
}

Why is this behavour - my global hook works with a message loop but not with an empty loop?

I'll preface this with saying that I am new to win32 programming.
I'm creating a global keyboard hook using a .dll, I have put in install and uninstall functions to handle the actual setting and removing of the keyboard hook.
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hk=NULL;
//static CMyFile *pLF;
#pragma data_seg()
HINSTANCE hins = NULL;
__declspec( dllexport ) LRESULT Install(){
std::cout << "Installing" << std::endl;
hk = SetWindowsHookEx(WH_KEYBOARD_LL,EventAnalysis::KeystrokeAnalysis::KeyboardCallback,hins,0);
if(hk == NULL){
std::cout << "Hook creation failed! - " << GetLastError() << std::endl;
}
return 0;
}
__declspec(dllexport) BOOL CALLBACK UnInstall()
{
std::cout << "UnInstalling" << std::endl;
return UnhookWindowsHookEx(hk);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hins = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
So now that I have my .dll, I created a simple executable that loads the library and installs the hooks:
int _tmain(int argc, _TCHAR* argv[])
{
auto funHandle = LoadLibrary(L"C:\\Users\\tprodanov\\Documents\\visual studio 2010\\Projects\\HaveFun\\Release\\HaveFun.dll");
if(funHandle == NULL){
std::cout << "Library load failed! - " << GetLastError() << std::endl;
}
auto Install = (LRESULT(*)()) GetProcAddress(funHandle, "?Install##YAJXZ");
if(Install == NULL){
std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
}
Install();
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
auto Uninstall = (BOOL(*)()) GetProcAddress(funHandle, "?UnInstall##YGHXZ");
if(Uninstall == NULL){
std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
}
Uninstall();
return 0;
}
What I find curious is that the behavior of my program is as expected in its current state (and also if instead of a message loop I just pop out a MessageBox() that waits for the user to click OK), but it doesn't work if I use std::cin.get() or an empty while loop. Can someone please explain why this is the behavior?
Also as a followup question - the KeyboardCallback function just prints to the console "Key Pressed".
LRESULT CALLBACK EventAnalysis::KeystrokeAnalysis::KeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam){
std::cout << "Key pressed" << std::endl;
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
I expected that this will be printed only when I press keys when focused on the console window, but even if I type in notepad the "Key Pressed" messages show up in my executable that called the Install function of the .dll. I don't understand this, since as far as I understood the dynamic library is loaded independently in every process, so every process has its own copy of the KeyboardCallback function and it will try to print to the foreground window's console.
The documentation makes it clear what is happening:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
The hook is installed by the call you made to Install. And so in the same thread that makes that call you need to run a message loop.
As for why showing a message box influences things, a message box operates by running a modal message loop. And that message loop will dispatch the hook messages.
And for the followup question, again the documentation has the answer:
The system calls this function every time a new keyboard input event is about to be posted into a thread input queue.
When it says posted into a thread input queue it means any thread input queue.
Or in the remarks to the documentation of SetWindowsHookEx look at the list of the various hook types, and their scope. The WH_KEYBOARD_LL is listed as a global hook.
Note also that WH_KEYBOARD_LL is a low-level hook and so does not result in the DLL being injected into another process. In fact your code is overly complex. You simply do not need a DLL here at all. You can get it all going with a call to SetWindowsHookEx from your executable that passes a callback function in that same executable.
Here's a minimal sample program that demonstrates all this:
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
std::cout << "Key pressed" << std::endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
std::cout << "Installing" << std::endl;
HHOOK hk;
hk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
std::cout << "UnInstalling" << std::endl;
UnhookWindowsHookEx(hk);
return 0;
}

dll hook function not called

I trying to catch and retranslate keyboard and mouse events. So I use SetWindowsHookEx and function in dll. First time ะจ have one big error - GetProcAddress can't get my function. That answer help me a lot GetProcAddress returns NULL
Now i can call functions from dll and I can see effect from hook: my keyboard not work while programm is run. But hook not called.
main.cpp
#include <Windows.h>
#include <WinUser.h>
#include <iostream>
#include <fstream>
using namespace std;
HHOOK hhk;
int main(){
HINSTANCE hinstLib = LoadLibrary(TEXT("hookdll.dll"));
typedef void (*Install)();
typedef void (*Uninstall)();
typedef LRESULT (_stdcall *HookProcedure)(int, WPARAM , LPARAM );
Install install = (Install) GetProcAddress(hinstLib, "install");
Uninstall uninstall = (Uninstall) GetProcAddress(hinstLib, "uninstall");
HookProcedure hookProc = (HookProcedure) GetProcAddress(hinstLib, "_hookProcedure#12");//omg
cout << GetLastError()<< "\n";
install();
hhk = SetWindowsHookEx(WH_KEYBOARD, hookProc, hinstLib, NULL);
cout << GetLastError()<< "\n";
for(int i = 0; i < 50; i++){
Sleep(200);
cout << i << "\n";
}
UnhookWindowsHookEx(hhk);
uninstall();
return 0;
}
hookdll.cpp
#include <Windows.h>
#include <iostream>
#include <fstream>
HINSTANCE hinst;
HHOOK hhk;
std::ofstream myfile;
extern "C" __declspec(dllexport)
LRESULT CALLBACK hookProcedure(int code, WPARAM w, LPARAM l)
{
MessageBox(NULL, (LPCWSTR)L"HEY HEY", (LPCWSTR)L"Test", MB_OK);
//never saw this message
return CallNextHookEx(NULL, code, w, l);
}
extern "C" __declspec(dllexport) void install() {
myfile.open("log.txt",std::ios_base::app);
myfile << "\ninstall " << GetLastError();
}
extern "C" __declspec(dllexport) void uninstall() {
myfile << "\nuninstall " << GetLastError();
myfile.close();
}
extern "C" __declspec(dllexport)
BOOL WINAPI DllMain( __in HINSTANCE hinstDLL, __in DWORD fdwReason, __in LPVOID lpvReserved) {
hinst = hinstDLL;
return TRUE;
}
The keyboard hook allows you to intercept WM_KEYDOWN and WM_KEYUP window messages. Console applications do not receive these messages unless there is an active windows message queue. If you want to see and process these messages in a console application create a window and give it keyboard focus. Make sure you do message pumping with the GetMessage and DispatchMessage WinAPI calls in the thread that owns the window.
If you do not want to create a window you can use WH_KEYBOARD_LL to intercept keyboard related messages sent to the active message queue of a thread. You will still need to use GetMessage to read from the queue or it will eventually start dropping messages.

Let a dll call a .exe function by sending a pointer [duplicate]

This question already has answers here:
letting a DLL call a exe function with function pointer
(2 answers)
Closed 9 years ago.
This question looks like one I asked before, except that I now know that you can't call the main function from a global object. So this code doesn't work with main. But why does it fail with other functions as well?
This is the code.
.exe
main.cpp
#include "dll_class.h"
#include <iostream>
int my_main(void)
{
std::cout << "Enter the my_main code.\n";
std::getchar();
}
DllClass object(my_main);
int main(void)
{
std::cout << "Enter the main code.\n";
std::getchar();
}
.dll
dll_class.h
#include "platform.h"
#include <iostream>
class DLL_API DllClass //DLL_API is just a macro for import and export.
{
public:
DllClass(int(*main)(void))
{
std::cout << "Start application.\n";
platform = new Platform(main);
}
~DllClass(void)
{
delete platform;
}
private:
Platform* platform;
};
platform.h
class DLL_API Platform
{
public:
Platform(main_t main_tp);
~Platform(void){}
};
platform.cpp
#include "platform.h"
#include "Windows.h"
#include <iostream>
HHOOK hookHandle;
int(*main_p)(void);//This will hold a the main function of the the .exe.
LRESULT CALLBACK keyHandler(int nCode, WPARAM wParam, LPARAM lParam);
DWORD WINAPI callMain(_In_ LPVOID lpParameter)
{
std::cout << "Calling the main function.\n";
main_p();
return 0;
}
Platform::Platform(int(*main_tp)(void))
{
main_p = main_tp;
CreateThread(NULL, 0, callMain, NULL, 0, NULL);
std::cout << "Setting hooks.\n";
hookHandle = SetWindowsHookEx(WH_MOUSE_LL, keyHandler, NULL, 0);
std::cout << "Enter message loop.\n";
MSG message;
while(GetMessage(&message, (HWND)-1, 0, 0) != 0){
TranslateMessage( &message );
DispatchMessage( &message );
}
}
LRESULT CALLBACK keyHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
std::cout << "Inside the hook function.\n" << std::endl;
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
}
It runs great, till a certain moment.
This is the output.
Start application.
Setting hooks.
Calling the main function.
Enter message loop.
Inside the hook function. (A lot of times of course).
but it never says:
Enter the my_main code.
Enter the main code.
Is it impossible to let dll call a exe function?
The answer is still the same as the one I gave to your other question. Your Platform constructor is hung. The loop termination conditions are never met, so the constructor never returns. And the main function cannot run until all global objects have been constructed.
Update: The above discussion was why Enter the main code never prints.
If you step through your my_main function, you'll see the problem with Enter the my_main code: The calls to cout and getchar are ignored. That's because the order of constructions of global objects in different translation units is unspecified. In the main executable, the object global object is being constructed first, which means that the cin and cout objects may not be fully constructed. That's why cout can't print and why getchar cannot read.
Surely, the CORRECT thing to do here is to construct the object inside main. If needed, pass in my_main to the object. But this will solve all of the "trying to use something before it has been constructed".
The key here (which I only gather from reading the comments on the other answer) is that the cout object is not "the same one" for the main executable and the DLL. This leads to issues with calling things that do cout before you have entered main [which I tried to explain in the previous question too - the C runtime library needs to initialize certain things, and that happens in an unspecified order before main is called].

Why does SetWindowsHookEx return 0?

I'm trying to set a WH_CBT hook, and it return 0 all the time.
I checked for error, and I got error 1428. I researched a little and found out that I have a problem with the hMod parameter, though I can't see what should I put in it instead of null. Does anyone know what I am doing wrong?
This is my code:
#include "stdafx.h"
#include "Windows.h"
#include <iostream>
using namespace std;
HHOOK hookHandle;
LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam);
int _tmain(int argc, _TCHAR* argv[])
{
hookHandle = SetWindowsHookEx(WH_CBT,CBTProc,NULL,0);
if(hookHandle == NULL)
{
cout << "ERROR CREATING HOOK: ";
cout << GetLastError() << endl;
getchar();
return 0;
}
MSG message;
while(GetMessage(&message, NULL, 0, 0) != 0)
{
TranslateMessage( &message );
DispatchMessage( &message );
}
cout << "Press any key to quit...";
getchar();
UnhookWindowsHookEx(hookHandle);
return 0;
}
LRESULT CALLBACK CBTProc( int nCode,WPARAM wParam, LPARAM lParam)
{
cout << "hello" << endl;
return CallNextHookEx(hookHandle, nCode,
wParam, lParam);
}
P.S. I apologize if the code has stupid elements about it. I'm not a newbie to programming, just to C++.
If you specify 0 for the threadid that specifies the hook to be global. For that to work, the hook needs to be injected into other processes. This means the hook needs to be exposed from a DLL. You need to either move the hook procedure to a dll, or specify a thread in your process.
Use GetModuleHandle(NULL) and GetCurrentThreadId() to get the handle and the thread id you need to pass to that function.
Sample:
hookHandle = SetWindowsHookEx(WH_CBT,CBTProc,
GetModuleHandle(NULL),
GetCurrentThreadId());
As Logan says, that would hook only the current process. You need to put the code in a dll to develop a system hook.
I know that this is very old post, but I was fighting with the simmilar issue. I wanted to track size and location changes for the "Shell_traywnd" window and I found a solution in this thread. I belive that it will help for someone else.