标签: pinvoke

P/Invoke动态DLL搜索路径

我有一个现有的应用程序P/Invokes到一个DLL与应用程序本身驻留在同一目录中.

现在(由于佳能生产了最疯狂的API之一)我需要支持这个API的两个版本,并在运行时确定我应该使用哪个(旧的或新的).由于DLL具有相同的名称(第一个加载具有相同名称的其他DLL,因此只重命名第一个将无法帮助我)我必须将它们保存在不同的目录中.

因此我的问题是:我有什么选择来控制DllImport声明中给出的DLL使用的目录?

我想我可以尝试以下两个想法中的任何一个:

1)在执行第一个P/Invoke之前使用"SetDllDirectory"设置我想要的目录,然后重置它.

2)使用"LoadLibraryEx"手动加载所需的DLL,并希望这样做.

但是,有没有更多的".NET:ish方式"首先尝试?

更新:我意识到我可以在两个单独的.Net程序集中填充对DLL的所有访问权限,然后将它们中的每一个放在一个带有相应API文件的单独目录中.然后我可以动态加载正确的.Net程序集,并自动加载正确的DLL.有什么理由不行吗?

我能想到一个:我将如何调试这些东西?有可能告诉Visual Studio一个程序集(包含在我的解决方案中)应该放在一个子目录中并从那里进行调试吗?

.net c# pinvoke dllimport

13
推荐指数
1
解决办法
5147
查看次数

在.NET 4.0中,P/Invoke环境是否发生了变化?

我已经开始将.NET 2.0 WinForms应用程序升级到.NET 4.0.嗯,好的,升级过程只是切换平台目标,但让它真正起作用.我认为这就是它的全部内容.

但似乎.NET 4.0中关于互操作的东西发生了巨大的变化.使用DllImport(),该应用程序嵌入了几个Delphi dll.当应用程序面向.NET 2.0时,一切正常.但是当我将它改为目标.NET 4.0时,东西开始变得混乱,就像破坏内存的东西一样.

例如,它在奇怪的地方用"0"替换单个数字.在IStream中传递的数据用(Hex)00 00 00 00 00 00 00 80替换8个字符,但只有大约70%的时间.两次连续调用以检索相同的值会返回不同的结果(从内存中的缓存中检索值,第一次成功,第二次失败).发送到日志的字符串显示为截断.

我尝试过很多尝试使调用约定更加明确的东西,没有任何效果.所有字符串在.NET端处理为[MarshalAs(UnmanagedType.LPWStr)],在Delphi端处理为PWChar.

在.NET 4.0中改变了什么会破坏P/Invoke?

- - - - - - - - - - - - - - 编辑 - - - - - - - - - - - ----------------

这是最简单的例子.它生成一个PDF,有时可以正常工作,但更频繁地最终损坏(并在.NET 2.0中正常工作):

[DllImport(DLLName)]
public static extern void SetDBParameters(
    [MarshalAs(UnmanagedType.LPWStr)] string Server,
    [MarshalAs(UnmanagedType.LPWStr)] string Database,
    [MarshalAs(UnmanagedType.LPWStr)] string User,
    [MarshalAs(UnmanagedType.LPWStr)] string Password,
    short IntegratedSecurity);

procedure SetDBParameters(Server, Database, User, Password: PWChar;
    IntegratedSecurity: WordBool); stdcall;


[DllImport(DLLName)]
public …
Run Code Online (Sandbox Code Playgroud)

delphi pinvoke .net-4.0

13
推荐指数
1
解决办法
1643
查看次数

在C#中命名Windows API常量

C#中常量命名约定是Pascal大小写:

private const int TheAnswer = 42;
Run Code Online (Sandbox Code Playgroud)

但有时我们需要从Windows API中表示已存在的常量.

例如,我不知道如何命名:

/// <summary>
/// With this style turned on for your form, 
/// Windows double-buffers the form and all its child controls.
/// </summary>
public const int WS_EX_COMPOSITED = 0x02000000;
Run Code Online (Sandbox Code Playgroud)

我该怎么命名呢?

保持它WS_EX_COMPOSITED可以让我快速将它与WinAPI相关联,但这是错误的.

一些选择:

  • WsExComposited - 太匈牙利人了
  • Composited - 太短
  • WsExenum with Compositedin it - 仍然是匈牙利人
  • ExtendedWindowsStyles.Composited - 班级常数?枚举?

应该指出的是,良好命名的目标是:

  • 它必须是可读的.
  • 它不能触发FxCop和StyleCop,即使这意味着将它隐藏起来.

c# pinvoke winapi constants naming-conventions

13
推荐指数
1
解决办法
774
查看次数

如何在C#中处理null或者可选的dll struct参数

如何struct使用pinvoke 处理从C#调用的dll方法中的可选参数?例如,lpSecurityAttributes此处参数应该null在不存在时传递.

正确的传递方式struct似乎正在使用ref,但它不能有可选参数,或者null总的来说.

有什么方法可以达到这个目的?

c# null pinvoke interop optional-parameters

13
推荐指数
1
解决办法
1172
查看次数

获取活动窗口文本(并向其发送更多文本)

我在C#中创建一个小实用程序,当按下全局热键时,它会向活动文本框添加一些文本,这是一种自动完成功能.我有我的全局热键工作,但现在我不知道如何在活动文本框中获取当前文本(如果活动窗口是一个文本框).到目前为止我尝试过的是使用

一个.GetForegroundWindow然后使用该句柄调用GetWindowText.这给了我活动窗口的窗口标题,而不是文本框内容.

湾 GetActiveWindow并使用该句柄调用GetWindowText.这根本不给我任何文字.

这是我所做的一个例子

[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);   
[DllImport("user32.dll")]
static extern int GetActiveWindow();

public static void TestA() {
    int h = GetForegroundWindow();
    StringBuilder b = new StringBuilder();
    GetWindowText(h, b, 256);
    MessageBox.Show(b.ToString());
}

public static void TestB() {
    int h = GetActiveWindow();
    StringBuilder b = new StringBuilder();
    GetWindowText(h, b, 256);
    MessageBox.Show(b.ToString());
}
Run Code Online (Sandbox Code Playgroud)

那么,关于如何实现这一点的任何想法?

编辑28.01.2009: 所以,我发现了如何做到这一点.这是我用过的:

using …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke winapi

12
推荐指数
1
解决办法
2万
查看次数

P/Invoke和C++ Wrappers之间的性能差异

在学习P/Invoke的过程中,我问过上一个问题:

如何在涉及指针时进行P/Invoke

但是,我不太明白在C#中使用P/Invoke而不是在托管C++中创建包装器的含义.在C#中使用P/Invoke创建相同的DLL肯定会导致更清晰的接口,因为我可以在嵌入式资源上使用DLLImport,但是我自己编组的本机DLL的托管C++包装器会有更好的性能吗?

c# performance pinvoke managed-c++

12
推荐指数
2
解决办法
8427
查看次数

将.NET P/Invoke代码组织到Win32 API的最佳实践

我在.NET中重构一个庞大而复杂的代码库,大量使用P/Invoke到Win32 API.项目的结构并不是最好的,我发现DllImport语句遍布整个地方,经常复制到同一个函数,并且还以各种方式声明:

import指令和方法有时被声明为public,有时是private,有时是静态的,有时也是实例方法.我担心重构可能会产生意想不到的后果,但这可能是不可避免的.

是否有可以帮助我的最佳实践记录?

我的instict是组织一个静态/共享Win32 P/Invoke API类,它在一个文件中列出所有这些方法和相关常量... 编辑有超过70个user32 DLL导入.

(代码库由20多个项目组成,包含大量的窗口消息传递和跨线程调用.如果有所不同,它也是从VB6升级的VB.NET项目.)

.net c# vb.net pinvoke

12
推荐指数
1
解决办法
2354
查看次数

C++和C#互操作性:P/Invoke与C++/CLI

在找到C#和C++之间的互操作方法的过程中,我发现这篇文章解释了P/Invoke.

我读了很多文章声称C++/CLI不是精确的C++,需要一些努力来修改原始的C++代码.

我想问一下,当我想要从C#对象中使用一些C++对象(代码/数据)时,最佳方法是什么.

  • 看起来为了使用P/Invoke,我应该提供C风格的API.这是真的吗?我的意思是,有没有办法将C++对象导出到C#,如带有P/Invoke的SWIG?或者,我是否必须为此目的使用SWIG?
  • 将C++更改为C++/CLI有多难?与将C++重写为C#相比,是否值得尝试?C++设计得很好,所以将它实现到C#并不是很重要.
  • (关于主题问题)是否有相反的方式?我的意思是,如果我想使用C++中的C#代码,有没有办法这样做?

c# c++ pinvoke interop c++-cli

12
推荐指数
2
解决办法
5515
查看次数

Pinvoke DeviceIoControl参数

我正在使用C#项目DeviceIoControl.我已经为我的签名咨询了相关的Pinvoke.net页面:

[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
    SafeFileHandle hDevice,
    EIOControlCode IoControlCode,

    [MarshalAs(UnmanagedType.AsAny)]
    [In] object InBuffer,
    uint nInBufferSize,

    [MarshalAs(UnmanagedType.AsAny)]
    [Out] object OutBuffer,
    uint nOutBufferSize,

    out uint pBytesReturned,
    [In] IntPtr Overlapped
    );
Run Code Online (Sandbox Code Playgroud)

我从来没有见过object和前,但MSDN文档听起来前途:[MarshalAs(UnmanagedType.AsAny)]

一种动态类型,它在运行时确定对象的类型,并将对象编组为该类型.该成员仅对平台调用方法有效.

我的问题是:使用此签名的"最佳"和/或"正确"方式是什么?

例如,IOCTL_STORAGE_QUERY_PROPERTY期望InBuffer是一个STORAGE_PROPERTY_QUERY结构.看起来我应该能够定义该结构,创建一个new实例,并将其传递给我的Pinvoke签名:

var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0, QueryType = 0 };
DeviceIoControl(..., query, Marshal.SizeOf(query), ...);
Run Code Online (Sandbox Code Playgroud)

但是,我刚刚System.ExecutionEngineException做了这个,所以我改为:

int …
Run Code Online (Sandbox Code Playgroud)

c# pinvoke deviceiocontrol

12
推荐指数
1
解决办法
7533
查看次数

在没有Windows阴影的情况下检索窗口大小

我正在尝试基于Window句柄捕获C#中的桌面窗口.我正在使用.NET并使用PInvoke来GetWindowRect()来捕获窗口矩形.我有窗口选择和矩形捕获工作正常.

但是,捕获的窗口矩形不仅包括实际窗口大小,还包括Window的装饰,如周围的阴影.当我尝试将窗口剪辑为位图时,位图包含区域和阴影.在Windows 10上,我得到透明阴影区域,包括活动窗口下方可能显示的任何内容:

在此输入图像描述

我使用的代码很简单,通过PInvoke调用使用Win32 GetWindowRect()捕获Window:

var rect = new Rect();
GetWindowRect(handle, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);

using (var graphics = Graphics.FromImage(result))
{
    graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}

return result;
Run Code Online (Sandbox Code Playgroud)

然后我捕获图像并将其分配到图片框中.

此外,它看起来像窗户之间有一些变化 - 有些窗户有阴影,有些窗户没有.大多数人都这样做,但是像Visual Studio和Chrome这样的人没有,所以它甚至不是一个简单的问题,即剥离无关的像素.

我已经尝试过使用GetClientRect(),但这只是客户区,这不是我所追求的.我想得到的是带有边框但没有阴影的实际窗口矩形.

反正有没有这样做?

c# windows pinvoke winapi

12
推荐指数
2
解决办法
1503
查看次数