【问题标题】:How to fix 'EntryPointNotFoundException'如何修复“EntryPointNotFoundException”
【发布时间】:2019-02-07 19:32:53
【问题描述】:

我正在尝试将外部 c++ 方法导入到我的 C# 代码中。

我修改了用于访问内存的 Windows 驱动程序。要调用驱动程序,我使用的是 c++ 接口。最后,为了调用将我连接到驱动程序的接口,我使用 C# 代码。

我面临的问题是,在运行时,我收到以下错误 System.EntryPointNotFoundException: Unable to find an entry point named 'GetTargetPid' in DLL 'API.dll'。

现在,接口本身只包含一个头文件。我认为这可能是问题所在,但是从我在网上阅读的内容来看,即使使用单个头文件来实现也非常好。

这是我在 C# 中的导入

[DllImport("API.dll")]
public static extern IntPtr GetTargetPid();

我在这里调用方法

IntPtr processID = IntPtr.Zero;
...
ProcessID = GetTargetPid();

所以我的 C# 代码没什么特别的。

现在这是我的 API.dll

extern "C"
{
...
class CDriver
{
public:
    //Handle to the driver
    HANDLE hDriver; 
    //Initialization of the handle              
    CDriver::CDriver(LPCSTR RegistryPath)
    {
        hDriver = CreateFileA(RegistryPath, GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
    }
    ...

    __declspec(dllexport)
    ULONG_PTR GetTargetPid()
    {
        if (hDriver == INVALID_HANDLE_VALUE)
            return false;

        PVOID Id = 0;
        ULONG_PTR Result;
        DWORD Bytes;

        if (DeviceIoControl(hDriver, IO_GET_PROCESS_ID, NULL, NULL,
            Id, sizeof(Id), &Bytes, NULL)) {

            Result = (ULONG_PTR)Id;
            return Result;
        }

        else
            return false;
    }

我在网上阅读的大多数示例都使用静态方法,这有什么重要性吗?我需要的是工作导入,我认为这应该是微不足道的,但我无法弄清楚。

【问题讨论】:

  • 这似乎是一个 c++ 问题,所以应该删除 c# 标签。
  • @RufusL:这是一个P/Invoke问题,双方的源代码。回答问题需要两种语言的知识;因此两个标签都属于。

标签: c# c++ pinvoke calling-convention


【解决方案1】:

你有两个问题。第一个问题__declspec(dllexport) ULONG_PTR GetTargetPid() 编译得很好并导出CDriver::GetTargetPid。你不想这样。

在阅读您的 CDriver 代码时,我确信它不是单例。如果你真的想 P/Invoke:

extern "C" {
__declspec(dllexport)
CDriver *CreateCDriver(LPCSTR RegistryPath)
{
    return new CDriver(RegistryPath);
}

__declspec(dllexport)
ULONG_PTR GetTargetPid(CDriver *driver)
{
    return driver->GetTargetPid();
}

__declspec(dllexport)
CDriver *DestroyCDriver(CDriver *driver)
{
    delete driver;
}
} // extern "C"

第二个问题:你正在 P/Invoking C 函数。需要 C# 中的 Cdecl 声明:

[DllImport("API.dll", CallingConvention=Cdecl, CharSet=CharSet.????)]
public static extern IntPtr CreateCDriver(string name);

[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr GetTargetPid(IntPtr cdriver);

[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr DestroyCDriver(IntPtr cdriver);

我无法从您的代码中看出您是编译 ANSI 还是 Unicode;填写字符集.????正确。

这玩意的用法是这样的:

IntPtr cdriver = null;
try {
    cdriver = CreateCDriver("whatever");
    var pid = GetTargetPid(cdriver);
    // do whatever with pid
} finally {
    DestroyCDriver(cdriver);
}

当您必须将 cdriver 引用移出堆栈时,您需要 Dispose()Finalize()

internal class CDriver : IDisposable {
    private IntPtr cdriver;

    public CDriver(string registry)
    {
        cdriver = CreateCDriver("whatever");
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SupressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        DestroyCDriver(cdriver);
        cdriver = IntPtr.Zero;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2022-07-19
    相关资源
    最近更新 更多