2014-10-21 1 views
0

Я знаю, что есть много вопросов по этой теме, но я считаю, что через все эти последние 10 дней я прошел через все, и я не мог найти решение ошибки, с которой я сильно страдаю.InvalidCastException с COM-клиентом и сервером в C#

У меня есть COM-сервер dll в C# и COM-клиент в C#. Все в Windows 7. Я получаю InvalidCastException, и я не могу решить проблему. Я начинаю сомневаться в возможности создания COM-сервера на C#.

У меня это исключение при создании экземпляра объекта COM в:

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

System.InvalidCastException был необработанным HResult = -2147467262 сообщение = Невозможно привести объект типа «MyTest.MyImplementation 'для ввода «Test.MyImplementation». Источник = ConsoleApplication3 StackTrace: в ConsoleAppCOM.Program.Main (String [] арг) в C: \ Users \ rkohn \ Documents \ Visual Studio 2013 \ Projects \ ConsoleApplication3 \ ConsoleApplication3 \ Program.cs: линия 48 в системе. AppDomain._nExecuteAssembly (RuntimeAssembly сборки, String [] арг) на Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() в System.Threading.ExecutionContext.RunInternal (ExecutionContext ExecutionContext, ContextCallback обратного вызова, состояние объекта, Boolean preserveSyncCtx) в системе .Threading.ExecutionContext.Run (ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта, Boolean preserveSyncCtx) в System.Threading.ExecutionContext.Run (ВыполнениеКонтекстовый запускКонтекст, ContextCallback c Allback, состояние объекта) на System.Threading.ThreadHelper.ThreadStart() InnerException:

Это код COM-сервер:

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; 
     } 
    } 
} 

Это код клиента:

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(); 
     } 
    } 

} 

Я уже пробовал STAThread, проверил «Register for COM Interop» в свойствах проекта сервера, проверял, что оба клиента и сервер нацелены на x64 ...

Я создал COM-сервер на C++, и тот же клиент отлично работает с C++ COM-сервером. Нет InvalidCastException.

Это IDL получается из типа Lib в 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; 
    }; 
}; 

Это IDL получается из типа Lib на C++ COM-сервер (Пожалуйста, НЕ СЧИТАЮТ метод имя добавлено к интерфейс, я сделал это во время моих тестов):

// 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; 
    }; 
}; 

Может ли быть какие-либо отношения с C# компонентного класса наследует от интерфейса _Object ;?

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

Любая помощь приветствуется.

+1

Я бы предположил, что ошибка не в этой строке, а на следующей строке, как следует из сообщения об ошибке. 'Test.MyImplementation' и' MyTest.MyImplementation' - это разные объекты полностью, это как сказать «Banana myBanana = new Banana(); Автомобиль myCar = (Car) myBanana; ' – DavidG

+0

Да, вы не хотите бросать банан в машину, отличная аналогия @DavidG – meda

+0

@DavidG и meda, это COM не простая программа OO. GUID связывает класс с соответствующим классом на сервере. – rodolk

ответ

0

Возможно, ваш MyImplementation должен реализовать IPimcManager (как и в коде сервера).Попытка:

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

Надеюсь, это поможет.

+0

В соответствии с этим уроком http://msdn.microsoft.com/en-us/library/aa645736(v=vs.71).aspx и другой информацией в Интернете мне не нужно указывать здесь интерфейс. Я знаю, что это странно, но это то, что все говорят. Во всяком случае, я пробовал это и имел ошибку компиляции. – rodolk

0

пожалуйста, попробуйте следующее:

на вашем классе клиента декларации, вместо

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

изменить его интерфейс и использование родительского интерфейса GUID:

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

надеюсь, что это помогает

0

Обычный шаблон, объявляющий совместно создаваемый COM-класс в вашем .NET-клиенте, требует не просто объявления класса (например, FooClass ниже), но интерфейс класса (Foo), который вы будете использовать вместе с new (new Foo()). Например:

[ComImport] 
[Guid(IIDs.IFoo)] // IIDs.IFoo is a string constant containing the interface's IID 
[CoClass(typeof(FooClass))] 
public interface Foo : IFoo { } 

[ComImport] 
[Guid(CLSIDs.Foo)] // CLSIDs.Foo is a string constant containing the co-class' CLSID 
[ComDefaultInterface(typeof(IFoo))] 
public class FooClass { } 

 Смежные вопросы

  • Нет связанных вопросов^_^