MessageBox - HWND parameter - c++

I am working on an MFC application and I am adding some error checking with the use of MessageBox which has documentation found here.
int MessageBox(
[in, optional] HWND hWnd,
[in, optional] LPCTSTR lpText,
[in, optional] LPCTSTR lpCaption,
[in] UINT uType
);
Note: The utype parameter is a list of styles separated with |
Above is MessageBox's implementation. My question is about the HWND parameter. When writing my call to MessageBox, Visual Studio 2017 Professional did not ask for the HWND parameter. At first, I thought it was because it is optional, but the other two optional LPCTSTR parameters were not as optional as they seemed, and required me to put at least "" to satisfy them.
Currently, my call to MessageBox only uses the last three parameters. My call is:
int BoxReturnVal = MessageBox("foo1", "foo2", MB_OK | MB_ICON);.
My question is why is the HWND parameter not asked for while writing the call to the function and do I need to worry about it all?
Thank you in advance ! :D

You are not calling the MessageBox() function that you think you are.
You are looking at the MessageBox() function in the Win32 API, but MFC has its own MessageBox() method in the CWnd class. The latter one, which does not have an HWND parameter, is the one you are actually calling.

Related

win32 - Dialog inside .dll

I want to a create .dll, which shows some dialog.
In my .dll I have this code:
HWND hDlg = CreateDialogParam(NULL, MAKEINTRESOURCE(IDD_RANKING_DIALOG), NULL, msgProc, NULL);
if (!hDlg) {
ShowError(GetLastErrorAsString().c_str());
return false;
}
ShowError calls Message box and GetLastErrorAsString() just calls standard GetLastError and converts to string.
I have this output:
The specified resource type cannot be found in the image file.
Then I have a standard win32 Window application and there I call method, which calls the mentioned code.
DialogTest test;
test.showDialog(); // calls functionality from .dll
What I am doing wrong? Do I need to link resource files to .dll?
I am using Visual studio 2010 and dialog is specified in my resource file (.rc).
The error code and message are accurate: The resource cannot be found where you instructed the system to go looking for it: The executable image that was used to start the process, not your DLL. The behavior is documented (see CreateDialogParam):
hInstance [in, optional]
Type: HINSTANCE
A handle to the module which contains the dialog box template. If this parameter is NULL, then the current executable is used.
Since you have the dialog template stored inside your DLL, you will have to pass the HINSTANCE that identifies your DLL. There are a number of ways to get the correct value, but passing NULL or GetModuleHandle(NULL) won't work. Both of these return the module handle to the executable image that started the process (not your DLL).
The easy solution: Pick the hInstance passed into your DllMain and store it in a global variable for later use.
HINSTANCE g_hInst = NULL;
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) {
switch ( fdwReason ) {
case DLL_PROCESS_ATTACH:
g_hInst = hinstDLL;
break;
default:
break;
}
return TRUE;
}
The robust solution: This solution can be used anywhere, in a DLL, an EXE, or a static LIB. Only down-side: It relies on undocumented features of Microsoft's linker. Don't worry, though, it won't fail silently.
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISMODULE ((HINSTANCE)&__ImageBase)
HINST_THISMODULE will always hold the correct value, regardless of where it is used.1)
The same can be achieved using official interfaces (GetModuleHandleEx) as well. The following solution can be used from an EXE, a DLL, or a static LIB as well, so long as you make sure to compile and link the function into the respective module:
HMODULE GetCurrentModuleHandle() {
HMODULE hModule = NULL;
GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModuleHandle,
&hModule );
return hModule;
}
This returns an HMODULE, not an HINSTANCE. This is not an issue, though, since they are the same thing2).
1) From Accessing the current module’s HINSTANCE from a static library
2) What is the difference between HINSTANCE and HMODULE?
You specified NULL as the first parameter to CreateDialogParam. If you want to load the dialog resource file from the Win32 Window Application, you should use this instead:
HWND hDlg = CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RANKING_DIALOG), NULL, msgProc, NULL);
However, if you want to load it from the DLL itself, you should replace the first parameter with the HINSTANCE parameter from the DllMain entry point function of the DLL.

Win api MessageBox alternative that has a set for text-align: center

As I found out by searching, it is not possible to create a MessageBox() with center-aligned text.
So is there some simple alternative providing the MessageBox() functionality (including program wait for closing/accepting the box) that has an option to center-align the text?
Thanks for suggestions/examples.
PS: On Windows7+, using C++ Windows API (compiled in MS Visual Studio 2012)
EDIT:
Some useful tips:
1) Express version of Visual Studio does NOT have a resource editor/file create option:
You do have a Visual Studio "higher" than express - How to: Add a
Resource File
You have just Express version :
How to
add a resource editor for Express version
Free editor
ResEdit
This MSDN forum page contains some other useful tips like:
From the 'solution explorer', right-click the *.rc file and select
'open with..', then select 'source code (text) editor' from the list.
You might want to 'set as default' to save you repeating those
intitial steps. Once done, you should be able to manually edit the
resource script within Express.
Free XN Resource Editor
2) Visual Studio C++ how to display a dynamic message (i.e., string) in my About box?
As I found out by searching, it is not possible to create a MessageBox() with center-aligned text.
It is not possible to create a center-aligned MessageBox() dialog, as the API does not expose an option for that. But it is possible to manipulate the standard MessageBox()` dialog with some slight trickery to force it to be center-aligned.
Use SetWindowsHookEx() to create a WH_CBT hook for the thread that is calling MessageBox() (no DLL needed). The hook callback allows you to discover the HWND of the dialog that MessageBox() creates. With that, you can manipulate it however you want. In this case, you can use FindWindowEx() to get the HWND of the STATIC control for the dialog's text and then apply the SS_CENTER style to it using SetWindowLong(). For example:
LRESULT CALLBACK CenterMsgBoxTextProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
HWND hDlg = (HWND) wParam;
HWND hTxt = FindWindowEx(hDlg, NULL, TEXT("STATIC"), NULL);
if (hTxt)
SetWindowLong(hTxt, GWL_STYLE, GetWindowLong(hTxt, GWL_STYLE) | SS_CENTER);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HHOOK hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) &CenterMsgBoxTextProc, NULL, GetCurrentThreadId());
MessageBox(...);
if (hHook) UnhookWindowsHookEx(hHook);
Alternatively, you can use SetWinEventHook() instead of SetWindowsHookEx():
void CALLBACK CenterMsgBoxTextProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
HWND hTxt = FindWindowEx(hwnd, NULL, TEXT("STATIC"), NULL);
if (hTxt)
SetWindowLong(hTxt, GWL_STYLE, GetWindowLong(hTxt, GWL_STYLE) | SS_CENTER);
}
HWINEVENTHOOK hHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, &CenterMsgBoxTextProc, GetCurrentProcessId(), GetCurrentThreadId(), 0);
MessageBox(NULL, TEXT("test"), TEXT("test"), MB_OK);
if (hHook) UnhookWinEvent(hHook);
Here is what the result looks like in both cases:
Afaik there is not. But it is actually quite easy to create such a dialog using Win32 resources and the DialogBox function.

GetModuleHandle(NULL) vs hInstance

When programming using the Windows API, I've always made the HINSTANCE from WinMain a global variable immediately. If I want to make an OK button, I'd do it like so (given global HINSTANCE g_hInstance):
return CreateWindow("BUTTON", "OK", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 10, 10, 100, 30, exampleParentWindow, EXAMPLECHILDID, g_hInstance, NULL);
but lately I've been seeing the instance handle determined without having to be passed as a parameter or clogging up the global namespace, using a call to GetModuleHandle(NULL)*. So, the example above would look like this:
return CreateWindow("BUTTON", "OK", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 10, 10, 100, 30, exampleParentWindow, EXAMPLECHILDID, GetModuleHandle(NULL), NULL);
*If your compiler supports it, you can write GetModuleHandle(nullptr) and the statement will have the same result.
What's the advantage (if any) of calling GetModuleHandle(NULL) over explicitly specifying the instance handle?
Fine Print: I know this has an answer, but it has not been phrased as its own question on StackOverflow.
In an EXE, it does not make any difference. hInstance from WinMain() and GetModuleHandle(NULL) both refer to the same HINSTANCE (the module of the .exe file). But it does make a difference if you are creating windows inside of a DLL instead, since you have to use the DLL's hInstance but GetModuleHandle(NULL) will still return the HINSTANCE of the EXE that loaded the DLL.
HMODULE WINAPI GetModuleHandle( _In_opt_ LPCTSTR lpModuleName );
Give the module handle of the module name passed.If you are passing NULL, the you get the module handle of the EXE which is currently running.
If you specifically name the module name, you get the module handle of that dll which is mapped to the process address space.
The use is that when you are trying to call a function exported by the dll, or trying to use a dialog template in side that dll.At that time if you use the HMODULE returned form GetMoudleHandle(NULL) your code wont work.
Just to add my two-cents to these answers. In case you need to get the module handle from within a DLL (and don't want to, or can't save it in a global variable from the DllMain call) you can use this function to get it instead:
HMODULE getThisModuleHandle()
{
//Returns module handle where this function is running in: EXE or DLL
HMODULE hModule = NULL;
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR)getThisModuleHandle, &hModule);
return hModule;
}
One potential gain you get from using GetModuleHandle(NULL) over directly using the WinMain HINSTANCE comes more from architecture. If you want to provide a platform-independent system that runs on linux/windows/whatever you can have a layer that does platform-dependent translations. If that's the case you don't want platform dependent objects such as HINSTANCE showing up in the main application code. So, to circumvent that platform-dependence I put GetModuleHandle(NULL) in the constructor of the platform-dependent class which has the same effect that direct use of the WinMain HINSTANCE does but that abstracts that specific functionality out of the main codebase itself.

Get Window Handle (HWND) of a window created by a library call

EDIT: I forgot to mention, I do not have source code for the DLL that creates window, so I can't actually change the function to return HWND.
I am creating a Win32 application, and am using a DLL that creates a window for me through one of its exported function "void X();" I call X() in my WinMain().
It does create a window for me. I want to get the HWND of the window that was created by this exported library function, as X() returns void, so I can use it for other API calls.
Can someone tell the easiest to get the HWND?
I have searched and questions answered here, but I cant somehow figure out the exact, appropriate solution. I tried EnumWIndows() and then getting the Process ID, and then comparing with the current thread process ID. But I guess there should be a far better much more efficient and a easy way to get HWND.
After all, I am in the WinMain of the process that created this window in the first place.
If I need to explain anything, that I have missed out writing here, please let me know.
I am sure that this is very basic and am missing something blatantly here. Sorry.
Thanks & Regards!
Use a tool like Spy++ or Winspector to see all of the HWNDs created by your app, in particular their class names and window titles. Then you can copy those values into your code and make a single call to FindWindow() after the DLL has created its window, eg:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// ...
X();
HWND hWnd = FindWindow("ClassNameHere", "TitleHere");
// ...
return 0;
}
The easiest way to do that is to use the function SetWindowsHookEx(WH_CBT, fun, NULL, GetCurrentThreadId()). Then the fun function, a callback defined by you, will be called when a number of events happen. The one you want is the HCBT_CREATEWND.
Somethink like that (totally untested):
HWND hDllHandle = NULL;
LRESULT CALLBACK X_CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
hDllHandle = (HWND)wParam;
return CallNextHookEx(NULL, nCode, wParam, lParam); //The first parameter is useless
}
HWND CallXAndGetHWND()
{
HHOOK hDllHook = SetWindowsHookEx(WH_CBT, X_CBTProc, NULL, GetCurrentThreadId());
X();
UnhookWindowsHookEx(hDllHook);
//hDllHandle is a global variable, so will be now you window!
return hDllHandle;
}
Note that this function is not thread-aware, but most likely you will call it just once at the beginning of your code, so it shouldn't matter.
And beware! Many functions, even Win32 API functions, create hidden windows. This code will hook all of them and return the last one to be created. Changing it to return any other, or even a list of them, if needed, should be trivial.

Winapi: createWindow in plugin

I'm developing a plugin (a dll that is loaded by other app). There's a special function that should return HWND so that app can show a dialog. The problem is that I don't know from where I can get the hInstance (it's not passed as a parameter to the function).
Looks like I'm not understanding something, I'm new to all this stuff, so forgive if the question is silly.
UPD: tried to get hInstance with getModuleHandle:
void* createLoginDialog() {
HINSTANCE hIns = (HINSTANCE) GetModuleHandle(L"comapping");
HWND hWnd = CreateWindow(L"Popup",
L"Enter login",
WS_POPUP,
20,
20,
20,
20,
NULL,
NULL,
hIns,
NULL);
return hWnd;
}
I'm still getting Access Violation.
Several ways to get it:
The first argument passed to your DllMain() entrypoint, cast to HINSTANCE
GetModuleHandle() using your DLL name, cast to HINSTANCE
VirtualQuery(), passing the address of your function. Cast the returned MEMORY_BASIC_INFORMATION.BaseAddress to HINSTANCE. Works on both 32-bit and 64-bit versions of Windows.
According to the documentation of CreateWindow, the hInstance argument is optional. This means that it's valid to pass NULL here. However, as Simon Richter points out in the comments to this answer, the argument may only be NULL the window class is registered globally.
If you're writing a DLL, you may just as well define a DllMain entry point function yourself. This function is called by Windows, passing the handle of your function as the first arugment. You can memorize this handle somewhere to reuse it when creating your window.