如何修复 'EntryPointNotFoundException'
How to fix 'EntryPointNotFoundException'
我正在尝试将外部 C++ 方法导入到我的 C# 代码中。
我已经修改了我用来访问内存的 Windows 驱动程序。为了调用驱动程序,我使用的是 C++ 接口。最后,为了调用将我连接到驱动程序的接口,我使用了 C# 代码。
我面临的问题是在运行时,出现以下错误 System.EntryPointNotFoundException:无法在 DLL 'API.dll' 中找到名为 'GetTargetPid' 的入口点。
现在,接口本身只包含一个头文件。我认为这可能就是问题所在,但是根据我在网上阅读的内容,即使在实现中使用单个头文件也非常好。
这是我在 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;
}
我在网上看到的大多数例子都是使用静态方法,这重要吗?我需要的是工作导入,我认为这应该是微不足道的,但我无法弄清楚。
你有两个问题。第一个问题 __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;填写CharSet。????正确。
这东西的用法是这样的:
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;
}
}
我正在尝试将外部 C++ 方法导入到我的 C# 代码中。
我已经修改了我用来访问内存的 Windows 驱动程序。为了调用驱动程序,我使用的是 C++ 接口。最后,为了调用将我连接到驱动程序的接口,我使用了 C# 代码。
我面临的问题是在运行时,出现以下错误 System.EntryPointNotFoundException:无法在 DLL 'API.dll' 中找到名为 'GetTargetPid' 的入口点。
现在,接口本身只包含一个头文件。我认为这可能就是问题所在,但是根据我在网上阅读的内容,即使在实现中使用单个头文件也非常好。
这是我在 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;
}
我在网上看到的大多数例子都是使用静态方法,这重要吗?我需要的是工作导入,我认为这应该是微不足道的,但我无法弄清楚。
你有两个问题。第一个问题 __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;填写CharSet。????正确。
这东西的用法是这样的:
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;
}
}