[英]How to expose nullable types via COM
我一直在努力解決這個問題一天半,希望有人可以幫助我。 假設我在C#中有這樣的結構:
public struct Part
{
public double? x; // or System.Nullable<double> x, doesn't really matter
}
(這些結構表示數據庫表,從Linq轉換為SQLMetal創建的SQL代碼)
我需要能夠將包含可空類型的這些結構公開給COM,以便它們可以在另一個應用程序(C ++)中使用。 但我無法弄清楚,對於我的生活,如何做到這一點。 我以為我可以創建類來封裝可空類型:
public class NullableDouble
{
private double _Value;
// class methods...
}
public struct Part
{
public NullableDouble x;
}
這種工作,但在C ++方面,我最終得到一個指向類的指針,但沒有類定義(只是一個接口):
interface DECLSPEC_UUID("{E8EE4597-825D-3F4C-B20B-FD6E9026A51C}") _NullableDouble;
struct Part
{
MyDll_tlb::_NullableDouble* x;
}
因此,我無法取消引用沒有類定義的指針,從中可以訪問C ++端的數據成員/方法。 如果我能弄清楚如何在C ++中獲取類定義(我是COM的新手),這仍然是一個不錯的選擇。
我想也許我可以使用不安全的代碼,但我無法弄清楚如何從雙轉換? 加倍*(我也是C#的新手!):
unsafe public struct Part
{
public double* x;
}
Part part = new Part()
{
x = AnotherObject.x // AnotherObject.x is a System.Nullable<double>
}
我想也許我可以使用System.Variant,但C#也不喜歡它(不一致的可訪問性,無論這意味着什么)。
public struct Part
{
public Variant x;
// produces 2 errors:
// 1) System.Variant inaccessible,
// 2) inconsistent accessibility
}
我已經使用C ++ 20年了,但我對COM和C#還是比較陌生的,所以這對我來說有點困難。
最壞情況......我將在結構中為每個可空類型創建一個布爾成員,並使用它來指示是否將值視為null。 但這似乎很愚蠢。 當然必須有一些方法通過COM公開可空類型。 為什么Microsoft會創建無法在COM中使用的.NET類型? 雷德蒙德的那些家伙不是白痴(雖然有時候看起來確實如此)。
那么,我的選擇是什么? 做這個的最好方式是什么?
提前致謝。
你可以使用type object
而不是double?
對於您的結構字段並將[MarshalAs(UnmanagedType.Struct)]
應用於它以將其編組為VARIANT
。 這是一篇關於這個主題的優秀文章 。
代碼示例:
C#:
using System.Runtime.InteropServices;
namespace InteropTest
{
[ComVisible(true)]
public struct TestStruct
{
[MarshalAs(UnmanagedType.Struct)]
public object testField;
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("6E0DD830-1BF9-41E0-BBEB-4CC314BBCB55")]
public class TestClass
{
public void GetTestStruct(ref TestStruct p)
{
double? testValue = 1.1;
p.testField = testValue;
}
}
}
注冊 (用於32位匯編):
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /codebase /tlb InteropTest.dll
C ++:
#include "stdafx.h"
#import "InteropTest.tlb" raw_interfaces_only
#define _S(a) \
{ HRESULT hr = (a); if (FAILED(hr)) return hr; }
int _tmain(int argc, _TCHAR* argv[])
{
_S( CoInitialize(NULL) )
InteropTest::_TestClassPtr testClass;
_S( testClass.CreateInstance(__uuidof(InteropTest::TestClass)) );
InteropTest::TestStruct s;
VariantInit(&s.testField);
_S( testClass->GetTestStruct(&s) );
printf("Value: %f", V_R8(&s.testField));
CoUninitialize();
return 0;
}
輸出:
Value: 1.100000
如果該字段設置為null
( double? testValue = null;
該類型返回的VARIANT
將VT_EMPTY
,否則就VT_R8
。
另外,將類接口公開給COM 並不是一個好習慣 。 您可能想為此創建一個單獨的界面。 采用這種方法,您可以基於IUnknown
公開您的界面,因為您不需要C ++的IDispatch
管道:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("E3B77594-8168-4C12-9041-9A7D3FE4035F")]
public interface ITestClass
{
void GetTestStruct(ref TestStruct p);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITestClass))]
[Guid("6E0DD830-1BF9-41E0-BBEB-4CC314BBCB55")]
public class TestClass : ITestClass
{
public void GetTestStruct(ref TestStruct p)
{
double? testValue = 1.1;
p.testField = testValue;
}
}
C ++:
InteropTest::ITestClassPtr testClass;
_S( testClass.CreateInstance(__uuidof(InteropTest::TestClass)) );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.