6

私は2つの機能を持つc++dllを持っています

const char* getVersionText1(void);
void        getVersionText2(const char** res);

どちらの関数も、製品のバージョンを説明する文字列を返します。最初の関数はそれをconstchar*として返し(つまり、内部で割り当ててディールで検索します)、2番目の関数はchar *へのポインターを取得し、バージョンを説明するchar*を指すように設定します。

これらの関数をC#から呼び出して、テキストを表示したいと思います。関数の呼び出し順序が重要なので、[dllimport...]スタイルを使用できません。最初にgetVersionよりコンストラクターを呼び出し、最後にデストラクタを呼び出します。したがって、dllを最初にメモリにロードする必要があります。

両方の機能のテキストを印刷する数行のコードを投稿してください。私はC#を初めて使用するので、コードに問題があると思われる場合は申し訳ありません。

static class NativeMethods{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);
    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}
class Program{
    // Define function pointers to entires in DLL
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr getVersionText1();
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void getVersionText2(IntPtr );
    static void Main(string[] args){
        // Pointers to functions of DLL.
        getVersionText1 f1;
        getVersionText2 f2;
        IntPtr pDll = NativeMethods.LoadLibrary("p:\\my.dll");
        IntPtr pAddressOfFunctionToCall;
        pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText1 ");
        f1 = (getVersionText1)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText1));
        pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText2 ");
        f2 = (getVersionText2)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText2));

        // Here I don't know what to do. It doesn't work ????
        IntPtr verText = f1();
        String s = Marshal.PtrToStringAuto(verText);
        Console.WriteLine(s);   // Doesnt work
        // And how to use the second function. How do I sent a pointer to char* ???
    }
}
4

3 に答える 3

12

C++ ライブラリ関数が を返す場合char*、C# コードはそれを として扱い、C#IntPtrMarshal.PtrToStringAnsi()変換しstringます。

IntPtr verText = f1();
string s = Marshal.PtrToStringAnsi(verText);
Console.WriteLine(s);
于 2015-01-01T03:33:43.337 に答える
8

電話をかける方法は次のとおりです。utf8/string 変換を自動的に実行する、より短い代替手段があるかもしれません。

[DllImport("mydll.dll")]
public static extern IntPtr getVersionText1(void);
public string getVersionTextConst()
{
    IntPtr ptr = getVersionText1();
    // assume returned string is utf-8 encoded
    return PtrToStringUtf8(ptr);
}

[DllImport("mydll.dll")]
public static extern void getVersionText2(out IntPtr res);
public string getVersionTextConst()
{
    IntPtr ptr;
    getVersionText2(ptr);
    // assume returned string is utf-8 encoded
    String str = PtrToStringUtf8(ptr);
    // call native DLL function to free ptr
    // if no function exists, pinvoke C runtime's free()
    return str;
}

private static string PtrToStringUtf8(IntPtr ptr) // aPtr is nul-terminated
{
    if (ptr == IntPtr.Zero)
        return "";
    int len = 0;
    while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
        len++;
    if (len == 0)
        return "";
    byte[] array = new byte[len];
    System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
    return System.Text.Encoding.UTF8.GetString(array);
}
于 2013-02-19T08:55:24.500 に答える