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

时间:2013-11-13 09:49:58

标签: c# c++ c dll

我有一个用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变量中输入我的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;

也没有任何反应。

1 个答案:

答案 0 :(得分:2)

C#使用2字节字符串并相应地编组它们。 char *用于存储1字节字符串。 你必须在你的DllImport属性和usec wchar_t * strings中指定charset。

如果你需要将字符串存储在char *中,你可以编写一个自定义marshaller,就像这样称为

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