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# プログラムに取り込む必要があります。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 属性で charset を指定し、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 に答える