Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / December 2007

Tip: Looking for answers? Try searching our database.

Creating COM servers in .NET

Thread view: 
Enable EMail Alerts  Start New Thread
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.