How can I programmatically activate an OLE control via COM interfaces?
I have an application which embeds a button control via Ac开发者_Go百科tiveX. The button was provided by a third party, and it implements a whole range of ActiveX interfaces (among which is IOleInPlaceObject
). I do have an reference to the IUnknown
implementation of the button.
The problem I'm facing is that the IOleWindow::GetWindow
function provided by the object always returns an error; the error code is 0x80004005 which is apparently a common HRESULT value meaning E_FAIL
. Not too descriptive.
For what it's worth, the object also exposes a hWnd
property via it's IDispatch
implementation; querying it succeeds, but the value of the property is always zero.
A bit of googling suggested that I may need to 'activate' the OLE object before the hWnd
property yields a useful value. Does anybody know how to do this, is there a dedicated COM interface for activating OLE objects?
Interestingly, the button does seem to have a window handle, as is visible in Spy++.
UPDATE: I just found IQuickActivate
which is implemented by the button control I'm dealing with, and which can be used to 'quickly' (ahem...) activate an item. However, filling the QACONTAINER
structure seems to be quite a pain, so I'll rather not do that right now.
It turned out that sending the OLEIVERB_INPLACEACTIVATE
verb using the IOleClientSite::DoVerb
function helped, like this:
IOleInPlaceObjectPtr oleInPlaceObj;
CheckAndThrow( unk->QueryInterface( &oleInPlaceObj ) ) );
HWND hwnd;
CheckAndThrow( oleInPlaceObj->GetWindow( &hwnd ) );
IOleObjectPtr oleObj;
if ( SUCCEEDED( unk->QueryInterface( &oleObj ) ) ) {
IOleClientSitePtr clientSite;
if ( SUCCEEDED( oleObj->GetClientSite( &clientSite ) ) ) {
hr = oleObj->DoVerb( OLEIVERB_INPLACEACTIVATE,
NULL,
clientSite,
0,
NULL,
NULL );
if ( SUCCEEDED( hr ) ) {
if ( SUCCEEDED( oleInPlaceObj->GetWindow( &hwnd ) ) ) {
return hwnd;
}
}
}
}
unk
is an IUnknownPtr
for which I'm trying to get the HWND
. The CheckAndThrow
function is a helper macro which yields an exception in case the given return code indicates a failure.
Naturally button has a valid HWND
, othrewise it wouldn't be a button/window.
You may get the HWND
of any control by using GetDlgItem
or similar.
I'm not certain either about how to activate the object programmatically. I'd try the following:
- Call
ReactivateAndUndo
. According to doc this may do what you need IMHO. - If you have the control
HWND
(and you definitely may obtain it if it exists) - it's possible to simulate user mouse input
精彩评论