Создание базового C ++ .dll для p / invoke в C # - PullRequest
4 голосов
/ 13 января 2011

Я программист на C #, и, к сожалению, из-за возраста и опыта у меня не было роскоши получить шанс пройти через эру программирования на C ++ в моем обучении - многое из этого загадочно и ново для меня , Не совсем здесь, чтобы обсуждать важность изучения такого или нет, но мне нужна некоторая помощь в том, что должно быть тривиальным вопросом.

ПРОБЛЕМА

Мне нужна помощь в упаковке моего кода C ++ в .dll. У меня нет опыта работы с C ++, и я испытываю большие трудности с созданием рабочего .dll, из которого я могу выполнить p / invoc ( Visual Studio 2010 ). Пожалуйста, продолжайте читать для получения более подробной информации и кода, который я пытаюсь упаковать.

ОПИСАНИЕ

У меня есть код, который нужно запустить в неуправляемой среде. При нормальных обстоятельствах простой p / invoke подходит для этой задачи. Подключите немного [ImportDll] и все готово. В худшем случае я иногда могу использовать Marshalling. Однако по причинам, которые мне еще предстоит выяснить, это не представляется возможным с моей нынешней задачей.

Я пытаюсь прочитать некоторые данные из owner drawn list box, который был сделан в старом неуправляемом приложении C ++, и получить текст из него. Я видел несколько примеров, как это сделать, но они есть в более старом коде VB6.

Я обнаружил эквивалент C ++, но это тоже мне не подходит. Даже с p / invoke, похоже, много проблем с перемещением памяти и тем, как она должна работать. Процесс довольно прост.

Мне нужно создать простой C ++ .dll, который запускает нужный мне метод в неуправляемом коде и заполняет переменную результатом.

Как бы глупо это не звучало, Я не знаю, как это сделать . Я попытался просто запустить простой C ++ Wizards в Visual Studio (используя Visual Studio 2010), и мне просто не повезло. Я надеялся, что кто-нибудь может помочь мне пройти через это и, возможно, объяснить, что происходит, чтобы я мог извлечь из этого уроки.

Вот код, который мне нужно поместить в .dll.

Предполагается, что hListWnd будет передано как IntPtr в C #, index будет простым Int32, и outputResult перейдет к тому, что необходимо для выполнения этой работы. В других ситуациях p / invoke я видел, как это было сделано с System.Text.StringBuilder, но я готов работать с что угодно , чтобы сделать эту работу правильной.

void GetListItemData( HWND hListWnd, long index, char *outputResult )
{
    int result;
    DWORD processID;
    HANDLE hProcess;
    char *itemData;
    char sDataRead[5];
    DWORD bytes;
    DWORD lListItemHold, lListItemDataHold;
    *outputResult=0;

    if( hListWnd )
    {
        GetWindowThreadProcessId( hListWnd, &processID );

        hProcess=OpenProcess( 0x10|0xf0000|PROCESS_VM_READ, 0, processID );

        if( hProcess )
        {
            lListItemHold=(DWORD)SendMessage( hListWnd, LB_GETITEMDATA, index-1, 0 );
            lListItemHold=lListItemHold+24;

            result=ReadProcessMemory( hProcess, (void *)lListItemHold, &sDataRead, 4, &bytes );
            if( !result )
            {
                RaiseWinErr();
            }

            memcpy( &lListItemDataHold, &sDataRead, 4 );
            lListItemDataHold=lListItemDataHold+6;

            ReadProcessMemory( hProcess, (void *)lListItemDataHold, outputResult, 16, &bytes );

            CloseHandle( hProcess );
        }
    }
}

Если кто-нибудь может мне помочь, пожалуйста, я умоляю здесь. Это стало очень неприятной проблемой для меня. Я пытался воспроизвести это в C #, используя RtlMoveMemory и ReadProcessMemory p / invoke, но безрезультатно. Я охотился на дни и дни, и продолжаю придумывать мертвые результаты. Я знаю, что некоторый код не имеет большого смысла (у меня были люди, спрашивающие меня, почему он требует +6 и что такое +24, и т. Д.), И абсолютная правда в том, что я не t полностью знаю. Что я знаю, так это то, что в списке *1048*, нарисованном владельцем, используется некоторая графика, и цель этих смещений состоит в том, чтобы исследовать данные за пределами области рисования графической области, поскольку фактическая структура List Item неизвестно.

Другой метод, который я попробовал, - это получение моего элемента в виде IAccessible с использованием библиотеки Accessibility.dll. Это тоже оказалось бесплодным. Я также попробовал ManagedWinApi с pinvoke.net, и библиотеки там не оказались успешными.

Я знаю, что этот код работает. Это просто не работает в C #. Моя теория состоит в том, что использование [DllImport] для вызова его в C # даст мне желаемый результат.

Еще раз спасибо за любую помощь.

1 Ответ

6 голосов
/ 13 января 2011

Третий параметр должен быть байтом [], маршалированным как char *, размером 16.

Если вы проверяете документацию для ReadProcessMemory, он принимает буфер и размер, и эта функция передаетразмер как 16 байтов.Это означает, что вам понадобится 16-байтовый массив.Среда выполнения должна быть совершенно счастлива маршалировать байт [] размера 16. Будьте осторожны, чтобы не смешивать символ C ++ с символом C # - символ C # на самом деле является C ++ wchar_t в Windows.Символ C ++ - это байт C #.

Не то чтобы я имел какое-то представление о том, как работают эти функции - я только что проследил использование третьего параметра, и он фактически передается только в ReadProcessMemory, параметры которого довольночетко задокументировано.

Чтобы упаковать в .dll (при условии, что вам больше нечего добавить в этот .dll), вы хотите добавить в начало пару вещей, чтобы попросить компилятор C ++ не искажать имяи экспортировать его для вас, выдав это в виде первой строки

extern "C" __declspec(dllexport) void GetListItemData( HWND hListWnd, long index, char *outputResult )

Вам понадобится только один исходный файл C ++, без заголовков, и скомпилируйте его как DLL (это в настройках проекта).Вам не понадобится никакой код, кроме функции и любых необходимых вам включений.

В C #

[System.Runtime.InteropServices.DllImport(
    DLLPath,
    CallingConvention = CallingConvention.Cdecl
)]
private static extern void GetListItemData(
    System.IntPtr hWnd,
    System.Int32 index,
    [MarshalAs(UnmanagedType.LPArray)]byte[] buffer
);

К сожалению, вы должны убедиться, что буфер имеет достаточный размер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...