I'm working with C++ and the Windows API now for just a little while. I've never used a callback in C++ since yesterday, when the Windows API required me to do so for installing a low level mouse event hook (link to hook function). To keep my code a little cleaner I wanted to outsource some code to a function and then I ran into a problem that I don't understand. I think it has to do something with me not totally understanding the callback scope or something like that. My code looks like this and I use C++11 and VS2017:
MouseHandler.h
#ifndef __MOUSEHANDLER_H_INCLUDED__
#define __MOUSEHANDLER_H_INCLUDED__
#include <Windows.h>
class MouseHandler
{
private:
public:
static _bstr_t coordinatesToString(POINT point);
MouseHandler();
~MouseHandler();
};
#endif // !__MOUSEHANDLER_H_INCLUDED__
MouseHandler.cpp
#include "stdafx.h"
#include "MouseHandler.h"
#include <comutil.h>
#include <string>
using namespace std;
HHOOK mouseHook = NULL;
_bstr_t MouseHandler::coordinatesToString(POINT point)
{
_bstr_t coordinates = "(";
_bstr_t xcoordinate = to_string(point.x).c_str();
_bstr_t ycoordinate = to_string(point.y).c_str();
coordinates += xcoordinate + "," + ycoordinate + ")";
return coordinates;
}
LRESULT CALLBACK MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT event = *((MSLLHOOKSTRUCT *)lParam);
if (nCode == HC_ACTION)
{
_bstr_t message = "Mouse action happened at position: ";
_bstr_t mouseCoordinates = MouseHandler::coordinatesToString(event.pt);
message += mouseCoordinates;
}
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
MouseHandler::MouseHandler()
{
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0);
while (GetMessage(NULL, NULL, 0, 0) != 0);
}
MouseHandler::~MouseHandler()
{
}
When I try to compile I get the error C3646 'coordinatesToString': unknown override specifier. I searched up and down and asked my colleagues, but I couldn't get help with this, so I hope someone here can help me. Thanks in advance!
Make sure you specify the correct type of data.
to_string((long double)point.x).c_str();
Load the lib.
#pragma comment (lib, "comsuppw.lib")
or
#pragma comment (lib, "comsuppwd.lib")
Include comutil.h to the header CMouseHandler.h.
I tested your code in VS2010 C++ on Win10 1803 x64.
CMouseHandler.h
#pragma once
#include <Windows.h>
#include <comutil.h>
#include <string>
using namespace std;
#pragma comment (lib, "comsuppw.lib")
class CMouseHandler
{
public:
CMouseHandler(void);
~CMouseHandler(void);
static _bstr_t coordinatesToString(POINT point);
};
CMouseHandler.cpp
#include "CMouseHandler.h"
HHOOK mouseHook = NULL;
_bstr_t CMouseHandler::coordinatesToString(POINT point)
{
_bstr_t coordinates = "(";
_bstr_t xcoordinate = to_string((long double)point.x).c_str();
_bstr_t ycoordinate = to_string((long double)point.y).c_str();
coordinates += xcoordinate + "," + ycoordinate + ")";
return coordinates;
}
LRESULT CALLBACK MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT event = *((MSLLHOOKSTRUCT *)lParam);
if (nCode == HC_ACTION)
{
_bstr_t message = "Mouse action happened at position: ";
_bstr_t mouseCoordinates = CMouseHandler::coordinatesToString(event.pt);
message += mouseCoordinates;
}
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
CMouseHandler::CMouseHandler()
{
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0);
while (GetMessage(NULL, NULL, 0, 0) != 0);
}
CMouseHandler::~CMouseHandler(void)
{
}
_bstr_t isn't defined, as visual studio doesn't recognise the type it assumes its an override specifier. You need to include comutil.h as specified in the documentation.
Related
I want to implement Internet Explorer webview control on my window.
I found this answer, on how to do that.
There is a problem: Navigate2 method from the answer is different from the headers I have. In the posters’s code, seems it has only one argument, and maybe others are by default, but I have 5 arguments with the stupidest thing I have ever met - VARIANT type variables (also, in poster’s code it is _variant_t which is undefined for me).
Probably I will never understand the sEiFe logic, why to make instead of Navigate2(wchar_t *,...) cool stuff VARIANT * (I know about Navigate method), but can anyone provide an example of calling that method.
This full code
#include <Windows.h>
#include <Ole2.h>
#include "resource.h"
#include <iostream>
#include <atlbase.h> //activex
#include <atlwin.h> //windows
#include <atlcom.h>
#include "exdisp.h"
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")
//This will load the browser dll then library and will generate headers
//All the declarations will be in the namespace SHDocVw
//#import "shdocvw.dll"
using namespace std;
class CMyDialog : public CAxDialogImpl<CMyDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP(CMyDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnBnCancel)
COMMAND_HANDLER(IDOK, BN_CLICKED, OnBnOk)
END_MSG_MAP()
CComPtr<IWebBrowser2> ctrl;
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// Do some initialization code
HRESULT hr;
//IDC_EXPLORER_TEST is the ID of your control
GetDlgControl(IDC_EXPLORER_TEST, __uuidof(ctrl), (void**)&ctrl);
VARIANT address;
address.vt = VT_BSTR;
address.bstrVal = SysAllocString(L"google.com");
VARIANT empty;
empty.vt = VT_EMPTY;
hr = ctrl->Navigate2(&address, &empty, &empty, &empty, &empty);
SysFreeString(address.bstrVal);
/*
Also fails
_variant_t a = SysAllocString(L"google.com");
VARIANT f;
f.vt = VT_I2;
f.iVal = navBrowserBar;
_variant_t fr = SysAllocString(L"_self");
_variant_t h = SysAllocString(L" ");
hr = ctrl->Navigate2(&a, &f, &fr, &h, &h);
*/
LRESULT res = CAxDialogImpl<CMyDialog>::OnInitDialog(uMsg, wParam, lParam, bHandled);
return 0;
}
public:
LRESULT OnBnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDCANCEL);
return 0;
}
LRESULT OnBnOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDOK);
return 0;
}
};
CComModule _Module;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
CMyDialog dlg;
dlg.DoModal();
return 0;
}
Returns an exception at method call because of 0x0 read violation.
It appears that you failed to check if GetDlgControl succeeded. When it fails, ctrl has an unspecified value and might be null.
Of course, that leaves the question why it would fail, but that's another issue.
I am setting a global hook for keyboard. When I give keyboard inputs to other applications, the application does not receive the input and it hangs. When the console is stopped, the application recovers and the keyboard inputs are posted together.
DLL source:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
Console applicatioon source:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
My suspicion was that since the dll will be loaded into each process in the process's own address space and console would not be present in other applications, it gets void and crashed. So I removed the console outputs and replaced with messagebox. Then also no difference.
What could be the problem?
Update:
I tried to do a local hook to a specific thread before trying it global. But I get Parameter is incorrect error 87 at setwindowshookex. Below are the updated code:
dll:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
Console application source:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
Try to use WH_KEYBOARD_LL. You can set global hook even without dll declaring hook function in you process. Plus, you should detect space action using PKBDLLHOOKSTRUCT struct
LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION )
{
switch ( wParam )
{
case WM_KEYDOWN:
{
// Get hook struct
PKBDLLHOOKSTRUCT p = ( PKBDLLHOOKSTRUCT ) lParam;
if ( p->vkCode == VK_SPACE)
{
MessageBoxA( NULL, "Hi", "Space", MB_OK );
}
}
break;
}
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
....
// Somewhere in code
kb_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, NULL, NULL );
Thanks for all the inputs in answers and comments.
I have found out the actual problem. The mistake I made was trying to use console window without any message queue.
If I understand correctly, console windows are hosted by conhost.exe and they don't have any message pumps. And the hook works correctly only if the application which installs it has a message queue (should explore more on why it's this way). See below for ways you can make it work
If you are not posting any message to the console application:
Replace the for loop in the console application's main with this:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
In case you are posting any message to the console application:
Create a window using CreateWindowEx, there is an option for a message only window also. You would have to create a class and assign a CALLBACK process. Read here for more details. Create that and pass the handle along to the hook dll and postmessage to the handle. Use the loop for Getting msg and dispatching it (mentioned above). Then all the messages you post the dummy window from your hook dll can be processed using the CALLBACK window process.
References:
Why must SetWindowsHookEx be used with a windows message queue
CreateWindowEx MSDN
I had the same issue, working with QT, the GUI would be blocked (as planned) but whenever it came back online, it would process my keyboard and mouse clicks.
I am not sure if this is the most efficient way of handling it, but to solve this, I handled all the keyboard and mouse events separately. If, some task was in progress, I would just ignore the key event.
Otherwise I guess it just queues up and waits for its' turn!
I am trying to print a list of running applications like alt-tab would give me. Here are what I have done so far:
1.In the beginning I tried EnumWindows, but I got hundreds of entries.
2.I found some similar questions and they led me to the blog of Raymond Chen.
http://blogs.msdn.com/b/oldnewthing/archive/2007/10/08/5351207.aspx
However it still shows more than 100 windows(window_num1 being 158 and window_num2 being 329), while alt-tab would give me only 4. What did I do wrong? Here is my code:
#include <windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "user32.lib")
HWND windowHandle;
int window_num1=0;
int window_num2=0;
BOOL IsAltTabWindow(HWND hwnd)
{
if (hwnd == GetShellWindow()) //Desktop
return false;
// Start at the root owner
HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
// See if we are the last active visible popup
HWND hwndTry;
while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry)
{
if (IsWindowVisible(hwndTry))
break;
hwndWalk = hwndTry;
}
return hwndWalk == hwnd;
}
BOOL CALLBACK MyEnumProc(HWND hWnd, LPARAM lParam)
{
TCHAR title[500];
ZeroMemory(title, sizeof(title));
//string strTitle;
GetWindowText(hWnd, title, sizeof(title)/sizeof(title[0]));
if (IsAltTabWindow(hWnd))
{
_tprintf(_T("Value is %s\n"), title);
window_num1++;
}
window_num2++;
//strTitle += title; // Convert to std::string
if(_tcsstr(title, _T("Excel")))
{
windowHandle = hWnd;
return FALSE;
}
return TRUE;
}
void MyFunc(void) //(called by main)
{
EnumWindows(MyEnumProc, 0);
}
int main()
{
MyFunc();
cout<<endl<<window_num1<<endl<<window_num2;
return 0;
}
You failure is, that you should walk only visible windows... read the blog again.
For each visible window, walk up its owner chain until you find
the root owner. Then walk back down the visible last active popup
chain until you find a visible window. If you're back to where you're
started, then put the window in the Alt+↹Tab list.
Your code walks over every window!
Just use IsWindowVisible
BOOL CALLBACK MyEnumProc(HWND hWnd, LPARAM lParam)
{
TCHAR title[256] = {0,};
if (IsWindowVisible(hWnd) && GetWindowTextLength(hWnd) > 0)
{
window_num1++;
GetWindowText(hWnd, title, _countof(title));
_tprintf(_T("Value is %d, %s\n"), window_num1, title);
}
return TRUE;
}
I have a strange situation using SetWindowsHookEx
I have a bcb 2009 project with a form and a Memo on it.
in the create we load the Dll and attach the function handler's to both sides.
The idea is that when the key board is hit a message appear in the memo box and when a mouse event happen an other text appears in the memo box.
The strange this is that when I cleaned the code from debug information it stops working. That means the hook got triggered one time and than it was over.
In the debug I was using some VCL TStringList to log key stokes data to disk. Playing with that code I finally detected that by adding
[code]
TList* lList = new TList();
delete lList;
To every one of the hook functions (keyboard, mouse) the code is working again.
What is wrong in my code that I have to do this?
This is the first time in 15 years I make a dll. so it can be something real basic in creating a dll or exporting the functions.
Every suggestion is welcome.
regards
JVDN
Some new additional information:
[solved]My target is win XP embedded. my application creates a error that closes the explorer by windows. And the hook is not working global in xp but only local. But it is working on my develop platform win 7 x64 global typing and mousing in notepad result in messages in the application.
[solution] Modified the WH_KEYBOARD to WH_KEYBOARD_LL and the mouse from WH_MOUSE to WH_MOUSE_LL solves the receiving key and mouse on Windows XP embedded.
Both the dll and the application have no runtime lib or packages.
DLL Code
[code]
//---------------------------------------------------------------------------
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
//---------------------------------------------------------------------------
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be performing new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE's to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
//
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
typedef void __stdcall ( *typFn)(WPARAM,LPARAM);
static typFn gGUIProcessingKeyboard = NULL;
static HHOOK gGUIProcessingKeyboardHook = NULL;
static typFn gGUIProcessingMouse = NULL;;
static HHOOK gGUIProcessingMouseHook = NULL;
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
//---------------------------------------------------------------------------
extern "C"
{ __declspec(dllexport) void SetGUIProcessingKeyboard(typFn aHandle);
__declspec(dllexport) void ReleaseGUIProcessingKeyboard(typFn aHandle);
__declspec(dllexport) LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam);
__declspec(dllexport) void SetKeyboardHookHandle(HHOOK aHook );
__declspec(dllexport) void SetGUIProcessingMouse(typFn aHandle);
__declspec(dllexport) void ReleaseGUIProcessingMouse(typFn aHandle);
__declspec(dllexport) void SetMouseHookHandle(HHOOK aHook );
__declspec(dllexport) LRESULT CALLBACK wireMouseProc(int code, WPARAM wParam,LPARAM lParam);
/**
* Set the keyboard loop back handle
*/
void SetGUIProcessingKeyboard(typFn aHandle)
{
if (aHandle != gGUIProcessingKeyboard)
{
gGUIProcessingKeyboard = aHandle;
}
}
/**
* Release the keyboard loop back handle
*/
void ReleaseGUIProcessingKeyboard(typFn aHandle)
{
gGUIProcessingKeyboard = NULL;
}
/**
* Set the handle used for tapping the Keyboard
*/
void SetKeyboardHookHandle(HHOOK aHook )
{
gGUIProcessingKeyboardHook = aHook;
}
/**
* Tapping the keyboard from the other applications
*/
LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam)
{
TList* lList = new TList();
delete lList;
if (code < 0) {
return CallNextHookEx(gGUIProcessingKeyboardHook, code, wParam, lParam);
}
if (NULL != gGUIProcessingKeyboard)
{
gGUIProcessingKeyboard( wParam,lParam);
}
return CallNextHookEx(gGUIProcessingKeyboardHook, code, wParam, lParam);
}
/**
* Set the mouse loop back handle
*/
void SetGUIProcessingMouse(typFn aHandle)
{
if (aHandle != gGUIProcessingMouse)
{
gGUIProcessingMouse = aHandle;
}
}
/**
* Release the mouse loop back handle
*/
void ReleaseGUIProcessingMouse(typFn aHandle)
{
gGUIProcessingMouse = NULL;
}
/**
* Set the handle used for tapping the mouse
*/
void SetMouseHookHandle(HHOOK aHook )
{
gGUIProcessingMouseHook = aHook;
}
/**
* Tapping the mouse from the other applications
*/
LRESULT CALLBACK wireMouseProc(int code, WPARAM wParam,LPARAM lParam)
{
TList* lList = new TList();
delete lList;
// if (gGUIProcessingMouseHook != NULL)
// {
if (code < 0) {
return CallNextHookEx(gGUIProcessingMouseHook, code, wParam, lParam);
}
if (NULL != gGUIProcessingMouse)
{
gGUIProcessingMouse( wParam,lParam);
}
return CallNextHookEx(gGUIProcessingMouseHook, code, wParam, lParam);
// }
// return 0;
}
} // extern C
And here is the application.
[code cpp]
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "MonitoringToolMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
typedef void __stdcall ( __closure *typFn)(WPARAM,LPARAM);
TForm1 *Form1;
HHOOK TForm1::mHook = NULL;
typedef void __stdcall (*typSetHook)(HHOOK);
typedef LRESULT CALLBACK ( *typHookFunc)(int,WPARAM,LPARAM);
static HHOOK gMyGUIProcessingKeyboardHook = NULL;
static HHOOK gMyGUIProcessingMouseHook = NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void __stdcall TForm1::MyKeyboardProc(
WPARAM wParam,
LPARAM lParam
)
{
if (Form1 != NULL)
{
Form1->Memo1->Lines->Add(L"GotA keyboard");
}
}
void __stdcall TForm1::MyMouseProc(
WPARAM wParam,
LPARAM lParam
)
{
if (Form1 != NULL)
{
Form1->Memo1->Lines->Add(L"Pip pip");
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
if (NULL == mHinst)
{
mHinst = LoadLibrary("KeyboardMouseHookDLL.dll");
}
if (mHinst)
{
typedef void (*Install)(typFn);
// the keyboard
typSetHook SetHook = (typSetHook) GetProcAddress( mHinst, "_SetKeyboardHookHandle" );
typHookFunc wireKeyboardProc = (typHookFunc)GetProcAddress(mHinst, "wireKeyboardProc" );
Install install = (Install) GetProcAddress(mHinst, "_SetGUIProcessingKeyboard");
if (install)
{
install(&MyKeyboardProc);
}
if ((NULL != wireKeyboardProc) &&
(NULL != SetHook) )
{
gMyGUIProcessingKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)wireKeyboardProc,mHinst,NULL);
SetHook(gMyGUIProcessingKeyboardHook);
}
// The mouse
typSetHook SetMouseHook = (typSetHook) GetProcAddress(mHinst, "_SetMouseHookHandle");
typHookFunc wireMouseProc = (typHookFunc)GetProcAddress(mHinst, "wireMouseProc");
Install installMouse = (Install) GetProcAddress(mHinst, "_SetGUIProcessingMouse");
if (installMouse)
{
installMouse(&MyMouseProc);
}
if ((NULL != wireMouseProc) &&
(NULL != SetMouseHook) )
{
gMyGUIProcessingMouseHook = SetWindowsHookEx(WH_MOUSE,(HOOKPROC)wireMouseProc,mHinst,NULL);
SetMouseHook(gMyGUIProcessingMouseHook);
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if (NULL == mHinst)
{
mHinst = LoadLibrary("KeyboardMouseHookDLL.dll");
}
if (mHinst)
{
if (NULL != gMyGUIProcessingKeyboardHook )
{
UnhookWindowsHookEx(gMyGUIProcessingKeyboardHook);
gMyGUIProcessingKeyboardHook = NULL;
}
typedef void (*Uninstall)(typFn);
Uninstall uninstall = (Uninstall) GetProcAddress(mHinst, "_ReleaseGUIProcessingKeyboard");
if (uninstall)
{
uninstall(&MyKeyboardProc);
}
if (NULL != gMyGUIProcessingMouseHook )
{
UnhookWindowsHookEx(gMyGUIProcessingMouseHook);
gMyGUIProcessingMouseHook = NULL;
}
Uninstall uninstallMouse = (Uninstall) GetProcAddress(mHinst, "_ReleaseGUIProcessingMouse");
if (uninstallMouse)
{
uninstallMouse(&MyMouseProc);
}
FreeLibrary(mHinst);
mHinst = NULL;
}
}
//---------------------------------------------------------------------------
And the form header
[code]
//---------------------------------------------------------------------------
#ifndef MonitoringToolMainH
#define MonitoringToolMainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMemo *Memo1;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
private: // User declarations
int __stdcall lKeyBoard();
void __stdcall MyKeyboardProc( WPARAM wParam, LPARAM lParam );
void __stdcall MyMouseProc( WPARAM wParam, LPARAM lParam );
HINSTANCE mHinst;
static HHOOK mHook;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
If you're installing a global system hook, the hook DLL will be injected in each running process. As each process has its own memory space, you'll need to define a shared data section to place variables like the hook handles, otherwise they will be different for each process.
#pragma data_seg(".SHARDAT")
static HHOOK gGUIProcessingKeyboardHook = NULL;
static HHOOK gGUIProcessingMouseHook = NULL;
#pragma data_seg()
Also don't register function pointers to the hook DLL, as you will ask other processes to call the registered functions in your application. It's better to register the HWND of your application and a window message.
Create a exported function in your DLL that sets the hook and stores HWND and custom message number, f.e.:
#pragma data_seg(".SHARDAT")
static HHOOK g_keybHook = NULL;
static HHOOK g_mouseHook = NULL;
HWND g_registeredWnd = NULL;
UINT g_registeredKeybMsg = 0;
UINT g_registeredMouseMsg = 0;
#pragma data_seg()
HINSTANCE g_hInstance = NULL;
BOOL InstallHook(HWND registeredWnd, UINT registeredKeybMsg, UINT registeredMouseMsg)
{
if (g_hHook != NULL) return FALSE; // Hook already installed
g_keybHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeybProc, g_hInstance, 0);
if (g_keybHook == NULL) return FALSE; // Failed to install hook
g_registeredWnd = registeredWnd;
g_registeredKeybMsg = registeredKeybMsg;
g_registeredMouseMsg = registeredMouseMsg;
return TRUE;
}
In the DllEntryPoint you save hinst in g_hInstance in case reason == DLL_PROCESS_ATTACH:
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if ((reason == DLL_PROCESS_ATTACH) && (g_hInstance == NULL))
g_hInstance = hinst;
return 1;
}
In your application you register 2 window messages with the RegisterWindowMessage function and pass these values to the InstallHook function from the hook DLL. Then your application needs to handle those messages in its message loop.
registeredKeybMsg = RegisterWindowMessage("MyOwnKeybHookMsg");
registeredMouseMsg = RegisterWindowMessage("MyOwnMouseHookMsg");
InstallHook(hwnd, registeredKeybMsg, registeredMouseMsg);
How to select an existing folder (or create new) from a native Win32 application?
Here is a similar question. It has a good answer for C#/.NET. But I want the same thing for native Win32.
Anybody knows a solution, free code, etc?
Update:
I tried the function from the answer. Everything worked as expected, except it is necessary to call the SHGetPathFromIDList function to retrieve the name of selected directory. Here is a sample screen shot:
SHBrowseForFolder
Do your users a favor, and set at least the BIF_NEWDIALOGSTYLE flag.
To set the initial folder, add the following code:
static int CALLBACK BrowseFolderCallback(
HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
if (uMsg == BFFM_INITIALIZED) {
LPCTSTR path = reinterpret_cast<LPCTSTR>(lpData);
::SendMessage(hwnd, BFFM_SETSELECTION, true, (LPARAM) path);
}
return 0;
}
// ...
BROWSEINFO binf = { 0 };
...
binf.lParam = reinterpret_cast<LPARAM>(initial_path_as_lpctstr);
binf.lpfn = BrowseFolderCallback;
...
and provide a suitable path (such as remembering the last selection, your applications data folder, or similar)
Just as a go to for future users, this article helped me a lot with getting a directory dialog in C++
http://www.codeproject.com/Articles/2604/Browse-Folder-dialog-search-folder-and-all-sub-fol
Here is my code (heavily based/taken on the article)
NOTE: You should be able to copy/paste this into a file / compile it (g++, see VS in ninja edit below) and it'll work.
#include <windows.h>
#include <string>
#include <shlobj.h>
#include <iostream>
#include <sstream>
static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg, LPARAM lParam, LPARAM lpData)
{
if(uMsg == BFFM_INITIALIZED)
{
std::string tmp = (const char *) lpData;
std::cout << "path: " << tmp << std::endl;
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
}
return 0;
}
std::string BrowseFolder(std::string saved_path)
{
TCHAR path[MAX_PATH];
const char * path_param = saved_path.c_str();
BROWSEINFO bi = { 0 };
bi.lpszTitle = ("Browse for folder...");
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LPARAM) path_param;
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
//get the name of the folder and put it in path
SHGetPathFromIDList ( pidl, path );
//free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
{
imalloc->Free ( pidl );
imalloc->Release ( );
}
return path;
}
return "";
}
int main(int argc, const char *argv[])
{
std::string path = BrowseFolder(argv[1]);
std::cout << path << std::endl;
return 0;
}
EDIT: I've updated the code to show people how to remember the last selected path and use that.
Also, for VS, using Unicode character set. replace this line:
const char * path_param = saved_path.c_str();
With this:
std::wstring wsaved_path(saved_path.begin(),saved_path.end());
const wchar_t * path_param = wsaved_path.c_str();
My Test code above is compiled with g++, but doing this fixed it in VS for me.
For Windows Vista and above, it's best to use IFileOpenDialog with the FOS_PICKFOLDERS option for a proper open dialog rather than this tree dialog. See Common Item Dialog on MSDN for more details.