I've created a dialog box inside a Win32 DLL (using resource editor) and now want to show it as application program (using this DLL) calls DisplayDialog, but it is not working.
// AppProgram.cpp
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_COMMAND:
switch (LOWORD (wParam)) {
case IDM_FILE_NEW_DIALOG:
DisplayDialog (hInst, hWnd);
break;
...
}
break;
....
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
My DLL appears like
#include "stdafx.h"
#include "myDLL.h"
EXPORT BOOL CALLBACK DisplayDialog (HINSTANCE hInst, HWND hWnd) {
DialogBox (hInst, MAKEINTRESOURCE (IDD_DIALOG1), hWnd, reinterpret_cast<DLGPROC> (DiagProc));
// MessageBox works here
}
...
I've tested that this DLL displays dialog if the dialog belongs to AppProgram.
Here, I want to display dialog when it is a part of DLL.
Please suggest whether we should create dialog inside DLL or should pass it from program. + how to show dialog in given scenario. Thanks in advance.
The hInst parameter is the handle to the module that contains the dialog resource. If you want to get the dialog from the DL's resourcesL, then pass the handle to the DLL rather than the handle to the main application.
Something like this:
HMODULE module = LoadLibrary("MyDll.dll");
HRSRC res = FindResource(module, "#1234", RT_DIALOG);
DLGTEMPLATE* pTemplate = (DLGTEMPLATE*)LoadResource(module, res);
DialogBoxIndirect(0, pTemplate, hwnd, dlgproc);
Related
I need to get the current WndProc with its messages and configuration and add my own code to it. Why do I need this? Because I'm working under an IDE that defines a window (and its children controls) with a WndProc, and I need to modify it because It contains all the actions related with every control. If I point a control to a custom WndProc the control loses all the actions and configuration set by the IDE. Suggestions?
Scheme:
HWND button; //My Button
LONG_PTR wndProc = GetWindowLongPtr(button, GWL_WNDPROC); //Getting the WndProc
wndProc -> Get this `WndProc` source code
LRESULT CALLBACK WndProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
wndProc (all the data);
+ my messages
}
You can't get source code of "old" WndProc of course, but you can call it using CallWindowProc() in your new wnd proc. Check out this article:
When you subclass a window, it's the original window procedure of the window you subclass you have to call when you want to call the original window procedure
Quote:
... your subclass function should go something like this:
wndProcOrig =
(WNDPROC)SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)SubclassWndProc);
LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
{
switch (wm) {
...
default:
return CallWindowProc(wndprocOrig, hwnd, wm, wParam, lParam);
}
}
It's easy to get system menu on console application (GetSystemMenu) and add some own entries (AppendMenu). But then these menu items are useless for the app. Is there any way to get into message stream that would identify what menu item was clicked ?
I've tried to hook to console window but without any result, I mean the WH_SYSMSGFILTER, all is compiling ok but there are no messages shown the hook function is not run by the system.
Next thing was ReadConsoleInput and this works partially, that is it shows mouse events on the system menu, but there is no information in MENU_EVENT_RECORD structure about what menu item was clicked.
These are my attempts all in one snippet, here the console should be flooded with messages, but only those from ReadConsoleInput appear, but these doesn't contain any useful information. No matter if user clicks on first or second added menu item there are only two codes shown 278 (0x116) WM_INITMENU and 287 (0x11F) WM_MENUSELECT, but there is no way I know to get to the wParam of WM_MENUSELECT message.
#include <windows.h>
#include <stdio.h>
HHOOK sysMsgFilterHook;
LRESULT CALLBACK SysMsgFilterCallback(int nCode, WPARAM wParam, LPARAM lParam) {
printf("%i\n", nCode);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
static LRESULT CALLBACK consoleWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
printf("%u\n", uMsg);
WNDPROC origProc = (WNDPROC) GetProp(hWnd, "origProc");
return CallWindowProc(origProc, hWnd, uMsg, wParam, lParam );
}
int main() {
SetLastError(0);
HWND console_hwnd = GetConsoleWindow();
HMENU console_hMenu = GetSystemMenu(console_hwnd, FALSE);
HINSTANCE console_hinstance = (HINSTANCE)GetWindowLong(console_hwnd, GWL_HINSTANCE);
DWORD console_processid = GetWindowThreadProcessId(console_hwnd, NULL);
HANDLE console_input_handle = GetStdHandle(STD_INPUT_HANDLE);
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "test menu item");
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "yet another menu item");
WNDPROC origProc = (WNDPROC)SetWindowLongPtr(console_hwnd, GWL_WNDPROC, (LONG_PTR)&consoleWndProc);
SetProp(console_hwnd, "origProc", (HANDLE)origProc);
sysMsgFilterHook = SetWindowsHookEx(
WH_SYSMSGFILTER,
(HOOKPROC)SysMsgFilterCallback,
console_hinstance,
console_processid
);
DWORD numEvents = 0;
INPUT_RECORD input;
while(ReadConsoleInput(console_input_handle, &input, 1, &numEvents)) {
//printf("input.EventType: %i\n", input.EventType);
if (input.EventType == MENU_EVENT) {
printf("input.Event.MenuEvent.dwCommandId %i\n", input.Event.MenuEvent.dwCommandId);
}
}
//printf("GetLastError: %lu\n", GetLastError());
UnhookWindowsHookEx(sysMsgFilterHook);
system("pause");
return 0;
}
I've succeeded with creating hook for mouse events, that is WH_MOUSE_LL. But all other hooks do not work.
What I intend to accomplish is to get some sort of WM_MENUCOMMAND message and then get rest with GetMenuItemInfo.
I've heard that the hooking procedure should be in another dll, but how to do that ? are there any working snippets ?
I'm looking for a way to manipulate a MessageBox like a window, would I have to actually use CreateWindowEx and make a tiny window in order to get the full functionality of a window including using things such as WM_GETTEXT and WM_SETTEXT or is there some way I can send these messages to a MessageBox? If I absolutely can't send windows messages to a MessageBox, then is there alternate methods less complicated then using CreateWindowEx to accomplish what I'm looking for?
Use a thread-local WH_CBT hook when you call MessageBox() to get its window handle. You can then send messages to it like any other window.
// if you need to customize MessageBox() across threads,
// store this variable in a TLS (thread-local storage) slot...
HHOOK hHook;
LRESULT CALLBACK MyCBTHook(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HCBT_CREATEWND: // window is being created
case HCBT_ACTIVATE: // window is being activated
{
HWND hWnd = (HWND) wParam;
// use hWnd as needed...
break;
}
}
return CallNextHookEx(hHook);
}
int MyMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)&MyCBTHook, NULL, GetCurrentThreadId());
int iResult = MyMessageBox(hWnd, lpText, lpCaption, uType);
UnhookWindowsHookEx(hHook);
return iResult;
}
I'll go ahead and give a summary to this, how can I use a dialog procedure that is a member of a class? I am creating a window wrapper class, but CreateDialogParam needs a global dialog procedure, so I tried this workaround:
I have done a bit of searching on this topic. I am making a Dialog class which I am subclassing to make a CMainWnd and then instantiating that. In the Dialog class I have a member function defined as INT_PTR CALLBACK Dialog::cb_proc(HWND,UINT,WPARAM,LPARAM). Now, I know that windows must have a global function as a callback procedure.
So I made a std::map<HWND,Dialog*> DlgProcs map to associate the dialogs window handle with its Dialog class pointer.
And a INT_PTR CALLBACK DlgMainProc(HWND,UINT,WPARAM,LPARAM) so I could pass that to CreateDialogParam(). In the body of DlgMainProc(...) I search the map for using the hWnd parameter to find the Dialog* and return its cb_proc(..) member.
My problem is that none of the messages get processed, this is because the member procedure in my Dialog class never gets called. Even though when I put a MessageBox() in DlgMainProc inside a if (DlgProcs.find(hWnd) != DlgProcs.end()) { statement, the messagebox is displayed, over and over again until I have to abort the program from Visual Studio 2008. Which tells me that it is finding the hWnd in my map. The weird thing is it also does this if I put it in the else statement after that, which contradictingly tells me it is NOT finding the hWnd in the map.
If I put a messagebox in the cb_proc member function it does not get displayed at all. But during this I never get any compiler, linker, or runtime errors. When I remove the messagebox from it (as to not have to abort the program, it was just for debugging purposes) the program runs but no messages get processed, the X button does not close the program, button clicks do nothing.
Here is the PasteBin code: http://pastebin.com/GsGUBpZU
Btw, I have no problem subclassing this, my window is created fine, just no messages are processed, cb_proc just never gets called.
EDIT: Here is the relevant parts of the code
map<HWND,Dialog*> g_DlgProcs;
INT_PTR CALLBACK g_MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (g_DlgProcs.find(hWnd) != g_DlgProcs.end()) {
Alert("blah"); // Gets executed repeatedly
return g_DlgProcs[hWnd]->cb_proc(hWnd, msg, wParam, lParam);
} else {
Alert("blah"); // Removing the above alert, this gets
// executed repeatedly, erm, as well.. O.o strange
return FALSE;
}
}
Dialog::Dialog(int id, HWND parent /* = HWND_DESKTOP */) {
_id = id;
_parent = parent;
// Tried this before CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
_handle = CreateDialogParam(
(HINSTANCE)GetModuleHandle(NULL),
MAKEINTRESOURCE(id), _parent,
(DLGPROC)g_MainDlgProc, NULL
);
// Then tried it after CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
}
INT_PTR CALLBACK Dialog::cb_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
Alert("blah"); // Never gets executed
bool handled = true;
switch (msg)
{
case WM_INITDIALOG:
OnInitialize();
break;
case WM_COMMAND:
if (HIWORD(wParam) == 0 || HIWORD(wParam) == 1) {
OnMenuCommand((HIWORD(wParam) == 1), (int)LOWORD(wParam));
} else {
OnCtrlCommand((int)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam);
}
break;
case WM_NOTIFY:
{
LPNMHDR head = (LPNMHDR)lParam;
OnNotification(head->code, head->idFrom, head->hwndFrom);
}
break;
case WM_CLOSE:
OnClose(); // DestroyWindow(_handle)
break;
case WM_DESTROY:
OnDestroy(); // PostQuitMessage(0)
default:
handled = ProcessMsg(msg, wParam, lParam);
}
// Convert bool to Windows BOOL enum
return ((handled == true) ? TRUE : FALSE);
}
Does anybody know why it never gets called? Or maybe just guide me to another way to use a member function as a DLGPROC?
The standard solution is to pass your this pointer as the last parameter to Create,DialogParam, stash it in DWLP_USER in your WM_INITDIALOG handler, and retrieve it from DWLP_USER thereafter. Basically you use DWLP_USER as your map.
I tried your code and it worked: cb_proc gets called. You will miss any messages (e.g. WM_INITDIALOG) that get sent before CreateDialogParam returns.
You can fix the latter problem by adding the window handle and the object to the map in g_MainDlgProc. If you get a message for an unknown window, you know it belongs to the window you're creating; put the object in a global and you can add the handle/object to the map.
I'm just adding this here in case someone finds it useful; using the magic of C++11 lambdas and templates you can have a simple wrapper template that means you don't have to continually rewrite the boiler-plate code for saving and loading userdata in window and dialog box procedures.
Here's an example for the DialogBoxParam function, but the same technique can be applied to CreateDialogParam and CreateWindowEx as well.
template <typename T, INT_PTR (T::*P)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)>
INT_PTR DialogBoxThis(T* pThis, HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent)
{
return ::DialogBoxParam(hInstance, lpTemplateName, hWndParent, [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR {
if (uMsg == WM_INITDIALOG) SetWindowLongPtr(hWnd, DWLP_USER, lParam);
T* pThis = reinterpret_cast<T*>(GetWindowLongPtr(hWnd, DWLP_USER));
return pThis ? (pThis->*P)(hWnd, uMsg, wParam, lParam) : FALSE;
}, reinterpret_cast<LPARAM>(pThis));
}
You would use it like this:
class MyClass
{
INT_PTR MyDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
// from inside MyClass, we can show a dialog that uses member function MyDlgProc as the dialog procedure
// note it is NOT a static function
DialogBoxThis<MyClass, &MyClass::MyDlgProc>(this, hInstance,
MAKEINTRESOURCE(IDD_MYDIALOG), hWndParent);
I want to create my own class to handle creating windows and the window procedure but I have noticed that the window procedure has to be static! I'm now wondering whether its possible to make the window procedure object oriented? I have read some tutorials on object oriented windows, but they always make the procedure static -.- whats the use in that? :/
Any links or info on how to get around this problem would be appreciated,
thanks
You can get around that by making the static WndProc delegate everything to the members:
// Forward declarations
class MyWindowClass;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
std::map<HWND, MyWindowClass *> windowMap;
// Your class
class MyWindowClass {
private:
HWND m_handle;
// The member WndProc
LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ }
public:
MyWindowClass()
{
/* TODO: Create the window here and assign its handle to m_handle */
/* Pass &WndProc as the pointer to the Window procedure */
// Register the window
windowMap[m_handle] = this;
}
};
// The delegating WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd);
if (it != windowMap.end())
return it->second->MyWndProc(message, wParam, lParam);
return 0;
}
The general technique of allowing a window instance to be represented by as class instance is to make use of the SetWindowLongPtr and GetWindowLongPtr to associate your class instance pointer with the window handle. Below is some sample code to get you started. It may not compile without a few tweaks. It's only meant to be a reference.
Personally, I've stopped rolling my own window classes back a few years ago when I discovered ATL's CWindow and CWindowImpl template class. They take care of doing all this mundane coding for you so can focus on just writing methods that handle window messages. See the example code I wrote up here.
Hope this helps.
class CYourWindowClass
{
private:
HWND m_hwnd;
public:
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE: return OnCreate(wParam, lParam);
case wM_PAINT: return OnPaint(wParam, lParam);
case WM_DESTROY:
{
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL);
m_hwnd = NULL;
return 0;
}
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
CYourWindowClass()
{
m_hwnd = NULL;
}
~CYourWindowClass()
{
ASSERT(m_hwnd == NULL && "You forgot to destroy your window!");
if (m_hwnd)
{
SetWindowLong(m_hwnd, GWLP_USERDATA, 0);
}
}
bool Create(...) // add whatever parameters you want
{
HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this);
if (hwnd == NULL)
return false;
ASSERT(m_hwnd == hwnd);
return true;
}
static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (uMsg == WM_CREATE)
{
pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow);
m_hWnd = hwnd;
}
if (pWindow != NULL)
{
return pWindow->WndProc(uMsg, wParam, lParam);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
};
};
If you are looking for object oriented Win32 API then you should look to MFC and/or WTL.
Just to add to Brian's answer but for a win32 framework that's more beginner friendly take a look at Win32++. The library itself isn't as comprehensive in features compared to MFC or QT but that is a tradeoff the designer made at the beginning to keep the library easy to understand and simple to use.
If you're still interested in this topic, I highly encourage you to take a look at it since it uses yet another technique for saving the 'this' pointer by utilizing thread local storage.
You can use the window handle passed to the WindowProc to grab an object you've created for that particular window and delegate the event handling to that object.
e.g.
IMyWindowInterface* pWnd = getMyWindowObject(hWnd);
pWnd->ProcessMessage(uMsg, wParam, lParam);