Since the function's return value is utilized for error message, how do the functions return the necessary information back to the caller?
For example:
IDirect3D9::CreateDevice method
So if you take a look at that link you'll notice that it has some parameters marked Out this is important because this denotes what will be returned to the caller.
HRESULT CreateDevice(
[in] UINT Adapter,
[in] D3DDEVTYPE DeviceType,
[in] HWND hFocusWindow,
[in] DWORD BehaviorFlags,
[in, out] D3DPRESENT_PARAMETERS *pPresentationParameters,
[out, retval] IDirect3DDevice9 **ppReturnedDeviceInterface
);
In the above sample (copied and pasted from the MSDN link), you'll notice a parameter ppReturnedDeviceInterface is marked as being ** or a pointer to a pointer, the caller would pass in a the address of their pointer and would be returned a pointer at that address. Also the D3DPRESENT_PARAMETERS structure passed in to pPresentationParameters will be updated on return, as noted by the out annotation.
Ex:
IDirect3DDevice9 *pDevice = NULL;
HRESULT hr = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
pPresentationParams,
&pDevice);
if(SUCCEEDED(hr))
{
//pDevice should be non null at this point
}
Related
I need to get fullDescription property of a UI element using get_CurrentFullDescription method of UIAutomation library of c++ windows.
Issue is I have element as IUIAutomationElement instead of IUIAutomationElement6, get_CurrentFullDescription can only be invoked on element with IUIAutomationElement6 type.
How can I convert IUIAutomationElement to IUIAutomationElement6?
I am using HandlePropertyChangedEvent method to listen on changes in UI, which returns:
HRESULT HandlePropertyChangedEvent(
[in] IUIAutomationElement *sender,
[in] PROPERTYID propertyId,
[in] VARIANT newValue
);
https://learn.microsoft.com/en-us/windows/win32/api/uiautomationclient/nf-uiautomationclient-iuiautomationpropertychangedeventhandler-handlepropertychangedevent
Here, I need to access FullDescription property of sender element coming from HandlePropertyChangedEvent function.
#IInspectable mentioned QueryInterface hint in comments, based on that here is answer:
CComPtr<IUIAutomationElement> pElement;
// Code to initialize pElement goes here
CComPtr<IUIAutomationElement6> pElement6;
HRESULT hr = pElement->QueryInterface(&pElement6);
if (SUCCEEDED(hr))
{
// Use the pElement6 object here
}
I am writing a Windows API COM wrapper to be used in VBScript, and came up with a problem with callback controlled functions such as EnumWindows.
This is what I have currently:
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(BSTR lpEnumFunc, int lParam, int *Result)
{
*Result = int(EnumWindows(WNDENUMPROC(lpEnumFunc), lParam))
return S_OK;
}
But, as I expected this didn't work and when I use this with VBScript, it crashes.
How can I export EnumWindows from my COM wrapper to use in VBScript and will VBScript support using it? If so, how can I use EnumWindowsProc callback function in VBScript?
UPDATE
BSTR WindowClassName = SysAllocString(L"");
WCHAR WindowTitle[8192];
BOOL CALLBACK EnumWindowsProc(
__in HWND hWnd,
__in LPARAM lParam
)
{
RealGetWindowClass(hWnd, WindowClassName, 100);
GetWindowText(hWnd, WindowTitle, 8192);
if (0 == wcscmp(WindowClassName, L"#32768"))
{
//<< NOW, HWND need to be caught by WSH and then show it. (I.E. WScript.Echo HWND) >>
}
return TRUE;
}
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(int lParam)
{
EnumWindows(EnumWindowsProc, lParam);
return S_OK;
}
Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
WINAPI.WinAPI_EnumWindows 0
Now I did above, but instead of this, I need WSH to know if a handle to specified window type is found and return HWND internally and show it from WSH, not directly from C++.(such as via a Message Box).
This function's lParam parameter can be set from VBScript, but how can I set EnumWindowsProc? Can it be done using GetRef or something similar in VBSript? But GeRef allows only one parameter. I want this EnumWindowsProc callback function also to be declared in VBScript, otherwise wrapping this function becomes useless.
I read this post from #Alex.K's comment and found it very useful, but I can't understand how to use it with EnumWindows's callback EnumWindowsProc.
Please help me more on this.
I am trying to write a shell extension that adds a menu item to the context menu for all file types. The code for the extension (in its entirety) is located here but I'll include some of the relevant parts below as I describe the problem.
The ContextMenu class implements the IShellExtInit and IContextMenu interfaces:
class ContextMenu : public IShellExtInit, IContextMenu
{
public:
// [...]
// IShellExtInit methods
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder,
IDataObject *pdtobj, HKEY hkeyProgID);
// IContextMenu methods
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pReserved,
LPSTR pszName, UINT cchMax);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,
UINT idCmdLast, UINT uFlags);
}
All of the methods are rigged with MessageBox() calls to indicate when they are called. There is only one small problem — they are never called.
The extension includes another class that implements IClassFactory. The implementation for IClassFactory::CreateInstance() is as follows:
STDMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid,
LPVOID *ppvObject)
{
if (pUnkOuter) {
return CLASS_E_NOAGGREGATION;
}
if (!ppvObject) {
return E_INVALIDARG;
}
*ppvObject = NULL;
ContextMenu *contextMenu = new ContextMenu;
HRESULT hResult = contextMenu->QueryInterface(riid, ppvObject);
contextMenu->Release();
return hResult;
}
I can confirm that this method is being called and I can also confirm that ContextMenu::QueryInterface() is then being called with riid set to IID_IContextMenu.
However, nothing happens after that. None of the IContextMenu methods are called. Neither is IShellExtInit::Initialize(). Why is this happening?
Test Environment
Visual Studio 2013 Express
Windows 7 Home Premium x64
Edit: I completely forgot to describe how the extension is being registered. The DllRegisterServer() function creates the following registry keys/values and checks the error codes to confirm that they are created:
Key: HKCR\CLSID\{CLSID}, Value: NULL, Data: NitroShellExt
Key: HKCR\CLSID\{CLSID}\InprocServer32, Value: NULL, Data: [path to DLL]
Key: HKCR\CLSID\{CLSID}\InprocServer32, Value: ThreadingModel, Data: Apartment
Key: HKCR\*\ShellEx\ContextMenuHandlers\NitroShellExt, Value: NULL, Data: {CLSID}
Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved, Value: {CLSID}, Data: NitroShare Context Menu
...where {CLSID} is {52A10783-C811-4C45-9A3D-221A962C8640}. I then use regsvr32 to register the extension and regedit to confirm that the keys/values do indeed exist.
In my project, I wrote a component which will be called in a service(COM server). There is another process will get this component's interface and register a callback interface through connection point. So the service could use the callback interface to do some feedback.
But I found that when I use the IConnectionPoint::Advise to register my callback interface cause a crash.
I implement the connection point manually. Here are part of my code:
class ATL_NO_VTABLE CUploadManager :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CUploadManager, &CLSID_UploadManager>,
public IUploadManager,
public IConnectionPointContainer,
public IConnectionPoint
...
// IConnectionPointContainer Functions
STDMETHODIMP EnumConnectionPoints(IEnumConnectionPoints **ppEnum);
STDMETHODIMP FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP);
// IConnectionPoint Functions
STDMETHODIMP GetConnectionInterface(IID *pIID);
STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer **ppCPC);
STDMETHODIMP Advise(IUnknown *pUnkSink, DWORD *pdwCookie);
STDMETHODIMP Unadvise(DWORD dwCookie);
STDMETHODIMP EnumConnections(IEnumConnections **ppEnum);
In the client, I have get the component interface already, then I get the connection point and try to call function Advise:
...
CComPtr<IConnectionPointContainer> pCPC;
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC);
if (FAILED(hr))
{
return ;
}
CComPtr<IConnectionPoint> pConnectionPoint;
hr = pCPC->FindConnectionPoint(__uuidof(_IEvents), &pConnectionPoint);
if (SUCCEEDED(hr))
{
DWORD dwCookie = 0;
CDataCallback* pCallback = new CDataCallback();
IUnknown* pUnknown = NULL;
pCallback->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = pConnectionPoint->Advise(pUnknown, &dwCookie);
...
All interface pointers could be got successfully, but when I call Advise, the crash occurs. The strange thing is the crash is not happened in the Advise implementation, it seems occurs in the RPC call process, the call stack is like this:
003d0070() <----crash here
combase.dll!76eea3ab()
[Frames below may be incorrect and/or missing, no symbols loaded for combase.dll]
combase.dll!76ee9d00()
rpcrt4.dll!7612a53d()
mfc90ud.dll!CDialog::OnCmdMsg
...
But if the first parameter of Advise is NULL, the function Advise could be executed.
Here is the Sink code implemented in client:
class CDataCallback : public _IEvents
{
public:
CDataCallback() {}
~CDataCallback() {}
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release()
{
return 0;
}
HRESULT __stdcall TestFunc()
{
...
return S_OK;
}
};
The interface _IEvents is generated in the component which will be used as a callback in the connection point. I just use this class to test the connection point, so the implementation is very simple.
I have no idea about how this crash occurs.
Thanks for all your help!
The problem is likely to be in your CDataCallback class. It's QueryInterface implementation is unsafe and returns interface pointer incorrectly.
class CDataCallback : public _IEvents
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
You have to check iid and return E_NOINTERFACE in case requested interface is not _IEvents. Basically you can set a breakpoint there and see if you have a call there prior to crash and check the arguments.
Your sink might be queried for other interfaces (IMarhsal etc) and you have to properly indicate that you are not implementing them, instead of returning unmatching pointer, use of which leads to undefined behavior.
I'm hosting an IWebBrowser2 control in my C++ program using nothing but plain Win32 (no mfc, atl, wtl etc). On DISPID_NAVIGATECOMPLETE2 I add a custom object to be accessed from javascript running on the displayed webpage.
To add the custom object I call InvokeEx with DISPATCH_PROPERTYPUT and a DISPPARAMS structure with a pointer to my custom object.
During the call to InvokeEx the AddRef function of my custom object is called and I increment its reference counter. But the object never gets a call to its Release function, so the reference counter never decreases down to zero again.
Who is responsible for calling Release() after AddRef() has been called in InvokeEx?
EDIT: (Adding some code)
This is the code that adds my custom object to the IHTMLWindow2. custObj points to my custom object
IHTMLWindow2 *win = NULL;
GetDoc()->get_parentWindow(&win);
IDispatchEx *winEx = NULL;
win->QueryInterface(&winEx);
DISPID dispid;
HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid); //objName is "JSObject"
DISPID namedArgs[] = {DISPID_PROPERTYPUT};
DISPPARAMS params;
params.rgvarg = new VARIANT[1];
params.rgvarg[0].pdispVal = custObj;
params.rgvarg[0].vt = VT_DISPATCH;
params.rgdispidNamedArgs = namedArgs;
params.cArgs = 1;
params.cNamedArgs = 1;
hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL);
This is the object that I'm adding (some private members have been left out for brevity)
class JSObject : public IDispatch {
private:
long ref;
public:
JSObject();
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDispatch
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo);
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr);
};
EDIT 2:
Now that it seems to be working like it should I decided to put it on github.
https://github.com/Tobbe/CppIEEmbed. Please fork and improve if you can :)
Well, you are assigning a property, aren't you? As long as this property exists and refers to your object, it will have a reference added.
If you want the remote object to release your reference you should assign NULL to the property, or some other object.