How do I determine if a certain method exists on an interface?
-
I have a COM DLL written in C++/ATL. I added a new method to one of the interfaces and altered my testbed to call this new method. I then went and registered an earlier version of the DLL which doesn't contain the new method. Not surprisingly, an exception is raised when the testbed tries to call the method. I can catch this with a try/catch handler, but I still get an unrecoverable exception when the calling function exits (see code snippet below). Is there anyway of interrogating the interface to see if the method exists? If not, is there I way my app can continue to run gracefully? This final 0xC0000005 exception is a bit of a showstopper. Thanks, Gary --- void func() { ::CoInitialize(NULL); try { CComPtr MyInt; MyInt.CoCreateInstance(CLSID_MyInterface); MyInt->NewMethod(); } catch(...) { AfxMessageBox("eek"); } } // exception 0xC0000005 thrown here
-
I have a COM DLL written in C++/ATL. I added a new method to one of the interfaces and altered my testbed to call this new method. I then went and registered an earlier version of the DLL which doesn't contain the new method. Not surprisingly, an exception is raised when the testbed tries to call the method. I can catch this with a try/catch handler, but I still get an unrecoverable exception when the calling function exits (see code snippet below). Is there anyway of interrogating the interface to see if the method exists? If not, is there I way my app can continue to run gracefully? This final 0xC0000005 exception is a bit of a showstopper. Thanks, Gary --- void func() { ::CoInitialize(NULL); try { CComPtr MyInt; MyInt.CoCreateInstance(CLSID_MyInterface); MyInt->NewMethod(); } catch(...) { AfxMessageBox("eek"); } } // exception 0xC0000005 thrown here
Gary Chapman wrote: Is there anyway of interrogating the interface to see if the method exists? You need to call GetIDsOfNames after CoCreateInstance to determine if a method exists on a given interface. The way your code is written will not work because even if the method exists, you cannot call it as if it is early-bound (you are doing late-binding). What you need to call is the Invoke method of IDispatch. [Edit] As Bo Hunter pointed out, I was wrong in saying the code won't work. [/Edit] COM programming is very complicated without help from libraries like ATL or MFC. However, you can reuse some of my code[^] to save a lot of time. ;)[
My articles and software tools
-
Gary Chapman wrote: Is there anyway of interrogating the interface to see if the method exists? You need to call GetIDsOfNames after CoCreateInstance to determine if a method exists on a given interface. The way your code is written will not work because even if the method exists, you cannot call it as if it is early-bound (you are doing late-binding). What you need to call is the Invoke method of IDispatch. [Edit] As Bo Hunter pointed out, I was wrong in saying the code won't work. [/Edit] COM programming is very complicated without help from libraries like ATL or MFC. However, you can reuse some of my code[^] to save a lot of time. ;)[
My articles and software tools
The interface would have to implement IDispatch would'nt it? If CLSID_Myinterface is a valid coclass then this code should work. This is perfectly valid code here.
BOOL OpenLinkUsingCom(TCHAR* pLink, int how, HWND hWnd) { IUniformResourceLocator* pLocator; HRESULT hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&pLocator); if (SUCCEEDED(hr)) { hr = pLocator->SetURL(pLink, IURL_SETURL_FL_GUESS_PROTOCOL); if (SUCCEEDED(hr)) { URLINVOKECOMMANDINFO ivci; ivci.dwcbSize = sizeof(URLINVOKECOMMANDINFO); ivci.dwFlags = 0; ivci.hwndParent = hWnd; switch (how) { case OPEN: ivci.pcszVerb = _T("open"); break; case EDIT: ivci.pcszVerb = _T("edit"); break; case PRINT: ivci.pcszVerb = _T("print"); break; default: ATLASSERT(0); } hr = pLocator->InvokeCommand(&ivci); } } if (pLocator) pLocator->Release(); return (SUCCEEDED(hr)); }
Please tell me if I am wrong. Thank You Bo Hunter -
The interface would have to implement IDispatch would'nt it? If CLSID_Myinterface is a valid coclass then this code should work. This is perfectly valid code here.
BOOL OpenLinkUsingCom(TCHAR* pLink, int how, HWND hWnd) { IUniformResourceLocator* pLocator; HRESULT hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&pLocator); if (SUCCEEDED(hr)) { hr = pLocator->SetURL(pLink, IURL_SETURL_FL_GUESS_PROTOCOL); if (SUCCEEDED(hr)) { URLINVOKECOMMANDINFO ivci; ivci.dwcbSize = sizeof(URLINVOKECOMMANDINFO); ivci.dwFlags = 0; ivci.hwndParent = hWnd; switch (how) { case OPEN: ivci.pcszVerb = _T("open"); break; case EDIT: ivci.pcszVerb = _T("edit"); break; case PRINT: ivci.pcszVerb = _T("print"); break; default: ATLASSERT(0); } hr = pLocator->InvokeCommand(&ivci); } } if (pLocator) pLocator->Release(); return (SUCCEEDED(hr)); }
Please tell me if I am wrong. Thank You Bo HunterBo Hunter wrote: Please tell me if I am wrong. Thank You Bo Hunter Sorry, I was wrong. You are right. :-O[
My articles and software tools
-
Gary Chapman wrote: Is there anyway of interrogating the interface to see if the method exists? You need to call GetIDsOfNames after CoCreateInstance to determine if a method exists on a given interface. The way your code is written will not work because even if the method exists, you cannot call it as if it is early-bound (you are doing late-binding). What you need to call is the Invoke method of IDispatch. [Edit] As Bo Hunter pointed out, I was wrong in saying the code won't work. [/Edit] COM programming is very complicated without help from libraries like ATL or MFC. However, you can reuse some of my code[^] to save a lot of time. ;)[
My articles and software tools
If interface being tested is derived from IDispatch, the GetIDsOfNames is a simplest way to see it. The second way is the ITypeInfo::GetIDsOfNames for non-dual interface if the Type Library is accessible (either by LoadRegTypeLib or by LoadTypeLib). PS It is a bad practice to change the contents of interface without the changing of its IID. With best wishes, Vita
-
If interface being tested is derived from IDispatch, the GetIDsOfNames is a simplest way to see it. The second way is the ITypeInfo::GetIDsOfNames for non-dual interface if the Type Library is accessible (either by LoadRegTypeLib or by LoadTypeLib). PS It is a bad practice to change the contents of interface without the changing of its IID. With best wishes, Vita