更改 c/c++ dll 中的参数

Changing parameters in c/c++ dll

本文关键字:参数 dll c++ 更改      更新时间:2023-10-16

我有一个用C语言编写的DLL。我在这个dll中有一个函数,例如:

unsigned char DLL_EXPORT getTRK(char *XML, unsigned long *Len)
{
    MessageBox(NULL, XML, "Dll message", MB_OK);
    char s[] = "Some string";
    XML = s;
    return rand()%2;
}

我需要更改 dll 中的 XML 变量值,并将此值带到我的 C# 程序中。我有关于 C# 的下一个代码:

[DllImport("Some_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte getTRK(string XML, uint Len);
...
string xml = "123";
uint len = 0;
tbXml.Clear();
if (getTRK(xml, len) == 0)
{
   tbXml.AppendText(xml);
}
else
{
   tbXml.AppendText("Some error!");
}

我已经尝试了不同的方法来做到这一点,但没有像需要的那样工作。我想输入 xml 变量 = "某个字符串" 的 c# prog 值。我怎样才能得到它?如果我使用 ref 或像这样:

[DllImport("Some_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte getTRK(ref string XML, ref uint Len);
...
string xml = "123";
uint len = 0;
tbXml.Clear();
if (getTRK(ref xml, ref len) == 0)
{
   tbXml.AppendText(xml);
}
else
{
   tbXml.AppendText("Some error!");
}

DLL 获取一些垃圾值,而不是"123"。 如果我这样做:

*XML = *s;

也什么也没发生。

C# 使用 2 字节字符串并相应地封送它们。 char* 用于存储 1 字节字符串。您必须在 DllImport 属性和 usec wchar_t* 字符串中指定字符集。

如果你需要将字符串存储在 char* 中,你可以编写一个自定义编组器,它被称为这样的东西

void ErrorWriter([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string errorMessage, string taskId, ProcessType processType);

并像这样实现

internal class Utf8Marshaler : ICustomMarshaler
{
    private static Utf8Marshaler _staticInstance;
    public IntPtr MarshalManagedToNative(object managedObj)
    {
        if (managedObj == null)
            return IntPtr.Zero;
        if (!(managedObj is string))
            throw new MarshalDirectiveException(
                "UTF8Marshaler must be used on a string.");
        // not null terminated
        byte[] strbuf = Encoding.UTF8.GetBytes((string) managedObj);
        IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length+1);
        Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
        // write the terminating null
        Marshal.WriteByte(buffer + strbuf.Length, 0);
        return buffer;
    }
    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        if (pNativeData == IntPtr.Zero)
            return string.Empty;
        int length = 1;
        IntPtr offsetPtr = IntPtr.Add(pNativeData, 1);
        while (Marshal.ReadByte(offsetPtr) != 0)
        {
            offsetPtr = IntPtr.Add(offsetPtr, 1);
            length++;
        }
        byte[] strbuf = new byte[length];
        Marshal.Copy(pNativeData, strbuf, 0, length);
        string data = Encoding.UTF8.GetString(strbuf);
        return data;
    }
    public void CleanUpNativeData(IntPtr pNativeData)
    {
        Marshal.FreeHGlobal(pNativeData);
    }
    public void CleanUpManagedData(object managedObj)
    {
    }
    public int GetNativeDataSize()
    {
        return -1;
    }
    public static ICustomMarshaler GetInstance(string cookie)
    {
        if (_staticInstance == null)
        {
            return _staticInstance = new Utf8Marshaler();
        }
        return _staticInstance;
    }
}