PInvoke Вылеает программа после завершения импортной функции

260
31 июля 2017, 10:48

C++ DLL:

#include "stdafx.h"
#include "windows.h"
#include "psapi.h"
#include "stdlib.h"
typedef struct PROCINF {
    DWORD dwPID;
    LPWSTR lpMainModName;
} *LPPROCINF;

extern "C" __declspec(dllexport) void GetProcessInfo(LPPROCINF lppi)
{
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, lppi->dwPID);
    if (hProcess == NULL) return;
    MessageBox(NULL, L"GET MAIN MOD NAME", NULL, NULL);
    //
    // Get process main module name.
    //
    lppi->lpMainModName = (LPWSTR)malloc(MAX_PATH * sizeof(wchar_t));
    GetModuleFileNameEx((HMODULE)hProcess, NULL, lppi->lpMainModName, MAX_PATH * sizeof(wchar_t));
    CloseHandle(hProcess);
}

C#:

    [StructLayout(LayoutKind.Sequential)]
    struct PROCINF {
        public uint dwPID;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string lpMainModName;
    }
    [DllImport("my.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern void GetProcessInfo(ref PROCINF info);
    // ...
        PROCINF pinfo = new PROCINF();
        pinfo.dwPID = 3604;
        GetProcessInfo(ref pinfo);
        MessageBox.Show("PID: " + pinfo.dwPID + Environment.NewLine +
                "Main module: " + pinfo.lpMainModName);

После завершения GetProcessInfo сразу вылетает программа, причём без ошибок. В чём проблема понять не могу, т.к. вроде как импортирую правильно (если убрать GetModuleFileNameEx и malloc, заменив заполнение значения пустой строкой, всё будет работать хорошо).

Answer 1

Вот решение с библиотекой на C++/CLI.

  1. Добавьте в проект библиотеку на C++/CLI. В Visual Studio 2017 это называется «CLR class library».
  2. Положите в этой библиотеке в заголовочном файле следующие определения:

    #pragma once
    #include "windows.h"
    #include "psapi.h"
    using namespace System;
    namespace InteropLibrary
    {
        public ref class ProcInf
        {
        public:
            UInt16 ProcessId;
            String^ MainModuleName;
        };
        public ref class ProcessHelper abstract sealed // аналог статического класса
        {
        public:
            static Boolean GetProcessInfo(ProcInf^ lppi)
            {
                HANDLE hProcess = OpenProcess(
                        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                        FALSE,
                        lppi->ProcessId);
                if (hProcess == NULL) return false;
                wchar_t moduleName[MAX_PATH + 1];
                // размер в символах, поэтому не удваиваем его
                auto nameSize = GetModuleFileNameEx(
                        (HMODULE)hProcess, NULL, moduleName, MAX_PATH);
                if (nameSize > 0)
                    lppi->MainModuleName = gcnew String(moduleName, 0, nameSize);
                CloseHandle(hProcess);
                return nameSize > 0;
            }
        };
    }

    О том, как создавать сигнатуры методов для C++/CLI, можно посмотреть, например, здесь.

  3. В C#-части выберите таргет с конкретной битностью (x86 или x64). Подключите часть на C++/CLI как project reference.

  4. В C#-коде вызывайте:

    InteropLibrary.ProcInf pi = new InteropLibrary.ProcInf() { ProcessId = 1234 };
    if (InteropLibrary.ProcessHelper.GetProcessInfo(pi))
    {
        ...

Вот вроде бы и всё.

Не забудьте: если в вашем проекте есть неуправляемый код, вы привносите в него undefined behaviour и все остальные «прелести» нативного доступа к памяти. Поэтому будьте предельно осторожны с нативными функциями. (Например, вы неправильно подсчитали размер буфера, нативное программирование таких ошибок не прощает.)

READ ALSO
Проблема с INotifyPropertyChanged

Проблема с INotifyPropertyChanged

Есть интерфейс 1:

348
Дублируются данные в шаблонах списка ListView

Дублируются данные в шаблонах списка ListView

Разрабатывается чат вконтакте, который поддерживает медиавложенияБыл написан обращённый список ListView, поддерживающий виртуализацию данных...

318
как передать static файл через koa-router

как передать static файл через koa-router

Мне нужно, чтобы переходя на любой роут моего приложения koa всегда передавал файл indexhtml, т

327
draggable jquery etc

draggable jquery etc

имеется ту ду лист, создается заметка, которая в формате li#draggable > p добавляется в ul в колонку PENDINGхочу реализовать drag&drop, чтобы заметки из колонки...

278