I'm trying to import external c++ methods into my C# code.
I have modified a Windows driver which I'm using to access memory. To invoke the driver, I'm using c++ interface. Finally, to invoke the the interface connecting me to the driver, I use C# code.
The problem I'm facing is that during the runtime, I get following error System.EntryPointNotFoundException: Unable to find an entry point named 'GetTargetPid' in DLL 'API.dll'.
Now, The interface itself consists only of single header file. I thought that maybe that is the problem, however from what I've read online, using single header file even for implementation is perfectly fine.
This is my import in C#
[DllImport("API.dll")]
public static extern IntPtr GetTargetPid();
and here I Invoke the method
IntPtr processID = IntPtr.Zero;
...
ProcessID = GetTargetPid();
So my C# code is nothing special.
Now here is my 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;
}
Most of the examples I'v read online are using static methods, is that of any importance? what I need is working import, i think this should be trivial, however I can't figure it out.
You have two problems. First problem __declspec(dllexport) ULONG_PTR GetTargetPid()
compiles just fine and exports CDriver::GetTargetPid
. You don't want that.
In reading your CDriver code I'm convinced that it's not a singleton. If you really want to 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"
Second problem: you are P/Invoking a C function. Need Cdecl declarations in C#:
[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);
I can't tell from your code whether you compile ANSI or Unicode; fill in CharSet.???? correctly.
The usage of this stuff is like this:
IntPtr cdriver = null;
try {
cdriver = CreateCDriver("whatever");
var pid = GetTargetPid(cdriver);
// do whatever with pid
} finally {
DestroyCDriver(cdriver);
}
The moment you have to move a cdriver reference off the stack you need Dispose()
and 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;
}
}