有谁知道围绕Windows API功能的.NET托管包装器在.NET框架本身不可用?
窗口创建和显示样式,常见UI控件操作,键盘/鼠标输入,文件和磁盘信息,内存映射文件等区域
我一直是访客http://www.pinvoke.net/的常客,并发现它是一个很好的资源.但是,必须直接使用DllImport函数,然后每次定位所需的结构和枚举都很慢并且容易出错.
(我确实意识到在可能的情况下以100%托管代码执行操作几乎总是更好的方法,但是有很多东西,特别是在Windows窗体中,您只能使用托管代码来执行此操作.)
目前专注于Windows XP,但未来可能会转向Windows 7.
如何加速从托管代码调用本机方法?
我正在编写一个程序,它需要能够管理任意大小的对象列表并高速检索它们的信息,并将其提供给脚本.脚本是编译的C#代码的一部分.我正在编写一个从C++(本机)DLL/SO/etc到C#(.Net或Mono)管理层的基本接口层.
现在,我一直在做一些测试,而且我发现平均来说,从托管代码PInvoking本机方法比在托管代码中完成所有这一切慢100倍(所有本机和所有托管都快速相同,供参考).
我使用的语法是:
[DllImport("test.dll")]
extern static public String test_method(String value);
String returnedValue = test_method("hello world");
Run Code Online (Sandbox Code Playgroud)
有没有办法缓存指向函数的指针,快速调用程序的一些代码,这会在加载本机库后提高速度?这样可以很好地解决问题,所以我怀疑它是否存在.:P
编辑:我没有指定,但这需要适用于Windows,Linux(至少是Ubuntu)和Mac OS X,所有这些都适用于x86和x64.否则我会使用C++/CLI接口并完成它,但除非适用于所有3个平台,否则我无法使用它.
我想从用户那里获得网络登录凭据.
我正在使用带有C#的.NET 3.5.到目前为止我使用了这个CredUIPromptForCredentials电话(关于如何使用它的一个非常有用的链接可以在这里找到)
我的问题是CredUIPromptForCredentialsAPI调用显示旧的Windows 2000/XP凭据对话框而不是新的Vista/7.
我在msdn上读到我应该使用CredUIPromptForWindowsCredentials函数.
有人可以发布一个如何在C#中使用它的例子吗?我还需要能够获得输入的凭据.
我假设我需要使用pinvoke但我不确定需要哪些函数调用.
详细方案.遗留应用程序将运行.我将为该应用程序提供Handle.我需要:a)将该应用程序带到顶部(在所有其他窗口之前).b)使其成为活动窗口.
需要哪些Windows函数调用?
在stackoverflow社区的帮助下,我设法调用了本机DLL函数.但是,我无法修改ID或intersects数组的值.无论我在DLL方面用它做什么,旧值仍然存在.它似乎是只读的.
以下是一些代码片段:
C++结构:
typedef struct _Face {
int ID;
int intersects[625];
} Face;
Run Code Online (Sandbox Code Playgroud)
C#映射:
[StructLayout(LayoutKind.Sequential)]
public struct Face {
public int ID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 625)]
public int[] intersects;
}
Run Code Online (Sandbox Code Playgroud)
C++方法(VS2010中的类型设置为DLL):
extern "C" int __declspec(dllexport) __stdcall
solve(Face *faces, int n){
for(int i =0; i<n; i++){
for(int r=0; r<625; r++){
faces[i].intersects[r] = 333;
faces[i].ID = 666;
}
}
Run Code Online (Sandbox Code Playgroud)
C#方法签名:
[DllImport("lib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int solve(Face[] faces, int len); …Run Code Online (Sandbox Code Playgroud) 如何将数据(文本)从托管程序集流式传输到本机库并将数据(文本)流式传输回托管程序集?
具体来说,我想System.IO.Stream在.NET端公开某种类型,并且(最重要的是)FILE *在本机方面.
本机方法的签名应该是:
FILE * foo(FILE * bar);
本机p/invoke调用的包装签名应该是:
CustomStream foo(CustomStream bar);
我不想在本机端使用回调方法(一个用于获取更多数据,一个用于设置更多数据).我想FILE *在本机端使用a - 以及所有相关的方法,例如fprintf.
我不想要任何磁盘I/O. 这需要是内存中的操作.
我完全控制托管程序集和本机库.
该解决方案必须与.NET 2.0一起使用
我愿意创建任何类型的托管或非托管填充层,以实现此目的.
"明显的"解决方案是使用STDIN和STDOUT启动子进程 - 但是我不想要一个单独的进程.此外,我试图重定向STDIN和STDOUT这不是在Windows控制台应用程序本机库的数据流都失败了几分壮观(以及很多头撞).
基于这个问题:
在C#Windows服务上重定向stdout + stderr我试图修改方法(至少)解决问题的一半"响应"流 - 但是没有FileStream(因为我想要更类似的东西MemoryStream).但是,FileStream是唯一一种公开合适的低级流句柄的流类型.
否则,我已经陷入困境,我现在正在考虑我需要深入研究并提出我自己的手动本地< - >托管流实现,但实际上并不知道从哪里开始.
最后!
我在这里发布了一个完整的示例项目:
这适用于.NET 3.5并使用AnonymousPipeServerStream- 但是只需要一点点反射器,就可以很容易地复制AnonymousPipeServerStream.NET 2.0中的内部工作方式.
感谢您的帮助shf301指向我的原生管道API,让我查看Microsoft文档以更好地了解正在发生的事情,并指出我需要使用该_open_osfhandle方法来获取FILE …
我有一些使用单个全局变量的简单C代码.显然这不是线程安全的,所以当我使用P/invoke从C#中的多个线程调用它时,事情搞砸了.
如何为每个线程单独导入此函数,还是使其线程安全?
我尝试声明变量__declspec(thread),但这导致程序崩溃.我也试过制作C++/CLI类,但它不允许成员函数__declspec(naked),我需要(我使用的是内联汇编).我编写多线程C++代码并不是很有经验,所以我可能会遗漏一些东西.
这是一些示例代码:
C#
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SomeFunction(int parameter1, int parameter2);
Run Code Online (Sandbox Code Playgroud)
C++
extern "C"
{
int someGlobalVariable;
int __declspec(naked) _someFunction(int parameter1, int parameter2)
{
__asm
{
//someGlobalVariable read/written here
}
}
int __declspec(dllexport) SomeFunction(int parameter1, int parameter2)
{
return _someFunction(parameter1, parameter2);
}
}
Run Code Online (Sandbox Code Playgroud)
[编辑]:结果SomeFunction()必须以某种规定的顺序为基础someGlobalVariable (例如,考虑一个PRNG,someGlobalVariable作为内部状态).因此,使用互斥锁或其他类型的锁不是一个选项 - 每个线程必须有自己的副本someGlobalVariable.
我一直在研究在C#中运行的原型代码应用程序,并使用旧C++代码中的类和函数(以导入的DLL的形式).代码要求是将类对象传递给非托管C++ DLL(来自C#),并将其存储/修改以供C#应用程序稍后检索.这是我到目前为止的代码......
简单的C++ DLL类:
class CClass : public CObject
{
public:
int intTest1
};
Run Code Online (Sandbox Code Playgroud)
C++ DLL函数:
CClass *Holder = new CClass;
extern "C"
{
// obj always comes in with a 0 value.
__declspec(dllexport) void SetDLLObj(CClass* obj)
{
Holder = obj;
}
// obj should leave with value of Holder (from SetDLLObj).
__declspec(dllexport) void GetDLLObj(__out CClass* &obj)
{
obj = Holder;
}
}
Run Code Online (Sandbox Code Playgroud)
C#类和包装器:
[StructureLayout(LayoutKind.Sequential)]
public class CSObject
{
public int intTest2;
}
class LibWrapper
{
[DLLImport("CPPDLL.dll")]
public static extern …Run Code Online (Sandbox Code Playgroud) 简而言之的问题是:如何释放从本机DLL返回的内存作为托管代码中的ItrPtr?
详细信息:假设我们有简单的函数将两个参数作为OUTPUT,第一个是参考指针到字节数组,第二个是参考Int.该函数将根据某些规则分配字节数,并返回内存指针和字节大小以及返回值(1表示成功,0表示失败).
下面的代码工作正常,我可以正确获取字节数组和字节数和返回值,但是当我尝试使用指针(IntPtr)释放内存时,我得到异常:
Windows已在TestCppDllCall.exe中触发了断点.
这可能是由于堆的损坏,这表明TestCppDllCall.exe或它已加载的任何DLL中的错误.
这也可能是由于用户在TestCppDllCall.exe具有焦点时按下F12.
输出窗口可能包含更多诊断信息.
为了清楚起见:
下一个C#代码与其他DLL函数正常工作具有相同的签名并释放内存工作没有任何问题.
如果您需要更改分配内存方法或添加任何其他代码,则接受(C)代码中的任何修改.
我需要的所有功能是Native DLL函数接受两个参数引用(Byte数组和int,在c#[IntPtr of byte array和int]中)根据一些规则填充一些值并返回函数结果(Success或Fail) .
CppDll.h
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
extern "C" CPPDLL_API int writeToBuffer(unsigned char *&myBuffer, int& mySize);
Run Code Online (Sandbox Code Playgroud)
CppDll.cpp
#include "stdafx.h"
#include "CppDll.h"
extern "C" CPPDLL_API int writeToBuffer(unsigned char*& myBuffer, int& mySize)
{
mySize = 26;
unsigned char* pTemp = new unsigned char[26];
for(int i = 0; i < 26; i++)
{
pTemp[i] = 65 + i;
}
myBuffer = pTemp;
return …Run Code Online (Sandbox Code Playgroud) C DLL中的函数如下所示:
int my_Funct(char* input, char* output);
Run Code Online (Sandbox Code Playgroud)
我必须从C#app调用它.我通过以下方式执行此操作:
...DllImport stuff...
public static extern int my_Funct(string input, string output);
Run Code Online (Sandbox Code Playgroud)
输入字符串完美地传输到DLL(我有可见的证明).函数填写的输出虽然错误.我有六进制数据,如:
3F-D9-00-01
Run Code Online (Sandbox Code Playgroud)
但不幸的是,切断两个零之后的所有内容,只有前两个字节来到我的C#应用程序.它发生了,因为(我猜)它将它视为空字符并将其作为字符串的结尾.
任何想法我怎么能摆脱它?我试图将它指定为IntPtr而不是字符串,但我不知道以后如何处理它.我尝试过后:
byte[] b1 = new byte[2];
Marshal.Copy(output,b1,0,2);
Run Code Online (Sandbox Code Playgroud)
2通常应该是字节数组的长度.但我得到了各种错误:例如"请求的范围超出了数组的末尾".或"试图读取或写入受保护的内存......"
我感谢任何帮助.