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

这是我的 Logger 类定义:

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.h Release() 函数中的 init() 函数返回时,我得到了 System.AccessViolationException

有人知道我在做什么错吗?我看到的关于这类事情的所有问题都是如何在不违反访问权限的情况下进行反向 P/Invoke,但它对我来说工作正常,只是当从另一个调用返回时它被搞砸了,好像那部分内存现在被认为是 C# 应用程序的一部分。

4

1 回答 1

2

问题是回调的调用约定不匹配。您的本机代码期望回调为cdecl,但托管代码将其声明为stdcall。您可以在托管代码或本机代码中解决此问题。为简单起见,我将展示如何在托管代码中修复它。

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

其他几点:

  1. 不要将SetLastError参数设置为,true因为您的函数没有设置 Win32 上一个错误。
  2. 不要unsafe在此代码中的任何地方使用。作为一般规则,您应该避免unsafe,并且您不需要它来做任何事情。
于 2013-03-04T18:17:30.997 回答