0

アンマネージドc++dllをインポートするac#マネージドプロジェクトがあります。私が望んでいたのは、C#コードで記述したロギング関数を使用してロギングを機能させることでした。そこで、C#側に次を追加しました。

public struct API 
{
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void FunctionPointer(string msg);

    [DllImport("mydll.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    unsafe public static extern void setLoggerPointer(IntPtr fctPointer);

    [DLLImport("mydll.dll", SetLastError = true)]
    [return: MarshalAsAttribute(UnmanagedType.I1)] unsafe public static extern bool init();
}

public unsafe class MyInterface
{
    public MyInterface()
    {
        API.FunctionPointer loggerDelegate;
        loggerDelegate = new API.FunctionPointer(Logger.LogMessage);
        IntPtr loggerPtr = Marshal.GetFunctionPointerForDelegate(loggerDelegate);
        API.setLoggerPointer(loggerPtr);

        if (API.init()) 
        {
           //do stuff
        }
    }
}

これが私のロガークラスの定義です:

public static class Logger
{
    public static void LogMessage(string msg)
    {
        Console.WriteLine(msg);
        fileStream.Write(msg);
    }
}

私はc++側のヘッダーに次のものを持っています:

#define MY_C_API extern "C" __declspec(dllexport);

MY_C_API __declspec(dllexport) void __stdcall setLoggerPointer( void *fctPointer(LPCTSTR msg) );
MY_C_API __declspec(dllexport) bool __stdcall init();

そしてC++ソースでは:

//global variable
void *(*logger)(LPCTSTR msg);

void __stdcall setLoggerPointer( void *fctPointer(LPCTSTR msg) )
{
    logger = fctPointer;
}

bool __stdcall init()
{
    logger("WOOO");

    return true;  //I'm getting the AccessViolation right here
}

mfc100.dll内のatlsimpstr.hRelease()関数のinit()関数から戻ると、System.AccessViolationExceptionが発生します。

誰かが私が間違っていることを知っていますか?この種のことについて私が見たすべての質問は、アクセス違反なしで逆P / Invokeを実行する方法でしたが、それは私にとってはうまく機能しています。他の呼び出しから戻ったときに、そのセクションが台無しになっているようです。メモリはC#アプリケーションの一部と見なされるようになりました。

4

1 に答える 1

2

問題は、コールバックの呼び出し規約が一致しないことです。ネイティブコードはコールバックがであると想定していますcdeclが、マネージコードはコールバックがであると宣言していますstdcall。これは、マネージコードまたはネイティブコードのいずれかで修正できます。簡単にするために、マネージコードで修正する方法を示します。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FunctionPointer(string msg);

他のいくつかのポイント:

  1. 関数がWin32の最後のエラーを設定していないため、SetLastErrorパラメータをに設定しないでください。true
  2. unsafeこのコードのどこでも使用しないでください。原則として、避けるべきunsafeであり、これには必要ありません。
于 2013-03-04T18:17:30.997 に答える