I've got a bit of a problem with my application using MSHTML. I have everything working except for the odd keystroke missing behavior when typing fast as mentioned in the subject line. I think it may have to do with the method I use to sink the events?
The details: my application is a separate program written in C++ and MFC in Visual Studio 2005. The program attaches to a currently running (independent) instance of Internet Explorer and gets the pointer to the IWebBrowser2 interface and passes it to an object of type CCmdTarget:
class CHandler : public CCmdTarget
{
IWebBrowser2* m_pWebBrowser2;
DWORD m_dwBrowserCookie;
…
DECLARE_DISPATCH_MAP()
};
This class keeps track of what's happening in the browser. I sink the browser events with the following command:
LPUNKNOWN pUnkSink = GetIDispatch(FALSE);
retval = AfxConnectionAdvise((LPUNKNOWN)m_pWebBrowser2, DIID_DWebBrowserEvents2, pUnkSink, FALSE, &m_dwBrowserCookie);
If I comment out the AfxConnectionAdvise, then no keystrokes are missed but no more events. If I leave it in I sink the events but miss the occasional keystroke if typing fast.
I know there are a number of ways of connecting to the events (AtlAdvise, connection points), but this was the only one I could get working.
Any suggestions would be great!
If you're just looking for keystrokes, can't you subclass the control?
Underneath the covers all the various connection methods (AtlAdvise, AfxConnectionAdvise, etc) all use IConnectionPointContainer and IConnectionPoint — they're just saving you typing boilerplate COM goo.
I suspect this has to do with how you're connecting to the running instance of IE. How are you getting the IWebBrowser2 pointer? Are you being loaded into the IE process or are you a separate process? If you're running on a different thread than the IWebBrowser2's original thread (the IE Tab UI thread), are you doing proper COM marshalling?
Related
C++, WinRT, VS2017 MFC, Win10
I have a C++/WinRT VS2017 console app as a test platform to find my Bluetooth LE device, enumerate the services and characteristics, and then write a value to the Tx characteristic, etc. I have all of that working and now I am trying to move that code to an existing VS2017 MFC app.
In the console app the BluetoothLEAdvertisementWatcher and callback to the watcher.Received() were done in the main.cpp. Once my BLE device was found, a separate function was called to create the device object from the deviceAddress and then enumerate the services and characteristics.
In the MFC app I created a separate function run in a separate thread to establish the watcher and attach the callback. That all works fine up to the point that it needs to GetGattServicesAsync(). In the console app the function OpenDevice() used to create the device object and get the services was done with a get() as in:
OpenDevice(deviceAddress).get();
The first thing OpenDevice() does is create the device object using
auto device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(deviceAddress);
If the device object is created, then the next thing it did was get the Services with:
auto services = co_await device.GetGattServicesAsync();
Here is where my MFC code fails. In the function thread that creates the watcher and watcher.Received callback my MFC code does the same call to OpenDevice(). In OpenDevice the device object is indeed created but then the call to GetGattServicesAsync() will never finish so matter how long I wait. If I enter the GetGattServicesAsync() in Debug mode, however, then it works fine.
For testing I have also put the OpenDevice() code within the watcher thread but, again, it stalls on GetGattServicesAsync().
In this case, however, I cannot use the co_await but had to use
auto services = device.GetGattServicesAsync().get();
Regardless, the GetGattServicesAsync() never finished.
Any suggestions of what I need to do or what I am doing wrong?
Since running in Debug was working I was trying to solve why this was not working in Release mode. I was relying on my log file entries to track the progress after the fact. For the halibut I put in some Beeps() to let me hear the progress and I was hearing beeps but not seeing log entries after that GetGattServicesAsync(). Apparently what was happening is that, for what ever reason, the GetGattServicesAsync() was NULLing out the handle to my log file so no writes were taking place. I did a check for NULL after the GetGattServicesAsync() and, if it was, re-established the log file. All of a sudden my log file was showing the progress that I thought was not happening. Sometime I think it is just me...:-(
We currently have a Silverlight UI (which we are unable to change from at this stage) for our system, which has very limited drag drop capabilities. We are currently running out of browser with elevated trust. So in order to handle Silverlight's shortcomings I have created a c++ com library in order to handle Drag Drop events. This works perfectly well for incoming events from other applications, however I'm struggling to get the Drag operations, with our app as the source, working correctly. Most of the files to be dragged from the app will be virtual, which I have managed to get working however regardless of everything I've tried I have been unable to get the operation to be asynchronous, and the app locks up during the process.
I initially implemented only the IAsyncOperation (need backward compatibility to xp), which had no apparent affect. My DataObject is queried for the interface, gets the ref. A Call to GetAsyncMode is made, which returns VARIANT_TRUE, and a call to StartOperation is made. However all operations are done on the same thread (ui thread) and no async seems to be in affect.
I Subsequently tried implementing ICallFactory to return an AsyncIDataObject. Here explorer seems to check for the ICallFactory interface, calls the CreateCall on the call object and queries it to make sure it has the correct interfaces. Using the symbol servers I am able to see that it this occurs in the AsyncStubInvoke call stack. From here a call to StdStubBuffer_QueryInterface is made which is searching for the ICallFactory interface. This check fails and I unfortunately cannot see what object is being checked for this interface. After this fails the call seems to fall back to SyncStubInvoke after an operation not supported error (following from the Interface not supported error). All of this too seems to have no effect on the end result and the call is still apparently synchronous with the source app locking up.
My DragDrop class which exposes the com calls is CComMultiThreadModel. I have tried using my DataObject as a basic class not inheriting from CComObjectRootEx and a wrapper IDataObject class which is defined in the IDL as well and does inherit from CComObjectRootEx as is also CComMultiThreadModel. I have also tried having this class inherit from IDispatch as well as IUnknown.
Any feedback would be greatly appreciated.
I have written a simple dialog based MFC application using a thirdd party soft tree control. I am trying to write a automation client for the application. For this I wrote a singleton out-of-process COM Testing Agent for the dialog based application sample app. The Com server exposes a Run method to the automation client. This Run method access the gut of the mfc app and actually mimicks a click on the GUI. The problem i am facing is when the automation client tries to invoke Run method on the Com object it is able to invioke it but when the Run method crashes when it tries to access the control's methods such as getCaretInedx.
I have tried to cach the exception and log the message to a file but have not been able to do so.
My question is: Is there any limitation in the way a com object can access the application? Or am i missing anything to facilitate this.
Any help or pointer is greatly appreciated. Since this is my first in COM I have not been able to make much progress.
Thanks
Is your client's window actually being created? If not, the hwnd doesn't exist, which is probably why it crashes. Furthermore, your client may be hidden behind another window when it is started, and may exhibit different behavior than when the user called it through regular interaction.
In general, calling code that relies on or interacts with the UI from a COM server is fraught with peril, especially when that code is not written in the first place to behave like this. Most UI isn't that defensive about HWND's existing etc.
I am having a problem with the program I am currently working on. It is caused by the increased security in vista/Windows 7, specifically the UIPI which prevents a window with a lower integrity level 'talking' to a higher one.
In my case, i am wanting to tell the window with a high Integrity level to move into our application, It works flawlessly on XP or windows 7 with the security off.
I have tried setting the HWND of the higher IL window directly, rather than using the findwindow() function, this works fine but the program then fails when trying to move it or generally interact with it. The windowhandle is saved by the app to be embedded and read by the app running at a lower IL.
I have also tried setting UIaccess in the manifest to TRUE and digitally signing the program but no luck.
Any ideas on how to solve this problem?
thanks.
Just thought i would follow this up for anyone who also struggled as I have finally found a way to do this.
IL = Integrity Level.
I had 2 apps, highIL.exe and lowIL.exe, the highIL wanted to find the lowIL.exe window, set it as a child window and move it into a zone created for it on the highIL.exe. This was blocked by the UIPI in vista+.
In the end i used the ChangeWindowMessageFilter method in vista and the ChangeWindowMessageFilterEx in Windows7, both found in the user32.dll. These functions allow you to poke a hole in the UIPI to allow messages that you want through.
I created a few custom messages using RegisterWindowMessage function, I used this function to register the method in both highIL and lowIL applications, the line looked a little like this:
const UINT MY_MOVEINTWINDOW_MSG = RegisterWindowMessage(_T("MyMsg.MoveWindow"));
The lowIL.exe is then able to send these messages to the highIL.exe window without them being blocked. Then it was a case of just simply adding and writing message handlers.
This method will only work if you have access to both the high and low IL.
The MSDN also has a working example of the ChangeWindowMessageFilterEx function on there Website
What's the approved way to handle second, third, etc launches of application in Windows (C++) application? I need the running (first) instance to take some special action (pop up a dialog) in this case, but for the secondary instances to terminate.
On Mac, AppleEvents sends you a 're-open' message in this scenario. Mozilla on Windows uses DDE to check for an existing instance and pass the command line through. It feels like a pretty nasty solution, all the same.
The windows way is to open a named mutex and, if you can acquire it, it means you're the first instance, if not, there is another one. At this point you can register a windows message (the function is literally RegisterWindowsMessage) which gives you a WM_ msg you can send to all windows and only your app would know to catch it, which allows you to tell your initial copy to open a dialog box or w/e.
How to limit 32-bit applications to one instance in Visual C++
"The method that is used in this article is the one that is described in MSDN under the WinMain topic. It uses the CreateMutex function to create a named mutex that can be checked across processes. Instead of duplicating the same code for every application that you will use as a single instance, the code that you must have is in a C++ wrapper class that you can reuse across each application."
SendMessage Function
"Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message."
"Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication."
RegisterWindowMessage
"The RegisterWindowMessage function defines a new window message that is guaranteed to be unique throughout the system. The message value can be used when sending or posting messages."
On windows there is not really solution for that at least not out of the box.
You can use mutex to do such things, basically the app check for the mutex at startup create it if it doesn't exist.
There is one issue with CreateMutex method that you might need to consider - the named mutex might have been created by a third party. Now, most of the time, this won't be an issue, there would be no reason for someone else to block your application. However, if you're making a program that does something important, it may be an issue. Consider, if your program was a virus scanner, a virus could disable it by creating the mutex.
Usually, CreateMutex should do the job, but you should be aware of the limits of this method.