none
Can't invoke a COM visible method with IntPtr parameter. RRS feed

  • General discussion

  • Hello:

       Apparently it is impossible to invoke a .net method
    that has a IntPtr parameter via a exported IDispatch interface. IDispatch.Invoke simply cannot find the method. I think this has to do with the default marshling of data types. IntPtr is marshaled into a VT_INT where VT_INT is marshaled back into a .net Int32. To my knowledge there is no variant type that gets marshaled into an IntPtr. We can confirm this in the Default Marshaling for Objects microsoft article.
       If this is true, trying to export such an interface to COM should result in an error or at least in a warning, yet there is non, and the TLB is successfully created making you assume that method is actually invokable.

    Regards,
       JGN.


    C# .NET example code. I can't find a way to invoke the method via COM. Yet...

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    namespace World {
        [ComVisible(true)]
        [Guid("DBA2C6B1-C4F8-40c7-BA0D-71B85B8D073C")]
        [ProgId("World.Hello")]
        [ClassInterface(ClassInterfaceType.None)]
        [ComDefaultInterface(typeof(IHello))]
        public class Hello: IHello {
            public void SayHello(IntPtr arg) {
                MessageBox.Show(@"Hello World! \o/");
            }
        }

        [ComVisible(true)]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

        public interface IHello {
            void SayHello(IntPtr arg);
        }
    }

    ... in the generated TLB, all you need to do is use a long. (oleview of generated TLB)

    [
      uuid(1097B776-9721-324A-ACB2-21DDBB27DAA0),
      version(1.0),
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, World.IHello)

    ]
    dispinterface IHello {
        properties:
        methods:
            [id(0x60020000)]
            void SayHello([in] long arg);
    };

    Tuesday, October 10, 2006 11:35 AM

All replies

  • Hmm, I think I am in this situation too now. Smile

    I'm trying to send a HWND over COM but get an "E_NOTIMPLEMENTED" error if trying to call a COM visible C# method using IntPtr as an argument from C++ with a HWND. This error goes away if I use a simple "int" type in the C# class, but that's of course a big no-no if this is to be portable to Win64 later on. And in either case, IntPtr looks pretty bad here, because the generated .tlb from that makes it take "COM long"'s, which I think are all 32-bit values. Or will this solve itself if I'd re-compile this on a 64-bit OS? Will it then automagically generate a 64-bit value for the .tlb? Or am I too look at this differently and use e.g. an object in C#, generating a VARIANT type in the .tlb? And perhaps use some MarshalAs attribute?

    Anyway, I then though -- what if I try to take this as a 64-bit value? Who cares if I waste half of that on 32-bit systems? So I declared it as a "long" (i.e. System.Int64) in C# and the generated .tlb file now indeed takes something of type "int64". Over in C++ land that calls this, I then thought I'd wrap this value in a CComVariant before calling the method, and everything looked fine since that class takes a LONGLONG in its constructor, which maps to a native __int64 type on 64-bit editions of Windows, or a double on 32-bit editions (since doubles internally use 8 bytes / 64 bits). However, and here's the catch, Windows XP and higher seems required for the LONGLONG declaration, and since we have a few Windows 2000 clients, that won't be the perfect solution either. ;-) Maybe one can send a pointer as a double and take a double in C#, then casting it to something else, but that really looks like a cludge, and I wonder if there's a "cleaner" way of doing this sort of pointer sending over COM?
    Thursday, December 6, 2007 9:53 AM