0

I know there are many questions about this topic but I believe I went through all of them in the last 10 days and I could not find the solution for the error I'm heavily suffering.

I have a COM server dll in C# and a COM client in C#. All in Windows 7. I'm receiving InvalidCastException and I cannot solve the problem. I'm beginning to doubt that it is possible to create a COM server in C#.

I'm having that exception when instantiating the COM object, in:

Test.MyImplementation mi = new Test.MyImplementation();

System.InvalidCastException was unhandled HResult=-2147467262 Message=Unable to cast object of type 'MyTest.MyImplementation' to type 'Test.MyImplementation'. Source=ConsoleApplication3 StackTrace: at ConsoleAppCOM.Program.Main(String[] args) in c:\Users\rkohn\Documents\Visual Studio 2013\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 48 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

This is the COM server code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;


namespace MyTest
{

    [ComVisible(true)]
    [Guid("DBE0E8C4-DABA-41F3-B6A4-CAFE353D3D16")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPimcManager
    {
        void GetTabletCount(out UInt32 count);
    }

    [ComVisible(true)]
    [Guid("C6659361-DABA-4746-931C-CAFE4B146690")]
    [ProgId("FakeServer.MyImplementation")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(IPimcManager))] //This to explicitly establish which is the default interface
    public class MyImplementation : IPimcManager
    {
        public MyImplementation() { }
        ~MyImplementation() { }
        public void GetTabletCount(out UInt32 count)
        {
            Console.WriteLine("GetTabletCount called!");
            count = 1;
        }
    }
}

This is the client code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Test
{

    [ComImport]
    [Guid(PimcConstants.IPimcManagerIID)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IPimcManager
    {
        void GetTabletCount(out UInt32 count);
    }

    [ComImport]
    [Guid(PimcConstants.PimcManagerCLSID)]
    class MyImplementation
    {
    }

    //        void GetTabletCount(out UInt32 count);
    //void GetTablet(UInt32 tablet, out IPimcTablet IPimcTablet);

    internal static class PimcConstants
    {
        //internal const string PimcManagerCLSID = "e23b1ced-5e47-4fdb-af66-b20370261b5e";
        internal const string PimcManagerCLSID = "C6659361-DABA-4746-931C-CAFE4B146690";
        internal const string IPimcManagerIID = "DBE0E8C4-DABA-41F3-B6A4-CAFE353D3D16";
        //internal const string PimcManagerCLSID = "c6659361-daba-4746-931c-cafe4b146690";
        //internal const string IPimcManagerIID = "dbe0e8c4-daba-41f3-b6a4-cafe353d3d16";
        //internal const string IPimcManagerIID = "af44bf80-36dd-4118-b4cf-8b1e3f4fb9ce";
    }

}

namespace ConsoleAppCOM
{

    class Program
    {

        [STAThread]
        static void Main(string[] args)
        {
            Test.MyImplementation mi = new Test.MyImplementation();
            Test.IPimcManager pimcManager = ((Test.IPimcManager)mi);


            uint cTablets = 0;
            pimcManager.GetTabletCount(out cTablets);

            System.Console.WriteLine(DateTime.Now + "-VALUE OBTAINED from PimcManager.GetTabletCount: " + cTablets);

            //Thread.Sleep(5);
            System.Console.ReadLine();
        }
    }

}

I've already tried STAThread, checked "Register for COM Interop" in server project properties, checked both client and server are targeted to x64 ...

I've created a COM Server in C++ and the same client works perfectly with the C++ COM Server. No InvalidCastException.

This is the IDL obtained from the type lib of the C# FakeServer:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: FakeServer.tlb

[
  uuid(A3CFF4E2-8724-461F-AFD4-D74583E89513),
  version(1.0),
  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "FakeServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

]
library FakeServer
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface IPimcManager;

    [
      odl,
      uuid(DBE0E8C4-DABA-41F3-B6A4-CAFE353D3D16),
      version(1.0),
      oleautomation,
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "MyTest.IPimcManager")    

    ]
    interface IPimcManager : IUnknown {
        HRESULT _stdcall GetTabletCount([out] unsigned long* count);
    };

    [
      uuid(C6659361-DABA-4746-931C-CAFE4B146690),
      version(1.0),
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "MyTest.MyImplementation")
    ]
    coclass MyImplementation {
        interface _Object;
        [default] interface IPimcManager;
    };
};

This is the IDL obtained from the type lib of the C++ COM Server (Please DO NOT CONSIDER the Name method added to the interface, I did it during my tests):

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: simplecomserver.tlb

[
  uuid(6F818C55-E6AD-488B-9EB6-511C0CCC0612),
  version(1.0),
  custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 134218331),
  custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1413900762),
  custom(DE77BA65-517C-11D1-A2DA-0000F8773CE9, "Created by MIDL version 8.00.0603 at Tue Oct 21 11:12:41 2014
")

]
library LibCOMServer
{
    // TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface ICOMServer;

    [
      odl,
      uuid(7F24AABF-C822-4C18-9432-21433208F4DC),
      oleautomation
    ]
    interface ICOMServer : IUnknown {
        HRESULT _stdcall Name([out, retval] BSTR* objectname);
        HRESULT _stdcall GetTabletCount([out] unsigned long* pcTablets);
    };

    [
      uuid(6AE24C34-1466-482E-9407-90B98798A712),
      helpstring("COMServer object")
    ]
    coclass CoCOMServer {
        [default] interface ICOMServer;
    };
};

Could there be any relationship with the C# coclass inheriting from interface _Object;?

coclass MyImplementation {
    interface _Object;
    [default] interface IPimcManager;
};

Any help is appreciated.

3
  • 1
    I would imagine the error is not on that line but on the next line as the error message suggests. Test.MyImplementation and MyTest.MyImplementation are different objects completely, it's like saying Banana myBanana = new Banana(); Car myCar = (Car)myBanana; Commented Oct 21, 2014 at 0:08
  • Yeah bro you don't want to cast a banana to a car, great analogy @DavidG Commented Oct 21, 2014 at 0:15
  • @DavidG and meda, this is COM not a simple OO program. The GUID relates the class to the corresponding class in the server. Commented Oct 21, 2014 at 1:03

4 Answers 4

0

please try this:

on your client class declaration, instead of

[ComImport]
[Guid(PimcConstants.PimcManagerCLSID)]
class MyImplementation
{
}

change it to interface and use parent interface GUID:

[ComImport]
[Guid(PimcConstants.IPimcManagerIID)]
interface MyImplementation:IPimcManager
    {
    }

hope it helps

Sign up to request clarification or add additional context in comments.

Comments

0

The InvalidCastException occurs in .NET Interop code whenever a COM object instance is being converted to another interface type , just like calling QueryInterface in C++, but as you have derived your interfaces from IUnknown, then you also need to provide the marshaling support, and its not an easy task, all you have to do is derive your interfaces from IDispath, the built in COM Marshaller oleaut32.dll would have taken care of your marshaling needs, as you are deriving from IUnknown then you need to also write your own custom marshaling code, the easier thing would be just replace the IUnknown with IDispath

1 Comment

if you Query one Interface, with one method then you don't need to Dispatch for MethodImpl. And marshaling is just about passing parameters to your Method, with simple types I don't see the need of marshaling, at least in C++
0

in Program try Test.IServer server = new Test.Server(); perhaps then you can call your MethodImpl like server.MethodImpl(params) because Interface(!) is providing your method in COM. Like calling COM from VBA - you don't care about CoClass, because you reference both COM and Class from typelib, last provides just interface for connection from which you call Method. I don't know COM providing classes. CoClass is being compiled with server, not client - you should not care about it in client.

p.s. but, frankly speaking, I have the same problem with NetSxS example with manifest in NET.Core 5.0 Reg-free COM

p.p.s I also had some exception about hostpolicy, but cannot reproduce it now... perhaps, it can be really some timeout, described here OR problem is in host-runtime-information: that example seemed to be really just for NET 7.0 Preview (not my 5.0) especially in part of Contract description. I even started to think about refactoring somehow...

Finally, <TargetPlatform>x86</TargetPlatform> helped for NET 5.0 for Win10 32x !!

Comments

-1

Perhaps your MyImplementation needs to implement IPimcManager (just like in your server code). Try:

class MyImplementation : IPimcManager
{
    public void GetTabletCount(out UInt32 count)
    {
        // implement your code here
    }
}

Hope this helps.

1 Comment

According to this tutorial msdn.microsoft.com/en-us/library/aa645736(v=vs.71).aspx and other info in the web I don't have to specify the interface here. I know it's weird but this is what all say. Anyway I have tried it and had a compilation error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.