簡體   English   中英

從VB6到托管C#方法的C ++ / CLI包裝器

[英]VB6 to C++/CLI wrapper around managed C# method

關於SO和網絡(例如pinvoke.net)的大量信息描述了從托管代碼中調用非托管代碼。 我處於一種特殊的情況下,我需要為舊版VB6應用程序實現API,但由於業務原因無法更改。 為了簡潔起見,可以說VB6應用程序執行以下操作。

'Legacy VB6
Public Declare Function GetData Lib "NewDLL" (ByVal szDataID As String, 
ByRef DataStruct As TDataStruct) As Long

Type TDataStruct
    szSKU       As String * 10
    szTypeInfo  As String * 20
End Type

這是我的處理方法。

C ++ / CLI實現。

//NewDLL.h
typedef struct DATASTRUCT
{
   char szSKU      [10];
   char szTypeInfo [20];
];

//NewDLL.cpp - C++/CLI
#include "NewDLL.h"
using namespace System;

extern "C" __declspec(dllexport)
Int32 __stdcall GetData(LPTSTR szDataID, DATASTRUCT* dataStruct)
{
   String^ m_DataID;

   m_DataID = gcnew String(szDataID);

   NewDotNetDll::GetDataClass::GetData(m_DataID, dataStruct);
   return (true);
}

.NET實現。

//DataStruct.cs
using etc...
using System.Runtime.InteropServices;
namespace NewDotNetDll
{
    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
    public struct DataStruct
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string SkuID;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string TypeInfo;
    }
}

//GetDataClass.cs
using etc...
using System.Runtime.InteropServices;

namespace NewDotNetDll
{
    public class GetDataClass
    {
        public static Int32 GetData(
            [MarshalAs(UnmanagedType.LPStr)] string skuID,
            [Out, MarshalAs(UnmanagedType.LPStruct)] DataStruct dataStruct)
        {
            Int32 rc = 0;
            //to do...
            return rc;
        }
     }
}

問題-如何通過引用將VB的TDataStruct傳遞給C#方法,以便它可以作用於內存中的非托管結構? 預先感謝大家。

如果要將結構映射到現有的非托管內存,則該結構不能包含托管類型(不滿足相同條件的對象引用或結構)。

string是托管類型,它包含UTF-16字符。 您的數據結構包含8位C ++ char 所以這不合適。

byte[] 也是托管類型,因為數組實際上是對C#中對象的引用。 因此,您也不能使用它。

讓我們通過使用固定大小的緩沖區解決這個問題

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public unsafe struct DataStruct
{
    public fixed byte SkuID[10];
    public fixed byte TypeInfo[20];
}

現在我們可以在C#中聲明一個指向該結構的指針:

public unsafe static Int32 GetData(string skuID, DataStruct *dataStruct)
{
    dataStruct->SkuID[0] = 65;
    dataStruct->SkuID[1] = 0;
    return 42;
}

並且此時無需使用MarshalAsAttribute

這是字符串處理的示例(將skuID復制到dataStruct->SkuID ):

public unsafe static Int32 GetData(string skuID, DataStruct *dataStruct)
{
    var skuIdBytes = Encoding.ASCII.GetBytes(skuID);
    if (skuIdBytes.Length >= 10)
        throw new ArgumentOutOfRangeException(nameof(skuID), "skuID is too long");

    Marshal.Copy(skuIdBytes, 0, new IntPtr(dataStruct->SkuID), skuIdBytes.Length);
    dataStruct->SkuID[skuIdBytes.Length + 1] = 0;

    return 42;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM