Sid Price
asked on
Consuming COM class ;ibrary with unmanged "C" application
I am working on a project that is a "C" language application to which I need to add some fairly complex XML parsing. I really like LINQ to XML and would like to build a COM class library to do the XML work so that I can use LINQ. THis means I need to access the class library from my unmanaged "C" application.
I understand that I need to call CoInitialize and then get a pointer to my DLL using CoCreateInstance and this is where I am so far failing. The code below is from the VB.NET COM enabled class library and also a snippet of the consuming application code. What I seem to be unable to do is to figure out the type of the pointer needed for the interface and also the CLSID and interface IID, this inspite of importing the TLB file into my source.
VB.NET code:
<ComClass(XMLReader.ClassI d, XMLReader.InterfaceId, XMLReader.EventsId)> _
Public Class XMLReader
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "8fec2c9f-a761-4fec-b964-5 27183de052 8"
Public Const InterfaceId As String = "b5f352b3-b93d-4091-8f8f-b 5b6698ca41 5"
Public Const EventsId As String = "bc3078e2-b563-42b8-8c03-2 a02e0bbeac f"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public ReadOnly Property MyName() As String
Get
Return "XMLReader"
End Get
End Property
End Class
And then in my 'C" app I have gthe following lines:
#import "..\XMLReader_LINQ\bin\deb ug\XMLRead er_LINQ.tl b" named_guids
...
IDispatch *pMyInterface ;
CoInitialize(NULL) ;
hr = CoCreateInstance(CLSID_XML Reader,NUL L,CLSCTX_I NPROC_SERV ER,IID__XM LReader,(v oid**)&pMy Interface) ;
I really am not sure that the interface type is "IDispatch", although the line does compile. Also the compiler reports that both "CLSID_XMLReader" and "IID__XMLReader" are undefined. Any pointers to how to move on from here would be much appreciated. This is such an old technique that finding any simple "howtos" on the Internet is proving impossible.
Many thanks,
Sid.
I understand that I need to call CoInitialize and then get a pointer to my DLL using CoCreateInstance and this is where I am so far failing. The code below is from the VB.NET COM enabled class library and also a snippet of the consuming application code. What I seem to be unable to do is to figure out the type of the pointer needed for the interface and also the CLSID and interface IID, this inspite of importing the TLB file into my source.
VB.NET code:
<ComClass(XMLReader.ClassI
Public Class XMLReader
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "8fec2c9f-a761-4fec-b964-5
Public Const InterfaceId As String = "b5f352b3-b93d-4091-8f8f-b
Public Const EventsId As String = "bc3078e2-b563-42b8-8c03-2
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public ReadOnly Property MyName() As String
Get
Return "XMLReader"
End Get
End Property
End Class
And then in my 'C" app I have gthe following lines:
#import "..\XMLReader_LINQ\bin\deb
...
IDispatch *pMyInterface ;
CoInitialize(NULL) ;
hr = CoCreateInstance(CLSID_XML
I really am not sure that the interface type is "IDispatch", although the line does compile. Also the compiler reports that both "CLSID_XMLReader" and "IID__XMLReader" are undefined. Any pointers to how to move on from here would be much appreciated. This is such an old technique that finding any simple "howtos" on the Internet is proving impossible.
Many thanks,
Sid.
ASKER
Thanks for the quick reply, however I don't think these links help me.
I have a "C" application and a COM enabled class library. I thought my code was fairly close. Are you saying that I am way off track? Do I have to call the COM DLL in order to have it call the .NET code? That seems like a load of work.
Sid.
I have a "C" application and a COM enabled class library. I thought my code was fairly close. Are you saying that I am way off track? Do I have to call the COM DLL in order to have it call the .NET code? That seems like a load of work.
Sid.
I thought you were writing a .NET assembly and calling it from C. If this is just straight COM/C then, yes, I gave you information you probably don't need. I'm not sure where you're defining the IID values that are being reported as undefined. I am pretty sure you need to set those values to the proper GUIDs before you make the call. Also, make sure the COM object is properly registered with regsvr32. There is a regasm program for assemblies, but I guess you're not doing that.
ASKER
You will see in my original post that the type library (TLB file) is imported into the application. This process generates two files, one of them is a TLH file and it is from this file that one is supposed to discover the IDs required. This is the TLH file generated when I compile my application:
// Created by Microsoft (R) C/C++ Compiler Version 15.00.30729.01 (efdf8a21).
//
// c:\data_root\projects\idb\ idb\idb_en gine\debug \xmlreader _linq.tlh
//
// C++ source equivalent of Win32 type library ..\XMLReader_LINQ\bin\debu g\XMLReade r_LINQ.tlb
// compiler-generated file created 04/01/12 at 09:56:21 - DO NOT EDIT!
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace XMLReader_LINQ {
//
// Forward references and typedefs
//
struct __declspec(uuid("a0143e31- cdd1-491d- 9c5b-32bf5 610a0cf"))
/* LIBID */ __XMLReader_LINQ;
struct /* coclass */ XMLReader;
struct __declspec(uuid("b5f352b3- b93d-4091- 8f8f-b5b66 98ca415"))
/* dual interface */ _XMLReader;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_XML Reader, __uuidof(_XMLReader));
//
// Type library items
//
struct __declspec(uuid("8fec2c9f- a761-4fec- b964-52718 3de0528"))
XMLReader;
// interface _Object
// [ default ] interface _XMLReader
struct __declspec(uuid("b5f352b3- b93d-4091- 8f8f-b5b66 98ca415"))
_XMLReader : IDispatch
{
//
// Property data
//
__declspec(property(get=Ge tMyName))
_bstr_t MyName;
//
// Wrapper methods for error-handling
//
_bstr_t GetMyName ( );
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_MyName (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
};
//
// Named GUID constants initializations
//
extern "C" const GUID __declspec(selectany) LIBID_XMLReader_LINQ =
{0xa0143e31,0xcdd1,0x491d, {0x9c,0x5b ,0x32,0xbf ,0x56,0x10 ,0xa0,0xcf }};
extern "C" const GUID __declspec(selectany) CLSID_XMLReader =
{0x8fec2c9f,0xa761,0x4fec, {0xb9,0x64 ,0x52,0x71 ,0x83,0xde ,0x05,0x28 }};
extern "C" const GUID __declspec(selectany) IID__XMLReader =
{0xb5f352b3,0xb93d,0x4091, {0x8f,0x8f ,0xb5,0xb6 ,0x69,0x8c ,0xa4,0x15 }};
//
// Wrapper method implementations
//
#include "c:\data_root\projects\idb \idb\idb_e ngine\debu g\xmlreade r_linq.tli "
} // namespace XMLReader_LINQ
#pragma pack(pop)
I just noticed that the file comment says it is generated for "C++", is this possibly my issue, some kind of name mangling? If so, how do I get the importer to generate a "C" compatible header file?
The registration of the COM assembly is a runtime requirement and does not affect the application compilation, so I think that is not an issue here.
It seems that this should have been a common requirement in the past and I am suprised that no simple examples are available.
Once again, any pointers would be much apprecited and thank you for taking the time to try and help,
Sid.
// Created by Microsoft (R) C/C++ Compiler Version 15.00.30729.01 (efdf8a21).
//
// c:\data_root\projects\idb\
//
// C++ source equivalent of Win32 type library ..\XMLReader_LINQ\bin\debu
// compiler-generated file created 04/01/12 at 09:56:21 - DO NOT EDIT!
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace XMLReader_LINQ {
//
// Forward references and typedefs
//
struct __declspec(uuid("a0143e31-
/* LIBID */ __XMLReader_LINQ;
struct /* coclass */ XMLReader;
struct __declspec(uuid("b5f352b3-
/* dual interface */ _XMLReader;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_XML
//
// Type library items
//
struct __declspec(uuid("8fec2c9f-
XMLReader;
// interface _Object
// [ default ] interface _XMLReader
struct __declspec(uuid("b5f352b3-
_XMLReader : IDispatch
{
//
// Property data
//
__declspec(property(get=Ge
_bstr_t MyName;
//
// Wrapper methods for error-handling
//
_bstr_t GetMyName ( );
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_MyName (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
};
//
// Named GUID constants initializations
//
extern "C" const GUID __declspec(selectany) LIBID_XMLReader_LINQ =
{0xa0143e31,0xcdd1,0x491d,
extern "C" const GUID __declspec(selectany) CLSID_XMLReader =
{0x8fec2c9f,0xa761,0x4fec,
extern "C" const GUID __declspec(selectany) IID__XMLReader =
{0xb5f352b3,0xb93d,0x4091,
//
// Wrapper method implementations
//
#include "c:\data_root\projects\idb
} // namespace XMLReader_LINQ
#pragma pack(pop)
I just noticed that the file comment says it is generated for "C++", is this possibly my issue, some kind of name mangling? If so, how do I get the importer to generate a "C" compatible header file?
The registration of the COM assembly is a runtime requirement and does not affect the application compilation, so I think that is not an issue here.
It seems that this should have been a common requirement in the past and I am suprised that no simple examples are available.
Once again, any pointers would be much apprecited and thank you for taking the time to try and help,
Sid.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
It allowed me to resolve my issue completely.
http://msdn.microsoft.com/en-us/library/ms973802.aspx
Here is an example of calling a COM object from C++ code:
http://www.codeproject.com/Articles/3906/Unmanaged-to-Managed-Calls/
Here is the Stack Overflow answer that includes the link from above:
http://stackoverflow.com/questions/530244/calling-c-sharp-from-c-com-add-in