0

我有一个用 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# prog 中。我在 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 变量 =“Some string”的 c# prog 值。我怎么才能得到它?如果我使用 ref 或 out 像这样:

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

也没有任何反应。

4

1 回答 1

2

C# 使用 2 字节字符串并相应地编组它们。char* 用于存储 1 字节的字符串。您必须在您的 DllImport 属性中指定字符集并使用 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;
    }
}
于 2013-11-13T10:03:55.353 回答