示例C API签名:
void Func(unsigned char* bytes);
在C中,当我想将指针传递给数组时,我可以这样做:
unsigned char* bytes = new unsigned char[1000];
Func(bytes); // call
Run Code Online (Sandbox Code Playgroud)
如何将上述API转换为P/Invoke,以便我可以将指针传递给C#字节数组?
首先,我在http://swigartconsulting.blogs.com/tech_blender/2005/08/how_to_move_the.html找到了此代码:
public class Win32
{
[DllImport("User32.Dll")]
public static extern long SetCursorPos(int x, int y);
[DllImport("User32.Dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref POINT point);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
}
Run Code Online (Sandbox Code Playgroud)
将以下代码粘贴到按钮的click eventhandler中:
Win32.POINT p = new Win32.POINT();
p.x = button1.Left + (button1.Width / 2);
p.y = button1.Top + (button1.Height / 2);
Win32.ClientToScreen(this.Handle, ref p);
Win32.SetCursorPos(p.x, p.y);
Run Code Online (Sandbox Code Playgroud)
这会将鼠标指针移动到按钮的中心.
这段代码效果很好,但我似乎无法弄清楚如何扩展它.假设我有一个Internet浏览器(嵌入在windows窗体中)打开一个网页(一些我手头不知道的随机页面),里面有一个下拉列表框.我已修改上面的代码,将光标移动到下拉列表框(使用下面显示的鼠标单击方法将列表向下拖放),并在列表中上下移动,突出显示每个项目作为鼠标指针过去,但对于我的生活,我无法弄清楚如何实际让鼠标点击当前选定的项目来保持选择.我正在这样做的方式现在下拉列表框只是关闭,选择不会改变.我正在使用以下代码进行鼠标单击(这会使列表下拉):
private static void MouseClick(int x, int y, IntPtr handle) //handle for the browser …Run Code Online (Sandbox Code Playgroud) 在这个问题中,我搜索了一个解锁文件的简单解决方案.感谢所有的评论和回答,我找到了PInvoking的简单解决方案DeleteFile.
它工作,但因为我从来没有通过PInvoke(Win32)使用文件操作,我不知道是否有一些陷阱或是否有另一种方法来调用DeleteFile删除文件的备用流.
我还不知道的是,如果我必须在try/catch中包装调用,或者仅仅查看布尔结果就足够了.在我的测试中,没有提出异常,但我不知道在现实世界中会发生什么.
public class FileUnblocker {
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteFile(string name );
public bool Unblock(string fileName) {
return DeleteFile(fileName+ ":Zone.Identifier");
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码看起来可靠吗?
更新
我发布了一个不完整的方法(unblock方法没有将"Zone.Identifier"文字连接到文件名).我现在纠正了这个,抱歉.
给定DLL中的以下C函数:
char * GetDir(char* path );
Run Code Online (Sandbox Code Playgroud)
你将如何P/Invoke这个函数到C#并正确编组char*..NET似乎知道如何做LPCTSTR,但是当我无法找出任何不会导致NotSupportedException在调用此函数时触发的编组时.
我是一位经验丰富的.Net程序员,但在我的生活中还没有编译过C/C++程序.现在我有这个C-dll,标题和文档(第三方,而不是来自Win API),我需要从中调用十种方法.
我在考虑使用Platform Invoke.我发现这三个工具可以为我创建代码:
可能
Pinvoker似乎与Interop助手和向导有一些不同的方法.Swig我刚刚检查时发现这个问题没有在这里提出.
这些工具的优缺点是什么?
鉴于我对C/C++知之甚少,对我来说生成P/Invoke代码的最佳=最简单,最安全的方法是什么?
我试图从C#调用以下简单的C函数:
SIMPLEDLL_API const char* ReturnString()
{
return "Returning a static string!";
}
Run Code Online (Sandbox Code Playgroud)
使用以下P/Invoke声明(使用或不使用return属性,它没有区别):
[DllImport("SimpleDll")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string ReturnString();
Run Code Online (Sandbox Code Playgroud)
如果DLL是Debug构建但在Release构建(AccessViolationException)中崩溃,则它可以工作.
我正在调用十几个其他简单的函数,这是唯一失败的函数(这里是其他函数:)
[DllImport("SimpleDll")] public static extern int NextInt();
[DllImport("SimpleDll")] public static extern void SetNextInt(int x);
[DllImport("SimpleDll")] public static extern int AddInts(int a, int b);
[DllImport("SimpleDll")] public static extern int AddFourInts(int a, int b, int c, int d);
[DllImport("SimpleDll")] public static extern double AddDoubles(double x, double y);
[DllImport("SimpleDll")] public static extern IntPtr AddDoublesIndirect(ref double x, ref double y);
[DllImport("SimpleDll")] [return: …Run Code Online (Sandbox Code Playgroud) 我尝试从我的C#-application中调用来自外部DLL的普通C函数.此功能定义为
void set_param(const char *data)
Run Code Online (Sandbox Code Playgroud)
现在我使用这个函数有一些问题:
如何在C#代码中指定此"const"?public static extern void set_param(sbyte *data)似乎错过了"const"部分.
调用此函数时,如何移交普通的8位C字符串?调用set_param("127.0.0.1")导致错误消息"无法从'string'转换为'sbyte '"*.
有没有办法从ac头自动创建.net的p/invoke包装?
当然我可以手工创建它们,但维护它们会很痛苦,而且我可能在某个地方犯了一个错误,导致很难调试崩溃.
我尝试过SWIG,但它创建了完整的类,其中简单的结构就足够了.SWIG的另一个问题是它需要c侧的额外互操作代码.
我更喜欢输出也适用于单声道,但这不是必需的.
我可以使用的另一件事是一个解析c头的程序,并以一个漂亮的中间格式(如xml)创建一个输出,我可以自己创建C#包装器.
编辑:
PInvoke Interop助手是我需要的.
但它有一些小问题:
*它将"unsigned char*"转换为我更喜欢IntPtr的字符串
*它假设size_t = int = long = 32bit.这对我来说是正确的,但在每个平台上可能都不是这样.
有没有一个干净的方法来解决这个问题?否则我会在转换之前在c代码上使用一些查找和替换.
我开发了一个GUI测试框架,可以按计划对我们公司网站进行集成测试.当某些内容失败时,它会截取桌面的屏幕截图等.这在专用Windows Server 2008上的登录用户上无人值守.
问题是在我已断开远程桌面会话的桌面上截取屏幕截图.我得到以下异常:
System.ComponentModel.Win32Exception (0x80004005): The handle is invalid
at System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX, Int32 destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
at System.Drawing.Graphics.CopyFromScreen(Point upperLeftSource, Point upperLeftDestination, Size blockRegionSize)
at IntegrationTester.TestCaseRunner.TakeScreenshot(String name) in C:\VS2010\IntegrationTester\IntegrationTester\Config\TestCaseRunner.cs:line 144
at IntegrationTester.TestCaseRunner.StartTest() in C:\VS2010\IntegrationTester\IntegrationTester\Config\TestCaseRunner.cs:line 96
Run Code Online (Sandbox Code Playgroud)
该TakeScreenshot()方法是这样的:
public static void TakeScreenshot(string name)
{
var bounds = Screen.GetBounds(Point.Empty);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
bitmap.Save("someFileName", ImageFormat.Jpeg);
}
}
Run Code Online (Sandbox Code Playgroud)
我确保屏幕保护程序设置为"无",没有超时.我还实现了一段代码,它可以执行一些pinvokes来发送鼠标移动,希望它能生成桌面图形处理..但是没有. …
使用[In,Out]和将参数从C#传递给C++时只使用ref有什么区别吗?
我发现了几个不同的SO帖子,以及来自MSDN的一些东西也接近我的问题,但并没有完全回答它.我的猜测是我可以安全地使用ref,就像我使用[In,Out]一样,并且marshaller将不会采取任何不同的行为.我担心的是它会采取不同的行为,并且C++对我传递的C#结构不满意.我已经在我正在使用的代码库中看到了两件事情......
以下是我发现并一直在阅读的帖子:
P/Invoke [In,Out]属性是否可选用于编组数组? 让我觉得我应该使用[In,Out].
这三个帖子让我觉得我应该使用[In,Out],但我可以使用ref代替它,它将具有相同的机器代码.这让我觉得我错了 - 所以问这里.