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, заменив заполнение значения пустой строкой, всё будет работать хорошо).
Вот решение с библиотекой на C++/CLI.
Положите в этой библиотеке в заголовочном файле следующие определения:
#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, можно посмотреть, например, здесь.
В C#-части выберите таргет с конкретной битностью (x86 или x64). Подключите часть на C++/CLI как project reference.
В C#-коде вызывайте:
InteropLibrary.ProcInf pi = new InteropLibrary.ProcInf() { ProcessId = 1234 };
if (InteropLibrary.ProcessHelper.GetProcessInfo(pi))
{
...
Вот вроде бы и всё.
Не забудьте: если в вашем проекте есть неуправляемый код, вы привносите в него undefined behaviour и все остальные «прелести» нативного доступа к памяти. Поэтому будьте предельно осторожны с нативными функциями. (Например, вы неправильно подсчитали размер буфера, нативное программирование таких ошибок не прощает.)
Продвижение своими сайтами как стратегия роста и независимости