代码之家  ›  专栏  ›  技术社区  ›  Corey Ross

C++中的一个函数的IDL声明(C++)

  •  0
  • Corey Ross  · 技术社区  · 16 年前

    我正在使用一个由C++编写的一些带有C前端的COM接口组成的现有代码库。有一些新功能需要添加,所以我必须修改COM部分。在一个特定的情况下,我需要将一个数组(从C_分配)传递给要填充的组件。

    我想做的是能够从C向方法传递一个int数组,类似于:

    // desired C# signature
    void GetFoo(int bufferSize, int[] buffer);
    
    // desired usage
    int[] blah = ...;
    GetFoo(blah.Length, blah);
    

    工程中的几个扳手:

    • 不能使用C++/CLI或托管C++(在这种情况下可以取消COM)。
    • C端不能用/unsafe编译(允许使用marshal)。

    COM接口仅由C部分使用(仅将永远使用),因此我不太关心与其他COM使用者的互操作性。32位和64位之间的可移植性也不是问题(所有东西都是从32位机器编译和运行的,所以代码生成器将指针转换为整数)。最终,它将被替换为C++/CLI,但这是一种方法。


    我最初的尝试

    类似于:

    HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
    

    输出TLB定义(似乎合理):

    HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);
    

    由C进口(不太合理):

    void GetFoo(int bufferSize, ref int buffer);
    

    哪一个 能够 使用与

    int[] b = ...;
    fixed(int *bp = &b[0])
    {
        GetFoo(b.Length, ref *bp);
    }
    

    …只是我不能用/unsafe编译。


    此刻

    我正在使用:

    HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);
    

    其进口为:

    void GetFoo(int bufferSize, int buffer);
    

    我需要像这样使用它:

    int[] b = ...;
    GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
    try
    {
        GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
    }
    finally
    {
        bPin.Free();
    }
    

    这是可行的,但我想找一个更干净的方法。


    所以,问题是

    对于这种情况,是否有一个易于从TLB生成器导入C的IDL定义?如果没有,在C侧可以做些什么来让它更安全一点?

    3 回复  |  直到 16 年前
        1
  •  1
  •   Tony Lee    16 年前

    所以您需要一个IDL数据类型,在32位机器上是32位,在64位机器上是64位。但您不希望封送处理代码像指针一样对待它,就像int一样。那么,当您从64位进程调用32位进程时,您希望额外的32位发生什么呢?

    对我来说,听起来像是违反物理学。

    如果它只是Inproc,请参阅下面的讨论: http://www.techtalkz.com/vc-net/125190-how-interop-net-client-com-dll.html .

    建议似乎是使用void*而不是intptr,并用[local]标记,这样马歇尔就不会参与其中。

        2
  •  0
  •   Gerald    16 年前

    我对C COM的可操作性知之甚少,但您是否尝试过使用safearray(int u ptr)或类似的工具?

        3
  •  0
  •   Corey Ross    16 年前

    六羟甲基三聚氰胺六甲醚。。。我发现了一些能让我更接近的信息…

    Marshaling Changes - Conformant C-Style Arrays

    这个IDL声明(C++)

    HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
    

    导入为(msil)

    method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32& buffer) runtime managed internalcall
    

    如果更改为(msil)

    method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32[] marshal([]) buffer) runtime managed internalcall
    

    可用作(c)

    int[] b = ...;
    GetFoo(b.Length, b);
    

    正是我想要的!

    但是,是否有其他解决方案不需要修复由tlbimport生成的运行时可调用包装器的msil?