如何通过COM暴露可空类型 [英] How to expose nullable types via COM

查看:80
本文介绍了如何通过COM暴露可空类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力解决这个问题了一天半的时间,希望有人能帮助我。比方说,我有这样的结构在C#中:

I have been struggling with this problem for a day and a half, hopefully someone can help me. Let's say I have structures like this in C#:

public struct Part
{
    public double? x;  // or System.Nullable<double> x, doesn't really matter
}



(这些结构代表了数据库表,从转换LINQ到由SQLMetal创建SQL代码)

(these structures represent database tables, converted from Linq to SQL code created by SQLMetal)

我需要能够以暴露这些结构中,含有空类型,对COM,使他们能够在另一应用程序(℃使用++ )。但我想不通,我用我的生命,如何做到这一点。我想我可以创建类来封装可空类型:

I need to be able to expose these structures, containing nullable types, to COM so that they can be used in another application (C++). But I cannot figure out, for the life of me, how to do this. I thought I could create classes to encapsulate the nullable types:

public class NullableDouble
{
    private double _Value;
    // class methods...
}

public struct Part
{
    public NullableDouble x;
}



之类的作品,但在C ++方面,我结束了一个指针一类,但没有类定义(只是一个接口):

That sort of works, but on the C++ side, I end up with a pointer to a class but no class definition (just an interface):

interface DECLSPEC_UUID("{E8EE4597-825D-3F4C-B20B-FD6E9026A51C}") _NullableDouble;

struct Part
{
    MyDll_tlb::_NullableDouble* x;
}



因此,我不能提领没有一个类定义的指针从中访问数据成员在C ++侧/方法。这仍然似乎是一个不错的选择,如果我可以弄清楚如何获取类的定义在C ++(我是新来的COM)。

Thus, I cannot dereference that pointer without a class definition from which to access the data members/methods on the C++ side. This still seems like a good option, if I can just figure out how to get the class definition in C++ (I'm new to COM).

我想也许我可以使用不安全的代码,但我无法弄清楚如何从双重转换?双*(我是新的C#呢!):

I thought maybe I could use unsafe code, but I can't figure out how to convert from double? to double* (I'm new to C# too!):

unsafe public struct Part
{
    public double* x;
}

Part part = new Part()
{
    x = AnotherObject.x // AnotherObject.x is a System.Nullable<double>
}



我想也许我可以用System.Variant,但C#不喜欢要么(可访问性不一致,知道是什么意思)。

I thought maybe I could use System.Variant, but C# doesn't like that either (inconsistent accessibility, whatever that means).

public struct Part
{
    public Variant x;  
    // produces 2 errors: 
    //   1) System.Variant inaccessible, 
    //   2) inconsistent accessibility
}

我一直使用C ++ 20年了,但我是相当新的COM和C#,所以这是一个有点对我来说是奋斗。

I've been using C++ for 20 years, but I am fairly new to COM and C#, so this is a bit of a struggle for me.

最坏的情况......我只是建立在结构中的每个可空类型的布尔成员并用它来指示值是否被视为如果是空。但是,这似乎只是愚蠢。毫无疑问,我们必须有某种方式通过COM暴露可空类型。为什么微软创建不能在COM中使用.NET类型?在雷蒙德那些家伙都不是傻瓜(虽然有时它肯定好像它)。

Worst-case scenario...I'll just create a boolean member in the struct for each of the nullable types and use that to indicate whether the value is to be treated as if it is null. But that just seems stupid. Surely there must be some way to expose nullable types via COM. Why would Microsoft create .NET types that can't be used in COM? Those guys in Redmond aren't idiots (although sometimes it sure seems like it).

那么,什么是我的选择?什么是做到这一点的最好方法是什么?

So, what are my options? What is the best way to do this?

先谢谢了。

推荐答案

您可以用键入对象而不是翻番?为您的结构领域和应用 [的MarshalAs(UnmanagedType.Struct)] 将其编组为 VARIANT 。这里是href=\"http://blogs.msdn.com/b/adam_nathan/archive/2003/04/24/56642.aspx\" rel=\"nofollow\">关于这个问题优秀文章的

You could use type objectinstead of double? for your structure field and apply [MarshalAs(UnmanagedType.Struct)] to it to marshal it as VARIANT. Here's an excellent article on the subject.

代码示例:

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位汇编):

Register (for a 32-bit assembly):

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

如果该字段设置为双testValue = NULL; ?)时,的键入返回 VARIANT 将 VT_EMPTY ,否则就 VT_R8

If the field is set to null (double? testValue = null;), the type of the returned VARIANT will be VT_EMPTY, otherwise it's VT_R8.

在一个侧面注意,它的是不是一个好的做法揭露一类接口的COM。您可能要创建一个单独的接口。采用这种方法,您可以根据的IUnknown 暴露你的界面,因为你不需要的IDispatch 水暖C ++

On a side note, it is not a good practice to expose a class interface to COM. You may want to create a separate interface for that. Taking this approach, you can expose your interface as based on IUnknown, because you don't need IDispatch plumbing for C++:

[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)) );

这篇关于如何通过COM暴露可空类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆