CDialog not Receiving Windows Messages in ActiveX Control - mfc

I have an ActiveX control in MFC that manipulates images and I am trying to add TWAIN scanning functionality to it.
I need to be able to receive a Windows Message back from the TWAIN driver that tells my control when an image has been scanned, so I have created a CDialog and I pass the HWND of the Dialog to the driver.
ALl the sample code I have seen on the net then uses PreTranslateMessage to capture the message from TWAIN, but in my ActiveX control this method is never being called.
Does anyone know how I can get the messages for that Dialog? I have also tried using PeekMessage with no success.
Many Thanks

You don't need to create a CDialog. You just need any window to process the messages. Anything dealing with TWAIN is best handled in its own thread. So, create a new thread for MFC (via CWinThread or AfxBeginThread). In that thread, create a CWnd. The HWND of this CWnd is the one you will pass with all the calls to the DSM, etc. Each thread has its own message queue, so set one up in there. Communicate with that thread via PostMessage, SendMessage, PostThreadMessage, etc. Assuming you post a message MY_SPECIAL_MESSAGE to signal to being acquiring an image, your message loop should look something like this:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == MY_SPECIAL_MESSAGE)
{
GetImageFromTWAIN();
}
else if (!ProcessTWAINMessage(&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Definitely look at the source code in the TWAIN development kit to see how this all works in detail. TWAIN is a tricky creature.
Trust me, this is the best approach. You can do it all in a single thread using your main thread's message queue, but it's to be avoided.

Related

::PostMessage doesn't work when I am tabbed in to another program

In our Program we have a Dialog from a separate dll open to display infomation. I need to close this dialog when our system timer causes the system to lock.
I send information to the dll by registering a system message in both my MainFrm and EditDisplayDll
SYSTEMLOCK = RegisterWindowMessage("SystemLock");
When I sent the message via
::PostMessage(GetActiveWindow()->m_hWnd,SYSTEMLOCK,0,0);
The message correctly sends to my EditDisplayDll and closes the dialog when the system locks; however, if I alt tab while waiting for the timeout and use another program(firefox, outlook, etc.) the message never correctly calls to the EditDisplayDll. The MainFrm and other windows inside of the MainFrm correctly lockout and hide themselves in either case.
I have tried also using HWND_BROADCAST with PostMessage and SendNotifyMessage. I have also tried to use FindWindow() and FindWindowEx() to specifically call the EditDisplayDll.
I cannot use something like GetDlgItem() because my MainFrm.cpp doesn't have access to this dll.
My decision to use GetActiveWindow() was because I believe it looks to windows specific to my program no matter what window I am in as seen in the imagery in Foreground Vs Active window
Finally, my question is, is there a way to call all Windows in my program no matter what program I am currently in or is there another way I could get access to the specific IDD of the EditDisplayDll in order to send the SYSTEMLOCK message to it?
CWnd *cWndED = FindWindow(_T("EditDisplay"),_T("EditDisplay")); HWND
hwnd = (HWND)cWndED;
You should use win32 API ::FindWindow with proper class, window name. And do not cast CWnd pointer to HWND. Your code should look like:
HWND hWnd = ::FindWindow(_T("ProperClass"), _T("ProperNmae"));
if (hWnd != NULL)
{
::PostMessage(hWnd, YOUR_MESSAGE, ....);
}
I will suggest you to find your Dll window class and name using Spy++ and then try to find that using above method. Remember it's always better to use native API for this kind of tasks.
FindWindow is a good solution if you know both, name of the window and the element.
If you want to get the HWND of your window - no element inside the window -, you can pass as first parameter NULL.
::FindWindow(NULL, _T("WindowName"));
Back to your code: If you are lucky your PostMessage does nothing, otherwise the active window may catch your message. Who knows how/if it is handled in the active window ? Use the PostMessage if you have a valid IsWindow(HWND) from FindWindow or FindWindowEx.
In case you want a CWnd from your HWND take a look at this. (The call may be slow)
HWND hWnd = ::FindWindow(_T("ClassName"), _T("WindowName"));
if (hWnd && IsWindow(hWnd))
{
::PostMessage(hWnd, MESSAGE_TO_BE_SEND, lParam_or_Flags);
}

I want to print a text on MFC Dialog

I made a thread to set some text on EditBox on Lobby Dialog. Below is my code.
And MainLobby is the Dialog Class. This project is "Dialog Based MFC Project".
MainLobby Lobby;
_beginthreadex(NULL, 0, ReceiveMessage, (void *)Lobby.GetSafeHwnd(), 0, NULL);
Lobby.DoModal();
But it doesn't work. Where is wrong? I thought hard but I couldn't find the answer.
I tried not Lobby.GetSafeHwnd() but Lobby.m_hwnd
unsigned WINAPI ReceiveMessage(void *arg)
{
HWND hDlg = (HWND)arg;
char msg[BUF_SIZE];
int msgLen;
while( (msgLen = recv(CClientApp::hSocket, msg, BUF_SIZE, 0)) != 0 )
{
SetDlgItemText(hDlg, IDC_LOBBY_CBOX, msg);
}
}
I am using MFC now. I will be glad a good idea.
The device context has to be updated.
Try:
UpdateData(true);
SetDlgItemText(hDlg, IDC_LOBBY_CBOX, msg);
UpdateData(false);
Or try it with a CString member variable for IDC LOBBY CBOX.
It is clear from your code that you are not using MFC properly. A Windows dialog based application does not require the programmer to explicitly create message handlers or receivers, that is what the MFC framework itself is doing for you. There is no reason to call beginthreadex before starting the dialog message loop as part of the DoModal method. When you invoke DoModal on any class descended From Dialog or DialogEX, the window is constructed, the member objects are constructed, and the message loop is started before the WM_INITDIALOG message is sent to the dialog for any other initialization before the dialog window is displayed. Once the window is displayed, the message loop is running, and text will display automatically in an edit control when you send it correctly. Normally one would declare a CEdit object with some name using the Class Wizard in visual studio then map the MFC object to the dialog object. Rather than type out all the details I will refer to this article: http://msdn.microsoft.com/en-us/library/6d1asasd.aspx
The dialog's HWND has not been initialized before DoModal is called. So your thread does not receive the proper HWND. The first place that you can access the correct HWND value is inside the dialog's OnInitDialog member function.
I see two problems in your code.
First you are calling Lobby.GetSafeHwnd before DoModal, so before the window is constructed. You should move the thread creation to the WM_INITDIALOG handler of MainLobby to create the thread there. Or you could create a modeless dialog.
Second you are using _beginthreadex in your MFC code. If you are starting a thread that uses MFC, then you need to start that thread with AfxBeginThread. If you only use CRT, then you use _beginthreadex. If you use neither, then use Windows CreateThread. The reason for this is that each layer (CRT, MFC) needs to do some housekeeping of thread specific information. This can only be done if you call the proper thread creation functions.
Third, you might consider using the MFC socket objects like CAsyncSocket. This object can send windows messages to your dialog if some data is available on the socket. This perfectly fits into your scenario with an MFC dialog that should handle socket data.
Another thing, but you already got that right: to access an MFC GUI object you need to be in the thread of that GUI object. So calling the Windows SetDlgItemText with the raw handle hDlg needs to be done, you cannot call an MFC function here.
BTW, are you sure your overall strategy is right? I don't see how you handle dialog life time, socket life time and how you put both together.

How to Cleanly Destroy WebBrowser Control

I am using ATL in VisualC++10 to host browser control.
My code is similar to this example: http://msdn.microsoft.com/en-us/library/9d0714y1(v=vs.80).aspx
Difference is I have main window and then child window hosts the browser control.
After 2 minutes i have to close the browser completely kill the browser activeX but this child window should be alive and do something else. But somehow this browser control still stays there, i can either see scrollbars or something..
I have also tried by creating child window to an existing child window, and at the time of closing browser I then destroy this child of a child - but still it does not work!
This is how I am closing:
CLOSE()
{
m_spIWebBrowser2->Navigate(bstrURL, &vEmpty, &vEmpty, &vEmpty, &vEmpty);
m_spIWebBrowser2->Stop();
m_spIWebBrowser2->put_Visible(VARIANT_FALSE);
m_spIWebBrowser2->Quit();
DestroyWindow(m_wndChild.m_hWnd);
}
Thanks!
I had many problems with "access violation" when closing webbrowser control, these are the steps that worked for me:
Unadvise any previously advised events (DWebBrowserEvents2 in my case).
If you've attached click events unattach them like this: _variant_t v; v.vt = VT_DISPATCH; v.pdispVal = 0; IHTMLDocument2->put_onclick(v);
IWebBrowser2->Stop()
IWebBrowser2->ExecWB(OLECMDID_CLOSE, OLECMDEXECOPT_DONTPROMPTUSER, 0, 0) - when closing browser window through window.external.CloseWindow() I had unhandled exceptions and OLECMDID_CLOSE fixed it.
IWebBrowser2->put_Visible(VARIANT_FALSE)
IWebBrowser2->Release()
IOleInPlaceObject->InPlaceDeactivate()
IOleInPlaceObject->Release()
IOleObject->DoVerb(OLEIVERB_HIDE, NULL, IOleClientSite, 0, windowHandle_, NULL)
IOleObject->Close(OLECLOSE_NOSAVE)
OleSetContainedObject(IOleObject, FALSE)
IOleObject->SetClientSite(NULL)
CoDisconnectObject(IOleObject, 0)
IOleObject->Release()
IWebBrowser2->Quit() should not be called for WebBrowser control (CLSID_WebBrowser), it is intended only for Internet Explorer object (CLSID_InternetExplorer).
Why must it be so hard?
My experience is that some calls might need message processing to function properly. Try to pump some messages between your calls to Navigate, Stop etc. When working with the web browser interfaces I PostMessage myself often to trigger the next step to make sure the previous step had time to complete.
The problem might be related to your child thread. You cannot access web browser interfaces between threads without some additional work. COM needs to be initialized as single-threaded apartment (STA). And you need to follow the rules of STAs:
Every object should live on only one thread (within a single-threaded apartment).
Initialize the COM library for each thread.
Marshal all pointers to objects when passing them between apartments.
Each single-threaded apartment must have a message loop to handle calls from other processes and apartments within the same process. Single-threaded apartments without objects (client only) also need a message loop to dispatch the broadcast messages that some applications use.
...
If I use DialogBox and drop a IEControl on it as a resource and DialogBox is derived from CAxDialogImpl<> - then while I call DestroyWindow() of dialogBox then it is automatically doing the cleanup() - which is what I required.
But originally I wanted to get rid of DialogBox itself and use IEControl directly on my Window, it seems not..

Can I use my own message loop in windows?

I am building a C++ program, on windows, using Visual Studio. It relies on a COM base API, that sends windows message for notification.
To process those messages, I see two possibilities:
Create a windows form and call doModal on it which should process the messages, but since I don't want to use any UI, it's not what I want to do
make my own loop for processing messages
I don't know what is best, or if there is another way to process the messages (there is probably a windows function that can launch the loop)
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
It is not just for your own benefit, COM requires you to create a message loop. COM needs it to handle apartment threaded COM servers, an expensive word for "components that don't support multi-threading". The vast majority of them don't.
It is best to create a window, it doesn't have to be visible. That gives you a HWND that you can use in your SendMessage() calls. The window procedure you write can process the messages. From there, it gets to be easy to create a minimal user interface, with Shell_NotifyIcon for example. Always nice when you can display a notification when something goes wrong. So much better then an event in a log that nobody ever looks at.
Yes, you can. Every thread can have one message loop and you don't need any windows to receive messages or send them (see PostThreadMessage).
There is nothing wrong with using this method if your application is event-driven.

keep a formless application from closing for a keyboard hook

I am working on a c++ win32 program that involves a keyboard hook. The application is a win32 project with no user interface whatsoever. I need to keep the application from closing without using causing the hook to not work or use up a bunch of system resources. I used to use a message box but I need the application to be completely invisible.
Any help would be appreciated!
If you have any questions just ask.
I think what you need is message only window
(MSDN says) A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
Do you really need windows?
The MSDN LowLevelKeyboardProc page recommends using a simple message loop.
Just insert this snippet after the hook call.
// message loop to keep the keyboard hook running
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
A better way would be to add an loop that keeps going around.
bool shouldExit = false;
do
{
//some code to handle events
shouldExit = handleEvents();
//sleep for a small bit so we dont take up 100% cpu
sleep(500);
}
while (!shouldExit);