Is there a solution for this case? - c++

This is a Windows Desktop Application project created by Visual Studio.
I have a Dialog resource created from the Resource View that has a Static Text.
I'm using this dialog in order to show errors to the user:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc);
The reason I'm using a DialogBox is that I need it to stop the code execution, because the next line of code will close the application I mean the user should be aware of the error message before application exits. I know a way to change the Static Text:
HWND myMessageBox = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), nullptr, MyMessageBoxProc);
HWND staticText = GetDlgItem(myMessageBox, IDC_STATIC);
SetWindowText(staticText, L"Text changed.");
But that approach doesn't stop code execution.
Since it's a Windows Desktop Application project I cannot create MFC classes and try the following approach:
// Find the Static Text.
// If called from within MyMessageBox class.
CWnd *staticText = GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
// If called from elsewhere.
MyMessageBox myMessageBox;
CWnd *staticText = myMessageBox.GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
So what would be a workaround in order to change the Static Text using a DialogBox without the need of MFC classes or even another approach that allows me to change the Static Text and still stop code execution like a DialogBox.

Just change the text in your window procedure (MyMessageBoxProc) by handling WM_INITDIALOG message. If you wish to supply the text to the dialog, then create it using DialogBoxParam instead, which is then accessible via the lParam parameter.
e.g.
INT_PTR MyMessageBoxProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG) {
HWND hCtrl = GetDlgItem(hWnd, IDC_STATIC);
SetWindowText(hCtrl, reinterpret_cast<LPCTSTR>(lParam));
}
return FALSE;
}
The creation would be something like:
LPCTSTR text = _T("Text changed.");
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc,
reinterpret_cast<LPARAM>(text));
Note that there is a standard message box that ships with windows, which you may want to use instead of writing your own. That's available via the function MessageBox

Related

CreateDialog in BHO always fails with error 1813 (resource not found)

I'm working on a BHO written a long time ago in C++, without the use of any of the VS wizards. As a result, this project deviates from the COM conventions and the boilerplate for a COM product. I worked with COM long ago, but never really did any Windows GUI/dialog stuff...
I'm trying to add a dialog box to allow the user to set the values of some new settings:
// serverDialog will be NULL
HWND serverDialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PROPPAGE_SETTINGS), NULL, DialogProc);
id (!serverDialog)
{
int error = GetLastError(); //1813
...
}
....
1813 means that the resource cannot be found. The IDD used there is in resource.h, which I manually included where needed.
DialogProc is defined as:
INT_PTR CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return FALSE;
}
Which I know I will have to change later if I want the dialog to actually process messages, but I haven't gotten that far yet. The 1813 error suggests failure before the dialog is even created as does the NULL dialog handle returned.
To add the dialog I used the Add Resource wizard and added a small property page.
I've tried to follow advice here, but to no avail.
Thanks!
You are passing GetModuleHandle(NULL) as the instance of the module that contains the resource. But GetModuleHandle(NULL) defines the executable file module. You need to pass the instance of the module containing your code. This question covers that topic: How do I get the HMODULE for the currently executing code?
You probably ought to pass a window handle to the hWndParent parameter so that the dialog is owned.

How to get HWND in ATL DLL (for SendMessage or PostMessage)

I want to get HWND in ATL DLL for SendMessage or PostMessage function in Thread.
but, ATL DLL doesn't have a window.
How to get HWND in ATL DLL?
Project Application Setting : DLL(Dynamic-link library), Security Development Lifecycle, ('not' Support MFC)
Class Option : Apartment, Aggregation Yes, Dual InterFace, Connection points.
HelloCtrl.cpp (VB Client is Handling ShowMessage())
STDMETHODIMP CHelloCtrl::ShowMessage(BSTR bstrCaption, VARIANT_BOOL* lpvbResult)
{
DWORD dwThreadID;
m_hThread_ReadData = CreateThread(NULL, 0, T_ReadData, (LPVOID)this, 0, &dwThreadID);
return S_OK;
}
DWORD WINAPI CHelloCtrl::T_ReadData(LPVOID pParam)
{
CHelloCtrl* hCtrl = (CHelloCtrl*) pParam;
::PostMessage(hCtrl->m_hWnd, WM_KEYDOWN, (WPARAM)NULL, (LPARAM)NULL);
return S_OK;
}
void CHelloCtrl::LeftButton()
{
Fire_OnMouseClick(123, 123);
}
HelloCtrl.h
#define WM_THREADFIREEVENT (WM_USER+1)
BEGIN_MSG_MAP(CHelloCtrl)
CHAIN_MSG_MAP(CComControl<CHelloCtrl>)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_THREADFIREEVENT, OnLeftButtonDown)
END_MSG_MAP()
public:
STDMETHOD(ShowMessage)(BSTR bstrCaption, VARIANT_BOOL* lpvbResult);
LRESULT OnLeftButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
void LeftButton();
private:
HANDLE m_hThread_ReadData;
static DWORD WINAPI T_ReadData(LPVOID pParam);
Window is an object that a process or module might have or might not have, or it might create one if needed. That is, your question does not have an answer without specifying what kind of window and its HWND handle you are looking for. DLL and HWND are unrelated.
From the context, it looks like you want a window which you can use for messaging and to transfer execution control between threads. That is, you post somewhere then handle elsewhere leaving the threading magic to window API.
In this case you can either reuse one of existing windows, such as window created for an ActiveX control, our you simply create your own window you fully control and use for your purposes. For the latter you derive from CWindowImpl and... see Implementing a Window with CWindowImpl. The former might be simpler might be not: ActiveX controls don't have to have a window in which case they are windowless controls. In the same time, you have an option to force windowed control using m_bWindowOnly, see How do I get the HWND for an ActiveX control after the control has been initialised/activated?.

How do I use Dialog resources in Win32?

Without resources I can create my UI with a complex array of CreateWindow() and CreateWindowEx(), and WndProc() to process my events.
I noticed if I right-click in the resource view and click "add resource", I can draw a dialog box with all the controls. This would save me a huge amount of time if I could draw the interface like I normally do with C#.
After I've drawn the interface with the resource editor, how do I then create the window from code? Can someone provide a very simple example with a button, and show how to handle a WM_COMMAND event on that button please?
Also, is this generally how people create the GUI? Is there any loss in flexible to do this way? Even in C# I often have to supplement designer-generated UI with my own code-generated UI, but the majority of the time I'm quite happy to use designer.
After creating the dialog in the resource editor, call CreateDialog(modeless dialog;you need to dispatch the messages manually just like when you use CreateWindow) or DialogBox(modal dialog; the function does not return until you close the dialog. it does the dispatching for you) to make the dialog show up. Just like you pass in the window proc to RegisterClass, you pass the dialog proc to those functions for the dialog call back. An example of DialogProc looks likes this:
BOOL DialogProc( HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam ){
switch( iMessage ){
case WM_COMMAND:
switch( LOWORD( wParam ) ){
case BTOK:
MessageBox( hDlg, "Hello, World!", NULL, NULL );
return TRUE;
break;
}
break;
}
return FALSE;
}
This is a basic way of creating a dialog. More sophisticated method would normally involve OOP, usually wrapping each resource( button, window, etc) as a C++ object or using MFC.
If you have placed your button or any control on some dialog, that control is already in created state. For handling the messages of these child controls on this dialog , you have to override OnCommand Method in the class which is implementing your dialog.
For Example:
//CDialog_ControlDlg is my Dialog class derived from CDialog
//IDC_BUTTON_SAMPLE is the ID of the button which was palced on the dialog in the resource Editor..
BOOL CDialog_ControlDlg::OnCommand(WPARAM wParam,LPARAM lparam){
int iNotiFicationMsg=HIWORD(wParam);//This is thenotification Msg from the child control
int iCommandId=LOWORD(wParam);//And Control ID of the Child control which caused that Msg
BOOL result=FALSE;
switch(iCommandId){
case IDC_BUTTON_SAMPLE:
if(iNotiFicationMsg==BN_CLICKED)
{
//Your Code for handling this type of Msg for this control..
}
break;
default:
{
//Specific Code;
}
return result;
}
}

C++: How to center MessageBox?

Using Visual Studio C++ with MFC. How do I center a MessageBox to it's parent window? Currently it centers to the desktop.
You need to install a hook and change the dialog box position on creation.
int MessageBoxCentered(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
// Center message box at its parent window
static HHOOK hHookCBT{};
hHookCBT = SetWindowsHookEx(WH_CBT,
[](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT
{
if (nCode == HCBT_CREATEWND)
{
if (((LPCBT_CREATEWND)lParam)->lpcs->lpszClass == (LPWSTR)(ATOM)32770) // #32770 = dialog box class
{
RECT rcParent{};
GetWindowRect(((LPCBT_CREATEWND)lParam)->lpcs->hwndParent, &rcParent);
((LPCBT_CREATEWND)lParam)->lpcs->x = rcParent.left + ((rcParent.right - rcParent.left) - ((LPCBT_CREATEWND)lParam)->lpcs->cx) / 2;
((LPCBT_CREATEWND)lParam)->lpcs->y = rcParent.top + ((rcParent.bottom - rcParent.top) - ((LPCBT_CREATEWND)lParam)->lpcs->cy) / 2;
}
}
return CallNextHookEx(hHookCBT, nCode, wParam, lParam);
},
0, GetCurrentThreadId());
int iRet{ MessageBox(hWnd, lpText, lpCaption, uType) };
UnhookWindowsHookEx(hHookCBT);
return iRet;
}
::AfxMessageBox() appears on the center of the MainFrame for me. Which is basically a call to ::MessageBox() with a handle to the MainFrame as the first parameter. Isn't that working for you?
You can't. That's why a lot of people write their own MessageBox classes.
Who said "can't"?
Try this:
This is for Win32 API, written in C. Translate it as you need...
case WM_NOTIFY:{
HWND X=FindWindow("#32770",NULL);
if(GetParent(X)==H_frame){int Px,Py,Sx,Sy; RECT R1,R2;
GetWindowRect(hwnd,&R1); GetWindowRect(X,&R2);
Sx=R2.right-R2.left,Px=R1.left+(R1.right-R1.left)/2-Sx/2;
Sy=R2.bottom-R2.top,Py=R1.top+(R1.bottom-R1.top)/2-Sy/2;
MoveWindow(X,Px,Py,Sx,Sy,1);
}
} break;
Add that to the WndProc code... You can set position as you like, in this case it just centres over the main program window. It will do this for any messagebox, or file open/save dialog, and likely some other native controls. I'm not sure, but I think you may need to include COMMCTRL or COMMDLG to use this, at least, you will if you want open/save dialogs.
I experimented with looking at the notify codes and hwndFrom of NMHDR, then decided it was just as effective, and far easier, not to. If you really want to be very specific, tell FindWindow to look for a unique caption (title) you give to the window you want it to find.
This fires before the messagebox is drawn onscreen, so if you set a global flag to indicate when action is done by your code, and look for a unique caption, you be sure that actions you take will only occur once (there will likely be multiple notifiers). I haven't explored this in detail, but I managed get CreateWindow to put an edit box on a messagebox dialog. It looked as out of place as a rat's ear grafted onto the spine of a cloned pig, but it works. Doing things this way may be far easier than having to roll your own.
Crow.
EDIT: Small correction to handle the problem raised by Raymond Chen. Make sure that parent handles agree throughout, and this should work ok. It does for me, even with two instances of the same program...

SetWindowLongPtr doesnt work properly

I want to subclass RichEdit in my program (here is c++ code: http://dumpz.org/46182/). _native_log is a hwnd of richedit. At first all works fine and LogWindow::wndProc callback called normal, but if i set some text in RichEdit or click on them LogWindow::wndProc stops work (there no any further calls of it). Is there any thoughts what's i do wrong?
void LogWindow::replaceNativeLog(HWND native_log_handle) {
_native_log = native_log_handle;
SendMessage(_native_log, EM_GETOLEINTERFACE, 0, (LPARAM) &_rich_edit_ole);
_old_wnd_proc = (WNDPROC) SetWindowLongPtr(_native_log, GWLP_WNDPROC, (LONG) &wndProc);
}
LRESULT LogWindow::wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case EM_STREAMIN:
break;
case WM_SETTEXT:
break;
};
return CallWindowProc(_old_wnd_proc, _native_log, Msg, wParam, lParam);
}
Starting with Common Controls version 6 the procedure of subclassing windows has been revised to eliminate the issues with previous versions. In particular it is no longer a problem if a control is subclassed more than once.
A comparison between subclassing pre-v6 Common Controls and the v6 way of doing things can be found at "Subclassing Controls". Instead of calling SetWindowLongPtr to replace the window procedure there is SetWindowSubclass which in addition to replacing the window procedure does all the internal bookkeeping. A consequence of the redesign is that you do not have to store a pointer to the previous window procedure either; if you need to call into the original window procedure there is DefSubclassProc at your disposal.
This of course will only help if all competing clients trying to subclass the a control all agree on using the v6 style subclassing.
Finally, I found the problem. I actually develop a plugin for Miranda IM, and there was another function trying to subclass richedit i want. So there is a kind of conflict between my and that functions. Thanks all for trying to help.