Как исправить «EntryPointNotFoundException» - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь импортировать внешние методы c ++ в мой код C #.

Я изменил драйвер Windows, который я использую для доступа к памяти.Чтобы вызвать драйвер, я использую интерфейс C ++.Наконец, для вызова интерфейса, связывающего меня с драйвером, я использую код C #.

Проблема, с которой я сталкиваюсь, заключается в том, что во время выполнения я получаю следующую ошибку System.EntryPointNotFoundException: Невозможно найти точку входа с именем «GetTargetPid» в 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;
    }

Большинство примеров, которые я читал онлайн, используют статические методы, это имеет какое-то значение?мне нужно работать с импортом, я думаю, что это должно быть тривиально, однако я не могу понять это.

1 Ответ

0 голосов
/ 07 февраля 2019

У вас две проблемы.Первая проблема __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 / вызываете функцию C.Нужны объявления Cdecl в 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);

Я не могу определить из вашего кода, компилируете ли вы 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;
    }
}
...