为了学习在C#中使用PInvoke,我有点不确定如何使用涉及简单值类型的指针处理各种情况.
我从非托管DLL导入以下两个函数:
public int USB4_Initialize(short* device);
public int USB4_GetCount(short device, short encoder, unsigned long* value);
Run Code Online (Sandbox Code Playgroud)
第一个函数使用指针作为输入,第二个函数使用指针作为输出.它们在C++中的用法相当简单:
// Pointer as an input
short device = 0; // Always using device 0.
USB4_Initialize(&device);
// Pointer as an output
unsigned long count;
USB4_GetCount(0,0,&count); // count is output
Run Code Online (Sandbox Code Playgroud)
我在C#中的第一次尝试导致以下P/Invokes:
[DllImport("USB4.dll")]
public static extern int USB4_Initialize(IntPtr deviceCount); //short*
[DllImport("USB4.dll")]
public static extern int USB4_GetCount(short deviceNumber, short encoder, IntPtr value); //ulong*
Run Code Online (Sandbox Code Playgroud)
如何在C#中使用这些函数的方式与上面的C++代码相同?有没有更好的方法来声明这些类型,也许使用MarshalAs?
我有一个非托管的 DLL,它正在将日志消息写入标准输出。我正在使用来自 WPF 应用程序的 P 调用调用此 DLL,我需要获取标准输出流日志。我试过 Console.SetOut,但这似乎只能捕获使用 Console.Write 等编写的信息。
谁有想法?我在其他地方发现了类似的问题,但他们没有答案。
我想知道什么是最顶级声明的引用,为什么我们仍然需要使用DllImport?我在说C#.
假设我有一个结构:
typedef struct {
float x;
float y;
float z;
int ID;
} Vertex;
Run Code Online (Sandbox Code Playgroud)
和一个C++函数:
float first(Vertex* ptr, int length){ //really silly function, just an example
Vertex u,v;
u.x = ptr[0].x; //...and so on, copy x,y,z,ID
v.x = ptr[1].x;
return (u.x * v.x + u.y * v.y + u.z * v.z);
}
Vertex* another(float a, int desired_size){
Vertex v = (Vertex*)malloc(desired_size*sizeof(Vertex));
v[0].x = a;
v[1].x = -a; //..and so on.. make some Vertices.
return v;
}
Run Code Online (Sandbox Code Playgroud)
首先 - 我的IDE.我正在使用Visual Studio …
我正在进行P/Invoke,我使用以下方法
[DllImport("Authz.dll", SetLastError = true)]
public static extern BOOL AuthzFreeContext(
IntPtr phAuthzResourceManager);
Run Code Online (Sandbox Code Playgroud)
即使它工作,如何保证Authz.dll始终加载到我的代码中.假设我dll是一些XXX.dll如何在使用之前检查是否加载了dll,这样我就不会找到找不到方法的方法.
我写了一个C++ DLL,现在我需要从托管应用程序调用本机函数.
导出的本机函数如下所示:
extern "C" __declspec(dllexport)
bool NativeMethod(char *param1, char *param2, char *result);
Run Code Online (Sandbox Code Playgroud)
所以,从C#我将调用该函数传递2个输入参数,1个输出参数,显然我将读取返回bool值.
我试图以多种方式包装所有这些,但总是我得到一个PInvokeStackImbalance例外.我知道调用本机函数的唯一方法是通过应用CallingConvention = CallingConvention.Cdecl).NET函数声明.但是通过这种方式,我无法读取输出参数(它总是空字符串),并且返回值始终为true.
在文档中它说:
KEYEVENTF_EXTENDEDKEY(0x0001):如果指定,则扫描代码前面有一个值为0xE0(224)的前缀字节.
有人可以解释这意味着什么吗?
这有什么区别:
keybd_event(RIGHT, 0, 0, 0);
keybd_event(RIGHT, 0, 2, 0);
Run Code Online (Sandbox Code Playgroud)
还有这个:
keybd_event(RIGHT, 0, 1 | 0, 0);
keybd_event(RIGHT, 0, 1 | 2, 0);
Run Code Online (Sandbox Code Playgroud)
因为当我执行这段代码时,我看不出有什么区别?
另外,什么是"字节bScan"?在描述中它是:密钥的硬件扫描代码.那意味着什么?
我正在使用P/Invoke从C#调用用Delphi XE2编写的DLL函数.当从单个线程顺序进行调用时,它似乎正在工作.但是,当多个线程调用该函数时,C#主机应用程序System.AccessViolationException似乎随机抛出.
为什么下面的代码会触发访问冲突,我该如何解决?
用于重现问题的最小Delphi库代码:
library pinvokeproblem;
{$R *.res}
uses Windows, SysUtils;
procedure Test(const testByte: byte); stdcall;
begin
OutputDebugString(PWideChar(IntToStr(testByte)));
end;
exports Test;
end.
Run Code Online (Sandbox Code Playgroud)
用于重现问题的最小C#主机应用程序代码:
[DllImport(
"pinvokeproblem.dll",
CallingConvention = CallingConvention.StdCall,
EntryPoint = "Test")]
private static extern void Test(byte testByte);
public static void Main(string[] args)
{
for (int i = 1; i <= 1000; i++) // more iterations = better chance to fail
{
int threadCount = 10;
Parallel.For(1, threadCount, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, test =>
{
byte …Run Code Online (Sandbox Code Playgroud) 脚本
这应该是一项简单的任务,但由于某种原因,我无法按预期进行.我必须struct在反向P/Invoke调用(非托管调用托管代码)期间编组基本C++ .
只有bool在struct中使用时才出现这个问题,所以我只是将C++方面修改为:
struct Foo {
bool b;
};
Run Code Online (Sandbox Code Playgroud)
由于.NET默认情况下将布尔值编组为4字节字段,因此我将本机布尔值显式编组为1字节长度字段:
public struct Foo {
[MarshalAs(UnmanagedType.I1)] public bool b;
}
Run Code Online (Sandbox Code Playgroud)
当我使用以下签名和正文调用导出的托管静态方法时:
public static void Bar(Foo foo) {
Console.WriteLine("{0}", foo.b);
}
Run Code Online (Sandbox Code Playgroud)
我打印出正确的布尔alpha表示.如果我使用更多字段扩展结构,则对齐是正确的,并且在编组后数据不会损坏.
问题
出于某种原因,如果我不将此编组struct作为参数传递,而是通过值传递返回类型:
public static Foo Bar() {
var foo = new Foo { b = true };
return foo;
}
Run Code Online (Sandbox Code Playgroud)
应用程序崩溃时出现以下错误消息:
如果我更改托管结构以保持byte而不是abool
public struct Foo {
[MarshalAs(UnmanagedType.I1)] public byte b;
}
public static Foo Bar() {
var foo = new …Run Code Online (Sandbox Code Playgroud) 尝试查找仍处于待处理状态的任何当前活动计时器,这可能会导致计算机唤醒.创建计时器时,会指定名称.所有指定计时器的列表都是理想的,而不仅仅是指定的名称.
以下是创建命名计时器的代码:
[DllImport("kernel32.dll")]
private static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, String lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
private static int SetWaitForWakeUpTime(DateTime wakeTime) {
long waketime = wakeTime.ToFileTime();
String timerName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name.ToString() + "WakeUpTimer";
using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, timerName)) {
if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true)) {
using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset)) {
wh.SafeWaitHandle = …Run Code Online (Sandbox Code Playgroud)