Introduction
When working with COM , the "COM Component Categories Manager" is a
system provided COM object that (as the name denotes) provides a way of working
with COM Object Categories.
Or quoting the MSDN information:
As the number of available components grows,
it becomes increasingly difficult to manage these components. In terms of the
interfaces they expose as well as the tasks they perform, many components offer
similar functionality, .
It is often necessary to enumerate the
components that can be used in a certain context. Examples of this are the Insert
Object dialog box used in OLE compound documents and the Insert Control
dialog box used in OLE controls. These dialog boxes list all components that
fulfill (or claim to fulfill) the interface contracts for compound documents or
controls. These existing categories (OLE document, OLE control) do not imply an
exact interface signature. OLE documents have to expose a certain set of core
interfaces (for example, IOleObject
or IPersistStorage
) but can
also expose additional interfaces such as IOleLink
The object exposes 2 interfaces. ICatInformation
for retrieving information
on categories and ICatRegister
for registering new categories and class
implementations.
The ICatInformation
interface provides
methods for obtaining information about the categories implemented or required
by a certain class, as well as information about the categories registered on a
given machine.
The ICatRegister
interface provides
methods for registering and unregistering component category information in the
Registry. This includes both the human-readable names of categories and the
categories implemented/required by a given component or class.
In the .Net framework, there is much to do about COM interoperability and I
was surprised to discover that there is no support at all for the COM Component
Categories Manager in the .Net framework.
So ... create it our selves I suppose.
Background
For more information on the COM Component Categories Manager, search the MSDN
library for ICatInformation
, ICatRegister
or Component Categories Manager.
Using the code
To begin. I apologize for the lack of comment in the code. Not enough time
and to much to do... But example shows a lot.
Basically the project creates 2 C# classes that wrap the
ICatInformation
and ICatRegister
interfaces and provide more C# style Methods,
using Arrays in stead of IEnum
interfaces and System.Guid
's in stead of
ole32.GUID
For example wrapping the
ICatInformation::EnumClassesOfCategories
method:
HRESULT EnumClassesOfCategories(
ULONG cImplemented,
CATID rgcatidImpl,
ULONG cRequired,
CATID rgcatidReq,
IEnumCLSID ** ppenumCLSID
);
becomes in the C# CatInformation
class...
public Guid[] GetClassesofCategories(Guid[] Implemented, Guid[] Required)
or with only one argument
Guid[] GetClassesofImplCategories(Guid[] Implemented)
and is then used like this:
Guid[] CatImpl = {new Guid("0002E500-0000-0000-C000-000000000046")};
Guid[] ImplList = m_CatInformation.GetClassesofImplCategories(CatImpl);
Or wrapping the ICatRegister::RegisterClassImplCategories
method:
HRESULT RegisterClassImplCategories(
REFCLSID rclsid,
ULONG cCategories,
CATID rgcatid[]
);
becomes in the C# CatRegister
class...
public void RegisterClassImplCategories(Guid ClsId, Guid[] ImplementedCatIds)
The CatInformation
and CatRegister
are normal C# classes. When they are
created they get an ICatInformation
and ICatRegister
COM interface respectively.
When the Dispose method of the classes is called the Classes release the COM
interface. All class methods convert the parameters if necessary, then call the
COM interface method and present the result.
How was it created ?
First of all the project starts with generating a usable .Net wrapper
for the COM interfaces ICatInformation
and ICatRegister
. This is a bit tricky in
the beginning. The interfaces are declared in the file "ComCat.idl" in
the Platform SDK Include directory. Of course these ar IDL files and these are
not usable in Dot Net, so we make a copy of the file and change a few
things like adding return values in stead of plain out parameters and adding a
library statement.
Then we use the MIDL.EXE compiler to generate a type
library. Then use TLBIMP.EXE to generate a dot net import library. We could use
the library as it is generated but there are still some things that are not very
useful. For example the C statements like CATID rgcatid[]
become something like ref ole32.GUID where we
would rather see something like Guid[] of course.
So
first decompile the dot net "ComCat.dll" file with the ILDASM.EXE tool
to "ComCat.il" and start editing the MISL file (the IL files are
provided with the source code and the changes are in comment at the top of the
file). Finally recompile the MISL file with the ILASM.EXE tool.
Seems a lot of
work but it doesn't take a lot of time if you get used to it.
Getting the
COM interfaces ?
Then we still
have to wrap the COM CoCreateInstance
function to
create our object.
STDAPI CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv
);
as wrapped like this
[DllImport("OLE32.DLL", EntryPoint = "CoCreateInstance",
CallingConvention = CallingConvention.StdCall)]
static extern uint CoCreateInstance(ref Guid ClassGuid ,
IntPtr pUnkOuter, CLSCTX dwClsContext, ref Guid InterfaceGuid,
ref IntPtr Result);
and we get the ICatInformation
interface like this
uint hr = Ole32.S_OK;
IntPtr CatInformationPtr = IntPtr.Zero;
object CatInformationObj = null;
hr = Ole32.CoCreateInstance(
ref Ole32.CLSID_StdComponentCategoriesMgr,
IntPtr.Zero,
CLSCTX.CLSCTX_INPROC_SERVER,
ref Ole32.IID_ICatInformation,
ref CatInformationPtr);
if (hr != Ole32.S_OK)
{
throw new COMException(
"Error creating instance of ICatInformation", (int)hr);
}
CatInformationObj = Marshal.GetObjectForIUnknown(CatInformationPtr);
m_CatInformation = (ICatInformation) CatInformationObj;
Points of Interest
Dot NET Interop works great but the documentation it is hell. Would it be that
difficult for Microsoft to give a long list of real world examples for Interop
in stead of spreading the information all over the MSDN ?
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.