.NET Forum / Languages / C# / December 2007
Creating COM servers in .NET
|
|
Thread rating:  |
Fredo - 31 Dec 2007 18:44 GMT I've never used C# to create COM servers before and I'm not really sure what I'm doing wrong. I read something about versioning problems when using InterfaceIsDual. I thought I could fix this by supplying the DispIDs. I have the following interface, for example:
[Guid("B7A755CC-809B-412f-BCFE-C47F0084DDFB")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)] public interface IIdentity { [DispId(100)] void Initialize(byte[] idData); [DispId(101)] IIdentity DistanceTo(IIdentity otherID); [DispId(102)] int CompareTo(IIdentity otherID); [DispId(103)] int RawDataLen { get; } [DispId(104)] ulong[] RawData { get; } [DispId(105)] int GetBit(int bit); [DispId(106)] void SetBit(int bit, int value); } }
But when I go into OLE/COM Object Viewer, I see the following for the dispinterface:
dispinterface _Identity { properties: methods: [id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)] BSTR ToString(); [id(0x60020001)] VARIANT_BOOL Equals([in] VARIANT obj); [id(0x60020002)] long GetHashCode(); [id(0x60020003)] _Type* GetType(); [id(0x60020004)] void Initialize([in] SAFEARRAY(unsigned char) idData); [id(0x60020005)] IIdentity* DistanceTo([in] IIdentity* otherID); [id(0x60020006)] long CompareTo([in] IIdentity* otherID); [id(0x60020007), propget] long RawDataLen(); [id(0x60020008), propget] SAFEARRAY(uint64) RawData(); [id(0x60020009)] long GetBit([in] long bit); [id(0x6002000a)] void SetBit( [in] long bit, [in] long value); [id(0x6002000b), propget] SAFEARRAY(unsigned char) ByteArray(); [id(0x6002000c), propget] SAFEARRAY(uint64) _id(); [id(0x6002000c), propput] void _id([in] SAFEARRAY(uint64) rhs); };
Why isn't it using the IDs I'm supplying?
Thanks.
Nicholas Paldino [.NET/C# MVP] - 31 Dec 2007 19:22 GMT Fredo,
I don't know if it is related, but I wouldn't use the ulong type for the RawData property. There is no corresponding type in COM automation. Perhaps this is interfering somehow with the generation of the type libaray.
Other than that, from the code, it should be applying the proper DISP id to the method, so the declaration of the RawData property is the only thing I can think of.
Do you really need an array of unsigned 64-bit values?
 Signature - Nicholas Paldino [.NET/C# MVP] - mvp@spam.guard.caspershouse.com
> I've never used C# to create COM servers before and I'm not really sure > what I'm doing wrong. I read something about versioning problems when [quoted text clipped - 70 lines] > > Thanks. Fredo - 31 Dec 2007 20:01 GMT Nicholas,
That was a mistake (just corrected it right before I read your post, actually). I did intend uints and not ulongs. I'm doing some code conversion from C++ and ulong was meant as a 32-bit uint. Thanks for noticing.
But that isn't the problem. See my reply to John for more info...
Pete
> Fredo, > [quoted text clipped - 83 lines] >> >> Thanks. John Duval - 31 Dec 2007 19:44 GMT > I've never used C# to create COM servers before and I'm not really sure what > I'm doing wrong. I read something about versioning problems when using [quoted text clipped - 72 lines] > > Thanks. Hi Fredo, Are you generating a TLB and then looking at the generated .TLB with OLEVIEW? When I do that with your code, I get the correct DISPIDs (100-106). If I comment out the DispId attributes, rebuild, and rerun REGASM /TLB, I get the other DISPIDs (0x60020000, etc...). I don't have my interop book handy, but I'd bet that the 0x6002+ range is used as the default DISPID offset, and your TLB was generated before you added the DispId attributes. If that's the case, then you just need to re-run REGASM /TLB to pick up the new DISPIDs.
John
Fredo - 31 Dec 2007 20:04 GMT John,
I'm not generating anything by hand. The way I did it was to go into the project properties and under Configuration Properties/Build, I set "Register for COM Interop" = true. I then build. The registration is done as part of the build. I then ran OleView and looked for my objects under All Objects and copied and pasted what it had in there for the dispinterface.
Pete
Hi Fredo, Are you generating a TLB and then looking at the generated .TLB with OLEVIEW? When I do that with your code, I get the correct DISPIDs (100-106). If I comment out the DispId attributes, rebuild, and rerun REGASM /TLB, I get the other DISPIDs (0x60020000, etc...). I don't have my interop book handy, but I'd bet that the 0x6002+ range is used as the default DISPID offset, and your TLB was generated before you added the DispId attributes. If that's the case, then you just need to re-run REGASM /TLB to pick up the new DISPIDs.
John
Nicholas Paldino [.NET/C# MVP] - 31 Dec 2007 20:14 GMT Fredo,
I would uncheck that, and also run REGASM to unregister the assembly from the registry for COM.
Then, build your project.
Once you do that, I would then generate the type library using TLBEXP.exe, and then view the type library in OLEVIEW and see if it is correct.
If it is, I would then recheck the option and have it regenerate the TLB and it should be generated correctly.
 Signature - Nicholas Paldino [.NET/C# MVP] - mvp@spam.guard.caspershouse.com
> John, > [quoted text clipped - 18 lines] > > John Fredo - 31 Dec 2007 20:40 GMT Thanks Nicholas and John, for the information. I think maybe there's some confusion on my side and maybe I'm not understanding what I need to do.
I was under the impression that to do a COM server, I need to create a C# interface and then create a class that implements that interface. This is what I have done.
Now, my C# interface is the one that has the DISPIDs defined and running TLBExport appears to generate the proper interface. Here's what I've got:
interface IIdentity : IDispatch { [id(0x00000064)] HRESULT Initialize([in] SAFEARRAY(unsigned char) idData); [id(0x00000065)] HRESULT DistanceTo( [in] IIdentity* otherID, [out, retval] IIdentity** pRetVal); [id(0x00000066)] HRESULT CompareTo( [in] IIdentity* otherID, [out, retval] long* pRetVal); [id(0x00000067), propget] HRESULT RawDataLen([out, retval] long* pRetVal); [id(0x00000068), propget] HRESULT RawData([out, retval] SAFEARRAY(unsigned long)* pRetVal); [id(0x00000069), propget] HRESULT ByteArray([out, retval] SAFEARRAY(unsigned char)* pRetVal); [id(0x0000006e)] HRESULT GetBit( [in] long bit, [out, retval] long* pRetVal); [id(0x0000006f)] HRESULT SetBit( [in] long bit, [in] long value); };
Those clearly match my DISPIDs like I want.
Here's where I'm confused. I then have a class called Identity that implements IIdentity. The class declaration begins with:
[Guid("C00C300D-AEAD-4ceb-BF80-3F8DBCF49C16")] [ClassInterface(ClassInterfaceType.AutoDual)] public class Identity : IIdentity { }
And that's the extent of my COM attributes.
TLBExp is then generating this for the Identity class
interface _Identity : IDispatch { [id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)] HRESULT ToString([out, retval] BSTR* pRetVal); [id(0x60020001)] HRESULT Equals( [in] VARIANT obj, [out, retval] VARIANT_BOOL* pRetVal); [id(0x60020002)] HRESULT GetHashCode([out, retval] long* pRetVal); [id(0x60020003)] HRESULT GetType([out, retval] _Type** pRetVal); [id(0x60020004)] HRESULT Initialize([in] SAFEARRAY(unsigned char) idData); [id(0x60020005)] HRESULT DistanceTo( [in] IIdentity* otherID, [out, retval] IIdentity** pRetVal); [id(0x60020006)] HRESULT CompareTo( [in] IIdentity* otherID, [out, retval] long* pRetVal); [id(0x60020007), propget] HRESULT RawDataLen([out, retval] long* pRetVal); [id(0x60020008), propget] HRESULT RawData([out, retval] SAFEARRAY(unsigned long)* pRetVal); [id(0x60020009), propget] HRESULT ByteArray([out, retval] SAFEARRAY(unsigned char)* pRetVal); [id(0x6002000a)] HRESULT GetBit( [in] long bit, [out, retval] long* pRetVal); [id(0x6002000b)] HRESULT SetBit( [in] long bit, [in] long value); [id(0x6002000c)] HRESULT SetValue([in] unsigned long value); [id(0x6002000d)] HRESULT Add( [in] IIdentity* value, [out, retval] IIdentity** pRetVal); [id(0x6002000e), custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, Add)] HRESULT Add_2( [in] unsigned long value, [out, retval] IIdentity** pRetVal); [id(0x6002000f)] HRESULT ShiftLeft( [in] unsigned long bits, [out, retval] IIdentity** pRetVal); [id(0x60020010), propget] HRESULT _id([out, retval] SAFEARRAY(unsigned long)* pRetVal); [id(0x60020010), propput] HRESULT _id([in] SAFEARRAY(unsigned long) pRetVal); };
So I guess I have a few questions:
1: Why don't the IDs match up with the DISPIds from the IIdentity interface?
2: If it's creating a COM interface for Identity, do I really need the IIdentity C# interface?
Sorry, I haven't done COM stuff in so long and I have no idea where my COM books have disappeared to, so I'm working with a flakey memory...
Nicholas Paldino [.NET/C# MVP] - 31 Dec 2007 20:49 GMT Fredo,
Remove the ClassInterface attribute from the class implementation. Since you have (correctly, I might add, in terms of how to ^properly^ export a COM type) defined an interface separately, there is no need to have the class definition define the interface.
Remove that, and it should be just fine.
 Signature - Nicholas Paldino [.NET/C# MVP] - mvp@spam.guard.caspershouse.com
> Thanks Nicholas and John, for the information. I think maybe there's some > confusion on my side and maybe I'm not understanding what I need to do. [quoted text clipped - 115 lines] > Sorry, I haven't done COM stuff in so long and I have no idea where my COM > books have disappeared to, so I'm working with a flakey memory... Fredo - 31 Dec 2007 21:21 GMT Sweet, thanks Nicholas. As always, I bow to the master...
> Fredo, > [quoted text clipped - 126 lines] >> Sorry, I haven't done COM stuff in so long and I have no idea where my >> COM books have disappeared to, so I'm working with a flakey memory...
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|