Pinvoke 和本机调用的 Hello World
Hello World for Pinvoke and Native Calls
我正在尝试为 Pinvoke 和本机调用做一个非常基本的 hello world。
我创建了一个包含 2 个项目的解决方案(一个用于 dll,一个用于通用 windows 应用程序)
所以我最终得到了这样一个项目继承权
我的 dll(文件 NativeCalls.cpp)中有一种方法:
#include "pch.h"
#include "NativeCalls.h"
#include <stdio.h>
MYAPI void print_line(const char* str) {
printf("%s\n", str);
}
在 C# 方面,我有我的 NativeCalls.cs 文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MSSurfaceHubMonitoring
{
public static class NativeCalls
{
[DllImport("NativeCalls.dll")]
private static extern void print_line(string str);
public static void sayHelo()
{
print_line("Hello, PInvoke!");
}
}
}
此时我将构建并 运行 它但出现找不到 dll 的错误
但是我认为它是依赖项而不是它自己的 dll。我已将 dll 的输出目录更改为 UW 应用程序 运行s 来自 (\bin\x86) 的根目录,因此它确实应该找到它。所以就像我说的那样,我认为它是依赖项而不是实际的 dll。
这是我在 Dependency Walker 中看到的内容
但是我已经安装了所有我能拿到的 c++ 包,所以我不明白如何获得缺少的依赖项。再加上这只是一个 hello world,为什么我需要所有这些库。
仅供参考
UW 应用程序未引用我的 dll 项目。我不确定是否需要?我不这么认为,因为这是 运行 时间的事情,所以只要 dll 在那里,它就应该找到它并读取它。但无论我是否尝试将项目添加为参考,我都会收到此错误:
对我最大的帮助是找到这些方法声明(甚至不在 class 中)
extern "C" {
__declspec(dllexport) int getPageSize()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
return siSysInfo.dwPageSize;
}
}
extern "C" {
__declspec(dllexport) Windows::Foundation::Collections::IMap<Platform::String^, int> ^getSystemInfo()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
IMap<String^, int> ^ret =
ref new Platform::Collections::Map<String^, int>;
ret->Insert("oemId", siSysInfo.dwOemId);
ret->Insert("cpuCount", siSysInfo.dwNumberOfProcessors);
ret->Insert("pageSize", siSysInfo.dwPageSize);
ret->Insert("processorType", siSysInfo.dwProcessorType);
ret->Insert("maxApplicationAddress", siSysInfo.lpMinimumApplicationAddress);
ret->Insert("minApplicationAddress", siSysInfo.lpMaximumApplicationAddress);
ret->Insert("activeProcessorMask", siSysInfo.dwActiveProcessorMask);
return ret;
}
但最后我为我不需要的东西创建了包装器。在 c# 中,您可以直接调用本机方法,而无需单独的 dll 或组件项目。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Monitoring
{
public static class NativeCallsWrapper
{
private static SYSTEM_INFO sysInfo = new SYSTEM_INFO();
private static MEMORYSTATUSEX mem = new MEMORYSTATUSEX();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern void GetSystemInfo([In, Out] SYSTEM_INFO Info);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
static NativeCallsWrapper()
{
GetSystemInfo(sysInfo);
GlobalMemoryStatusEx(mem);
}
[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_INFO_UNION
{
[FieldOffset(0)]
public UInt32 OemId;
[FieldOffset(0)]
public UInt16 ProcessorArchitecture;
[FieldOffset(2)]
public UInt16 Reserved;
}
public struct SYSTEM_INFO
{
public SYSTEM_INFO_UNION CpuInfo;
public UInt32 PageSize;
public UInt32 MinimumApplicationAddress;
public UInt32 MaximumApplicationAddress;
public UInt32 ActiveProcessorMask;
public UInt32 NumberOfProcessors;
public UInt32 ProcessorType;
public UInt32 AllocationGranularity;
public UInt16 ProcessorLevel;
public UInt16 ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
public static GeneralStatistics getGeneralStatistics()
{
GeneralStatistics generalStatistics = new GeneralStatistics();
generalStatistics.numberOfProcesses = (int)sysInfo.NumberOfProcessors;
generalStatistics.memoryTotal = mem.ullTotalPhys / 1048;
generalStatistics.memoryInUse = (mem.ullTotalPhys - mem.ullAvailPhys) / 1048;
return generalStatistics;
}
}
}
我正在尝试为 Pinvoke 和本机调用做一个非常基本的 hello world。
我创建了一个包含 2 个项目的解决方案(一个用于 dll,一个用于通用 windows 应用程序)
所以我最终得到了这样一个项目继承权
我的 dll(文件 NativeCalls.cpp)中有一种方法:
#include "pch.h"
#include "NativeCalls.h"
#include <stdio.h>
MYAPI void print_line(const char* str) {
printf("%s\n", str);
}
在 C# 方面,我有我的 NativeCalls.cs 文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MSSurfaceHubMonitoring
{
public static class NativeCalls
{
[DllImport("NativeCalls.dll")]
private static extern void print_line(string str);
public static void sayHelo()
{
print_line("Hello, PInvoke!");
}
}
}
此时我将构建并 运行 它但出现找不到 dll 的错误
但是我认为它是依赖项而不是它自己的 dll。我已将 dll 的输出目录更改为 UW 应用程序 运行s 来自 (\bin\x86) 的根目录,因此它确实应该找到它。所以就像我说的那样,我认为它是依赖项而不是实际的 dll。
这是我在 Dependency Walker 中看到的内容
仅供参考
UW 应用程序未引用我的 dll 项目。我不确定是否需要?我不这么认为,因为这是 运行 时间的事情,所以只要 dll 在那里,它就应该找到它并读取它。但无论我是否尝试将项目添加为参考,我都会收到此错误:
对我最大的帮助是找到这些方法声明(甚至不在 class 中)
extern "C" {
__declspec(dllexport) int getPageSize()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
return siSysInfo.dwPageSize;
}
}
extern "C" {
__declspec(dllexport) Windows::Foundation::Collections::IMap<Platform::String^, int> ^getSystemInfo()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
IMap<String^, int> ^ret =
ref new Platform::Collections::Map<String^, int>;
ret->Insert("oemId", siSysInfo.dwOemId);
ret->Insert("cpuCount", siSysInfo.dwNumberOfProcessors);
ret->Insert("pageSize", siSysInfo.dwPageSize);
ret->Insert("processorType", siSysInfo.dwProcessorType);
ret->Insert("maxApplicationAddress", siSysInfo.lpMinimumApplicationAddress);
ret->Insert("minApplicationAddress", siSysInfo.lpMaximumApplicationAddress);
ret->Insert("activeProcessorMask", siSysInfo.dwActiveProcessorMask);
return ret;
}
但最后我为我不需要的东西创建了包装器。在 c# 中,您可以直接调用本机方法,而无需单独的 dll 或组件项目。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Monitoring
{
public static class NativeCallsWrapper
{
private static SYSTEM_INFO sysInfo = new SYSTEM_INFO();
private static MEMORYSTATUSEX mem = new MEMORYSTATUSEX();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern void GetSystemInfo([In, Out] SYSTEM_INFO Info);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
static NativeCallsWrapper()
{
GetSystemInfo(sysInfo);
GlobalMemoryStatusEx(mem);
}
[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_INFO_UNION
{
[FieldOffset(0)]
public UInt32 OemId;
[FieldOffset(0)]
public UInt16 ProcessorArchitecture;
[FieldOffset(2)]
public UInt16 Reserved;
}
public struct SYSTEM_INFO
{
public SYSTEM_INFO_UNION CpuInfo;
public UInt32 PageSize;
public UInt32 MinimumApplicationAddress;
public UInt32 MaximumApplicationAddress;
public UInt32 ActiveProcessorMask;
public UInt32 NumberOfProcessors;
public UInt32 ProcessorType;
public UInt32 AllocationGranularity;
public UInt16 ProcessorLevel;
public UInt16 ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
public static GeneralStatistics getGeneralStatistics()
{
GeneralStatistics generalStatistics = new GeneralStatistics();
generalStatistics.numberOfProcesses = (int)sysInfo.NumberOfProcessors;
generalStatistics.memoryTotal = mem.ullTotalPhys / 1048;
generalStatistics.memoryInUse = (mem.ullTotalPhys - mem.ullAvailPhys) / 1048;
return generalStatistics;
}
}
}