First of all, here's my config:
VS2010/Debug/C++ Win32 Project/Vista Home Premium
Invoking GetOpenFileName via a button (CreateWindow) in a window (CreateWindow) gets me no problem: The Open Dialog works fine, I can click, navigate to another folder etc...
Now, I replace my CreateWindow with a DialogBoxParam (that should call CreateWindow behind the scenes), with the same (DLGPROC)WndProc and invoke the same GetOpenFileName. Here, the Open dialog is behaving strangely: looks like only the mouse double-click works (= populating ofn.lpstrFile and closing the Open dialog). Not able to click the Open and Cancel buttons and not able to navigate.
Anyone having experienced this before? Any known reasons for the Open dialog to kind of "freeze". Belong to a parent or not (ofn.hwndOwner = hwnd; ofn.hwndOwner = NULL;) gives the same problem.
Thanks
N
You wrote
with the same (DLGPROC)WndProc
That's your bug. A dialog procedure and a window procedure are not the same thing. They follow different rules, and if you follow WndProc rules when you should be following DlgProc rules, then bad things will happen.
Related
I'm using and improving on an open source MFC work-alike library called FFC. Sometimes the library associates the wrong window handle to a dialog object, which means the C++ object can't be found later when the correct handle is looked up. In particular, this is happening when the application opens its root window, which is a dialog that it opens with a call to DoModal.
In its DoModal function, the FFC library uses a... "surprising" way to attach the handle to the dialog object. It stashes the "this" pointer in a global variable and hooks a function to be called on all window messages before calling the DialogBox function. This hook function it registered in term assumes the handle from the first message it receives is the handle for the window in the global variable, and attaches that handle to it.
Sometimes, this works. Often - and I don't know if it's because of intrusive things done by the McAfee scanner on my work computer, or because my program starts from a console window, or something else - many unrelated messages will be captured before a message actually meant for the modal dialog comes through.
At first I thought it was because FFC wasn't making sure the message it looks for is "WM_CREATE". I added this check, but it didn't fix the problem. Turns out one or more of the spurious messages are also WM_CREATE messages! Before it gets the one for the real dialog, the first WM_CREATE it receives is a handle for a window with blank window text and rectangle 0,0-0,0.
So is this really the correct or canonical way to get the handle for a modal dialog? It seems unreliable. (Note that because the dialog is modal, you can't use the return value from CreateWindowEx because the DialogBox function doesn't return until the modal dialog is closed.) Is this really how MFC does it? Is there a better way? Could I associate some data with the dialog or look for data that should be associated with it to make sure I have the right window handle? (For instance checking the template parameter passed to the dialog box call, if I can get that back from the handle somehow.)
I am sure this is published in books, but MFC sets a windows hook (WH_CBT) and then looks for the HCBT_CREATEWND code in the hook to marry the C++ object to the HWND.
I use CreateDialog to create a modeless dialog in SetSite method after get the IWebBrowser2 interface. The dialog resource is in the BHO dll. When create a new instance (I mean doble click the IE shortcut) of IE the creation is successful but when I create a new tab the creation is failed (but in other computer it is successful). there is also something strange is that sometimes create a new tab will also create a new IE process but sometimes will not.
This is the code for dialog creation:
bool MyDialog::Create(MyContext *ls)
{
extern HINSTANCE hInstance; // handle of BHO dll
m_hDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDLG),ls->GetBrowserMainWnd(), MyDlgProc);
if (m_hDialog) {
SetWindowLong(m_hDialog, GWL_USERDATA, (LONG)ls);
SetTimer(m_hDialog, 1, 1000, NULL);
return true;
}
return false;
}
I think this has something to do with dialog creation in different UI thread but not sure about this. Hope somebody can help me with this problem. Thanks a lot!
Update 2014-03-31:
The GetBrowserMainWnd method call IWebBrowser2->get_HWND to get the main window handle. But for IE7 and later the introduced tabbed window makes things complex as MSDN's description:
"Internet Explorer 7. With the introduction of tabbed browsing, the return value of this method can be ambiguous. To alleviate confusion and maintain the highest level of compatibility with existing applications, this method returns a handle to the top-level window frame, not the currently selected tab."
So, I use the example code (refer to http://msdn.microsoft.com/en-us/library/aa752126(v=vs.85).aspx) solved this problem.
It seems that the root cause is the third parameter hWndParent. When I set it to NULL this problem disappear. I think the new process of an IE tab can't access the IE main window handle so failed with error code 5.
I have a dialog IDD_WINDOW_INFO that has to be opened when the user clicks a button or a menu item in my C++ Win32 application. The method that I use to open the dialog is in the following line:
DialogBox(hInstance, MAKEINTRESOURCE(IDD_WINDOW_INFO), hMainWindow, WindowInfoProc);
but my problem is that when that dialog box opens, the user cannot operate with the main window of my application. So what can I do to have both windows active?
You are calling DialogBox which shows the dialog modally. When a modal dialog is shown, the other owning windows are disabled and only the modal dialog can accept input. That is the very essence and intent of a modal dialog. The idea is that you can interact only with the dialog, and cannot interact with the other windows.
Another answer suggests passing NULL as the hWndParent parameter to DialogBox. That's not the solution. That will result in you having an unowned window. Yes, you will be able to interact with the main window, but when you do so your main window will appear on top of the dialog. That's because the ownership is set incorrectly. I recommend that you read about window ownership to better understand the issue.
The correct solution to your problem is to show a modeless dialog. A modeless dialog allows you to interact with the other windows in your application. And that's exactly what you ask for in the question.
You show modeless dialogs by calling CreateDialog followed by ShowWindow. This MSDN article shows an example: Using Dialog Boxes.
If I recall correctly, you can either pass NULL instead of the handle to the parent window or change the dialogbox type in the resource editor.
That is an easy way to do it, however the following is certainly better - since having an unowned dialog isn't your best choice.
The point is that DialogBox() will create a modal dialog window, while CreateDialog does not. Modal dialogs disable the parent window.
From MSDN: A modeless dialog box neither disables the owner window nor sends messages to it.
That should solve your problem.
CreateDialog(hInstance, MAKEINTRESOURCE(IDD_WINDOW_INFO), hMainWindow, WindowInfoProc);
ShowWindow(hWnd, SW_SHOW);
I would like to use c++ without mfc(and not clr) in order to modify textbox's and activate a button on a form outside of my project. I don't know where to start. I've done a lot of searching but can only find information for VB. A starting point would help.
Thanks.
I tried this and it doesn't seem to work.
HWND fWindow = FindWindow(NULL ,(LPCWSTR)"title");
and I also tried this
HWND fWindow = FindWindow(NULL ,LPCWSTR("title"));
I ALSO tried using LPTSTR instead of LPCWSTR, incase it was a unicode deal.
Maybe I don't understand this microsoft LPCWSTR and LPTSTR crap.
I also tried
HWND fWindow = FindWindow(NULL,TEXT("title"));
and that didn't work.
I guess the windows api must just be broken.
I tried the function on other programs...I'm using xp and I tried catching the calculator, and an explorer window, and something else. But I got nothing.
Heres some of the exact code I'm using to try and figure this out.
HWND face = NULL;
face = FindWindow(NULL,TEXT("My Computer"));
LPSTR title = TEXT("");
GetWindowText(face,title,250);
if(face != NULL)
{
MessageBox(NULL,title,TEXT("WOOP"),1);
}
face = nothing.
title = ""
Bear in mind, I'm not actually trying to hook explorer, I just want to figure out how to get it to work.
Use spy++ or winspector to see the actual "text" of the window.
(Strictly speaking, the caption of the window need not match it's window text. Especially true of "fancy" windows which paint their own caption.)
The following works fine for me (using Calc.exe to test).
HWND hwnd = NULL;
hwnd = FindWindow(NULL,_T("Calculator"));
TCHAR title[251];
if(hwnd != NULL)
{
GetWindowText(hwnd,title,250);
MessageBox(NULL,title,_T("WOOP"),MB_OK);
}
else
MessageBox(NULL,_T("No such window."),_T("OOPS"),MB_OK);
Edit: You should have used _TEXT instead of TEXT.
One way to do this is to use FindWindow to get a handle to the form. Then if you know the button and edit window Ids, you can use GetDlgItem to get their window handles. If you dont know the ids, you can use EnumChildWindows to examine all of the controls on the form.
Once you have the window handles for the controls, you can use SetWindowText to set the text on the edit control, and send a WM_COMMAND message to the form window with the button ID as the command value to make the form think that the button has been clicked.
There are a lot of ways to go about this once you have the correct window handles. There are security issues when you use the window handles of another process, but if the process isn't secured, then inter-process use of window handles just works. For a secured process, you won't be able to find out the window handles.
The windows API provides Methods for this. These should be independent of MFC and CLR, as they are plain win32. I had a project once accessing the Form fields of an Applictation from a loaded DLL (don't ask why).
you might want to look here (Codeproject)
or here (msdn)
At first, you need to obtain a handle to the process you want to access.
When have this, you can use GetDlgItem() (search msdn for that) to retrieve a handle to the desired textbox.
With this handle, you should be able to modify the control in question.
If your trying to get big (and do some more UI automation), you sould have a closer look at these:
Microsoft Active Accessibility
IAccessible2
Microsoft UI Automation
Windows Automation API (Win7)
I have a dialog (CDialog derived class) that can be used in two different ways (edition mode and programming mode).
When the dialog is open to be used in programming mode it is a modeless dialog that it is used for modifying the main view (kind of a toolbar). When it is open in edition mode the user can change the configuration of the dialog itself and in this case it is a modal dialog.
Right now they are two different dialogs with few differences and I would like to have just want dialog and let the user change between programming mode and edition mode just by pressing a button in the dialog.
So I need to convert the modeless dialog in a modal dialog and vice versa at runtime. Is there a way to achive that?
Thanks.
As maybe someone could be interested in doing something similar in the future, this is the way I eventually did it:
I use this two functions of main frame: CMainFrame::BeginModalState() and CMainFrame::EndModalState().
The problem with these functions is the same that with disabling the parent window. The window you want to make modal also gets disabled. But the solution is easy, just re-enable the window after calling BeginModalState.
void CMyDialog::MakeModal()
{
//disable all main window descendants
AfxGetMainWnd()->BeginModalState();
//re-enable this window
EnableWindow(TRUE);
}
void CMyDialog::MakeModeless()
{
//enable all main window descendants
AfxGetMainWnd()->EndModalState();
}
Thanks for your help.
That can't be done easily without closing and reopening the dialog. Then you can call ShowWindow or DoModal as appropriate.
That is not correct. This can be done, if you look at MFC's source you will realize that it's modal dialogs are not technically even modal. You will have to do a lot of mucking about to make this work properly, but basically you just have to disable the parent of the 'modal' window, and re-enable it when the 'modal' window closes.
I have done this personally so this may work for you, though I am not exactly sure what you are trying to do.