Consider the following code which needs to call one of two functions in User32.dll.
if( IsWindowsVistaOrGreater() )
AddClipboardFormatListener(hWnd) ;
else
SetClipboardViewer(hWnd) ;
If I'm not mistaken, this program will fail to start on WinXP because AddClipboardFormatListener does not exist in User32.dll under XP.
One way to solve this is not calling AddClipboardFormatListener directly but rather get a pointer to it ourselves:
GetProcAddress(GetModuleHandle("User32.dll"), "AddClipboardFormatListener").
However, if I instruct the linker to delay-load User32.dll...
Would this avoid loading that specific function under XP so that I don't need to call GetModuleHandle and GetProcAddress?
Is it recommended to delay-load a DLL when only a few functions need to be delay-loaded?
The case of User32.dll is particularly dramatic on the second point since most of the functions used in the program are know to exist in that DLL on all Windows versions.
I would guess that linking at load-time is more efficient than at run-time since the latter needs additional checks before each function call.
But I'm just guessing, hence the question.
Would this avoid loading that specific function under XP so that I don't need to call GetModuleHandle and GetProcAddress?
Yes. This is exactly the type of situation that delay-loading was invented for. your code can call a DLL function as if it were statically linked, but the executable will not load the DLL function pointer at runtime until the function is actually called for the first time. Internally, the delay-load mechanism uses LoadLibrary() and GetProcAddress() for you.
Is it recommended to delay-load a DLL when only a few functions need to be delay-loaded?
If a DLL is delay-loaded, ALL of its functions are delay-loaded, you cannot pick and choose which ones you want. So, if your app needs to use a lot of functions from the same DLL, like user32.dll, then static linking is usually more efficient, and then you can use GetProcAddress() manually for the few functions you really need to handle differently.
In this case, I would suggest getting rid of the OS check altogether and rely only on whether the DLL function actually exists or not, eg:
typedef BOOL (WINAPI *LPFN_ACFL)(HWND);
LPFN_ACFL lpAddClipboardFormatListener = (LPFN_ACFL) GetProcAddress(GetModuleHandle(TEXT("user32")), "AddClipboardFormatListener");
if( lpAddClipboardFormatListener != NULL )
lpAddClipboardFormatListener(hWnd);
else
SetClipboardViewer(hWnd);
Where delay-loading really shines is in its hooks. For instance, on earlier systems, you can use a delay-load failure hook to implement your own version of AddClipboardFormatListener(), and then your main code can just call AddClipboardFormatListener() unconditionally on all systems and it won't know the difference. For example (just a demo, not actually tested):
LRESULT CALLBACK ClipboardSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &ClipboardSubClassProc, uIdSubclass);
break;
case WM_CHANGECBCHAIN:
{
if (wParam == dwRefData)
SetWindowSubclass(hWnd, &ClipboardSubClassProc, uIdSubclass, lParam);
else if (dwRefData != 0)
SendMessage((HWND)dwRefData, uMsg, wParam, lParam);
break;
}
case WM_DRAWCLIPBOARD:
{
SendMessage(hWnd, WM_CLIPBOARDUPDATE, 0, 0);
if (dwRefData != 0)
SendMessage((HWND)dwRefData, uMsg, wParam, lParam);
break;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
BOOL WINAPI My_AddClipboardFormatListener(HWND hWnd)
{
HWND hWndNext = SetClipboardViewer(hWnd);
if ((!hWndNext) && (GetLastError() != 0))
return FALSE;
if (!SetWindowSubclass(hWnd, &ClipboardSubClassProc, 1, (DWORD_PTR)hWndNext))
{
DWORD dwErr = GetLastError();
ChangeClipboardChain(hWnd, hwndNext);
SetLastError(dwErr);
return FALSE;
}
return TRUE;
}
BOOL WINAPI My_RemoveClipboardFormatListener(HWND hWnd)
{
DWORD_PTR dwRefData;
if (!GetWindowSubclass(hWnd, &ClipboardSubClassProc, 1, &dwRefData))
{
SetLastError(ERROR_NOT_FOUND);
return FALSE;
}
RemoveWindowSubclass(hWnd, &ClipboardSubClassProc, 1);
return ChangeClipboardChain(hWnd, (HWND)dwRefData);
}
FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if ((dliNotify == dliFailGetProc) && (pdli->dlp.fImportByName))
{
if (strcmp(pdli->dlp.szProcName, "AddClipboardFormatListener") == 0)
return (FARPROC) &My_AddClipboardFormatListener;
if (strcmp(pdli->dlp.szProcName, "RemoveClipboardFormatListener") == 0)
return (FARPROC) &My_RemoveClipboardFormatListener;
}
return NULL;
}
__pfnDliFailureHook2 = &MyDliFailureHook;
...
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
AddClipboardFormatListener(hWnd);
break;
case WM_DESTROY:
RemoveClipboardFormatListener(hWnd);
break;
case WM_CLIPBOARDUPDATE:
// do all of your clipboard processing here...
break;
...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Related
I use SetWindowsHookEx to install a global GETMESSAGE hook in a dll like this:
SetWindowsHookEx(WH_GETMESSAGE,HookProc,hModule,0);
and the the hook procedure within the dll too.But when i called InstallHook(this function is exported from the DLL) to install the GETMESSAGE hook,booom, the system can not respon the mouse operation,the windows on the desktop can be close or move) ,here is my HookProc Code:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
WCHAR szMsg[MAX_PATH] = { 0 };
PMSG pMsg = (PMSG)lParam;
wsprintf(szMsg, L"MSG_FROM:%08x,MSG_TYPE:%d", pMsg->hwnd,pMsg->message);
OutputDebugString(szMsg);
return CallNextHookEx(NULL,nCode, wParam, lParam);
}
I've read the MSDN for many times,it just said i must process the message if the ncode is HC_ACTION,but,i don't know how to process the message.I think there must be someone else has this problem too, so, hope somebody give some help, and tell me how you process this trouble.
Thanks a lot.
I viewed many tutorials and posts on this subject, and they all say I pass the class instance pointer (this) in my CreateWindowEx() function, and then store it in the window procedure function, when the WM_NCCREATE message is sent. I guess this is because WM_NCCREATE is supposedly the first message that gets sent to the window procedure since a window is created.
A few questions/notes:
From debugging I came to know that actually WM_GETMINMAXINFO is the first sent message, before WM_NCCREATE (at least on my machine). Does this mean I should listen for this message instead of WM_NCCREATE?
According to this popular article, the reason everyone calls SetWindowLongPtr() after the message WM_NCCREATE is received is because
If the value does not exist by the time WM_NCCREATE is called then,
by some mysterious Windows behavior that I still don't understand, the
value never gets inserted.
I tried to do exactly that (that is, call SetWindowLongPtr() after CreateWindowEx()). It turns out to be just fine. The application runs okay. Below is my code, please tell me if there's something wrong with this approach.
void GLWin32::CreateWindow(...)
{
...
_hwnd = CreateWindowEx(NULL, _wndclassex.lpszClassName, title.c_str(), WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, _hinstance, NULL);
SetWindowLongPtr(_hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this));
...
}
//static window procedure for all instances of this class
LRESULT CALLBACK GLWin32::_msgRouter(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LONG l = GetWindowLongPtr(hwnd, GWLP_USERDATA);
GLWin32* thisPtr = reinterpret_cast<GLWin32*>(l);
if (thisPtr)
return thisPtr->_winProc(msg, wparam, lparam);
else
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Why is my approach not used instead of the popular approach?
The problem with this approach is that if you want to use the instance when processing any of the window creation messages (including "ordinary" messages that are sent as part of the creation process), you won't have access to it.
Suppose you want to create a button when processing WM_CREATE (typical scenario) and you want to set the button text to some instance member value. You want something like:
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
CreateWindow("BUTTON", this->buttonText, WS_VISIBLE | WS_CHILD,
10, 10, 50, 30, this->hwnd, NULL, this->hInstance, NULL);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Problem is, when WM_CREATE is processed (before CreateWindowEx returns), SetWindowLongPtr wasn't called yet and the instance pointer is missing, so _winProc isn't being called at all.
I'm using a low-level keyboard hook on windows. It works like a charme, despite of the fact that I'm currently unable to tell whether the key was initially pressed or pressed again. The documentation (+here) says, that bit 7 holds the transition state. But this seems only to be true when the key is being released. Bit 7 is sadly not set when I firstly press the key.
Is there any way to tell whether the key is pressed initially?
I happen to run into this problem recently. I can't find any good solutions, but I ended up using a flag and a GetAsyncKeyState before SetWindowHookEx.
BOOL wasDown;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
LPKBDLLHOOKSTRUCT key = (LPKBDLLHOOKSTRUCT) lParam;
if (key->vkCode == VK_SOMETHING) {
switch (wParam) {
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (!wasDown) {
// Processing on first key down
wasDown = true;
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
// Processing on key up
wasDown = FALSE;
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
wasDown = GetAsyncKeyState(VK_SOMETHING) < 0;
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
Of course, this code only does it for one key. You can use an array of flags to do multiple keys. Depending on your application you could also unconditionally set the flag to false if you want the first press after your hook is set.
I have made a simple win32 application, that opens a dialog box with an edit control. After searching for hours I couldn't find a way to get the user input from this edit control and store it in a string. I think the code here does what I want (haven't tested it) but I don't understand any of it. So an explanation or other solution would be nice. (I'm using VC++ 2012)
Other solution I found that IS C++ :S
Ok, I made a seperate message loop, and inserted the code there. Which now looks like this:
INT_PTR CALLBACK IP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
else if(LOWORD(wParam) == IDOK)
{
TCHAR szBuf[40];
GetDlgItemText(hDlg, IDC_EDIT1, szBuf, 39);
//Breakpoint here!
//szBuf="127.0.0.1" as intended :)
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Try to use
UINT WINAPI GetDlgItemText(
_In_ HWND hDlg,
_In_ int nIDDlgItem,
_Out_ LPTSTR lpString,
_In_ int nMaxCount
);
like this:
TCHAR szBuf[BUFF_LEN];
GetDlgItemText(hWnd, TXT_MYEDIT_ID, szBuf, BUFF_LEN - 1);
OK so I have my main window procedure (simplified):
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
if(!loadFiles())
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
loadFiles() is a function to read some text files. If the files are missing, it posts an error message and then returns false. I handle this by sending the WM_CLOSE message, which sends WM_DESTROY? The program calls PostQuitMessage(0) and.. nothing. The process is still sitting in background, now using 100% CPU on core 1. Here is my message loop :
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
Very simple, I've looked around and seen people using all kinds of different loops, most with PeekMessage() function.. its worth noting I have several child windows containing different controls, I show and hide them when the user selects different tabs, but I don't think it matters because PostQuitMessage(0) is supposed to post WM_QUIT to the message queue, which destroys the child windows aswell right? Any help? Thanks
According to MSDN WM_CREATE is sent during CreateWindow. So you are destroying the window right during creation. I am not sure that this is supposed to work. Also, why so complicated? The documentation says
If an application processes this message, it should return zero to
continue creation of the window. If the application returns –1, the
window is destroyed and the CreateWindowEx or CreateWindow function
returns a NULL handle.
So just return -1 in case loadFiles() fails and handle CreateWindow returning NULL accordingly.