Enumerate Com Object (Idispatch) Methods Using Atl

Enumerate COM object (IDispatch) methods using ATL?

You can't enumerate all the available methods unless the object implements IDispatchEx.

However, if you know the name of the method you want to call, you can use GetIDsOfNames to map the name to the proper DISPID.

HRESULT hr;
CComPtr<IDispatch> dispatch;
DISPID dispid;
WCHAR *member = "YOUR-FUNCTION-NAME-HERE";
DISPPARAMS* dispparams;

// Get your pointer to the IDispatch interface on the object here. Also setup your params in dispparams.

hr = dispatch->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
hr = dispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, dispparams, &varResult, NULL, NULL);
}

Edit: For completeness, I suspect there is a way to interrogate the ITypeInfo2 interface (assuming there is a type library for the object) that you get from IDispatch::GetTypeInfo for a list of methods, but I've not done it. See the other answer.

Implement COM IDispatch without ATL

If the interface is properly defined in the IDL and compiled into a type library, implementing IDispatch via the type library's ITypeInfo is quite feasible as it's mostly delegating. The interesting part is ITypeInfo::Invoke which relies upon correct C++ v-table layout:

public class CComClass: public IDualInterface
{
// ...

// implementing IDualInterface

ITypeInfo* m_pTypeInfo // can be obtained via ITypeLib::GetTypeInfoOfGuid for the GUID of IDualInterface

// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{
*pctinfo = 1;
return S_OK;
}

STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
if (0 != itinfo)
return E_INVALIDARG;
(*pptinfo = m_pTypeInfo)->AddRef();
return S_OK;
}

STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}

STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return m_pTypeInfo->Invoke(static_cast<IDualInterface*>(this), dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
}

I've used a similar approach to create a script-callable wrapper for MSHTML DOM objects to bypass scripting security restrictions.

So where do you get the ITypeInfo from? Essentially you get it by:

  1. Write an IDL file which declares your interface as a dual interface. It has to be a dual interface, as that is how the ITypeInfo implementation knows which function to invoke - it cannot just invoke the C++ functions directly on your class because C++ has no reflection and because it is language neutral. Therefore it can only delegate the Invoke call to another method declared in the type library.
  2. Compile the IDL to a header file and type library as part of the build process
  3. The header file produced from the IDL defines the interface, which your implementing class must inherit from. Once you have implemented all the methods you are good to go. (For development start by making them all return E_NOTIMPL then implement them one by one)
  4. Install the Type Library, either to the destination directory, or as a resource in the EXE/DLL. It will need to be registered by calling RegisterTypeLib. If it is embedded as a resource, you should call this from your DllRegisterServer implementation.
  5. Load the type library when the first instance of your object is created, using LoadTypeLib. This gives you an ITypeLib
  6. Get the ITypeInfo you need using GetTypeInfoOfGuid.

Chaining methods of ATL/COM objects

Something like this:

interface IMyInterface {
HRESULT DoSomething([in] long someParam, [out, retval] IMyInterface** ret);
HRESULT DoSomethingElse([out, retval] IMyInterface** ret);
};

Scripting clients should be able to do myObj.DoSomething(42).DoSomethingElse()

How I can enumerate the COM Object Members like interfaces, properties and methods?

You need to be more specific. There are two ways to interpret your question.

One is that you have a COM component (e.g. some library), and you want to programmatically enumerate interfaces/properties/methods of that. Usually (but not always), COM components come with a type library that contains full metainformation about all this - it's either embedded into the COM .exe or .dll, or is a separate .tlb file. In any case, if the COM component is properly registered in the system (e.g. using regsvr32), then COM provides a standard API to retrieve that type information, centered around ITypeLib and ITypeInfo interfaces.

Another interpretation is that you get a reference to a particular COM object, and you need to enumerate all methods/properties on that and/or invoke them by computed name, like Java or C# reflection, or Delphi RTTI. If so, then it is only possible if the COM object implements IDispatch interface, which allows you to do all of the above.

How to create anonymous IDispatch functions with ATL?

By default ATL creates "auto-dual" COM classes. They support both early binding and IDispatch. You'll see IDispatchImpl<> in their inheritance list. You declare the dispid in the IDL. No extra work is required.

Create A COM object inside another COM object

Use the ATL wizard to create the implementation of ISystemCmds. Then create the object through normal CoCreateInstance, or use the CComObject<> template (see method CreateInstance) if you need to initialize the object in a way that ISystemCmds does not support. Be aware that CComObject<>::CreateInstance() does not AddRef() your object like QueryInterface() and CoCreateInstance() do. AddRef the object before passing it along!

How to Pass an ATL com object from c++ to c#

Try to pass raw IUnkown* pointer to C# and then use Marshal.GetObjectForIUnknown to convert IntPtr to object and then cast this object to Icompte. You will need to add reference to the corresponding TypeLib into C# project to be able to perform such a cast.

Creating an ATL COM object that implements a specific interface

It's much more automatic than the other answers here are suggesting. All the boilerplate code is written for you by Visual Studio.

You're lucky you have the .idl, it's by far the most conveninent, I think.

You could paste the contents of the .idl file into your ATL COM project's existing .idl file, which would give you access to the declarations in it. For example, something like this could be pasted into an IDL file:

[
object,
uuid(ecaac0b8-08e6-45e8-a075-c6349bc2d0ac),
dual,
nonextensible,
helpstring("IJim Interface"),
pointer_default(unique)
]
interface IJim : IDispatch
{
[id(1), helpstring("method SpliceMainbrace")] HRESULT SpliceMainbrace(BSTR* avast);
};

Then in Class View, right click your class and choose Add | Implement Interface.

Notice that in this dialog, you can actually browse for a .tlb file, but I think it's better to have plain-text source for these things, for version control and the like.

Pick IJim from the list, press the > button to add it to the list to be implemented. Press Finish.

Visual Studio will add this to your class (along with a bunch of other crap to make it work):

// IJim Methods
public:
STDMETHOD(SpliceMainbrace)(BSTR * avast)
{
// Add your function implementation here.
return E_NOTIMPL;
}

Enumerating all IDispatch implementing objects on a machine

That's a very odd request. The rub is in the "all" stipulation. Simple enumeration through the HKCR\Typelib key and LoadTypeLib() isn't enough, a COM server is not required to publish a type library. You would actually have to CoCreateInstance() the coclass and QueryInterface for IDispatch. Not only is this slow, it is also risky.

You might get a better answer if you explain why you would actually contemplate doing something like this. Calling IDispatch::Invoke() without having some kind of idea what the arguments mean or what the side-effects might be is a recipe for disaster. Stay away from method names like "ReformatDrive".



Related Topics



Leave a reply



Submit