有没有办法让P/Invoke(DllImport)签名引用的特定DLL依赖于CPU架构?
我正在开发一个应用程序,它从第三方供应商的本机dll加载大量方法签名,在这种情况下是用户空间接口DLL到一块硬件.该供应商现在已开始提供DLL的x86和x64版本,我认为我的应用程序将受益于作为64位进程运行.除了这个DLL,一切都是.NET代码,所以构建为"任何CPU"都可以.
本机DLL中的所有方法签名在64位上都相同,但DLL的名称不同(Foo.dll与Foo_x64.dll).有没有办法通过P/Invoke签名或app.config条目我可以让它根据正在运行的CPU架构选择加载哪个DLL?
如果不是不同的DLL名称,它在不同的文件夹中是相同的名称,它是否打开任何其他选项?
注意:因为此用户空间DLL的版本必须与安装的硬件内核驱动程序匹配,所以DLL不与我们的应用程序捆绑在一起,而是依靠供应商安装程序将其放在%的目录中路径%.
有谁知道围绕Windows API功能的.NET托管包装器在.NET框架本身不可用?
窗口创建和显示样式,常见UI控件操作,键盘/鼠标输入,文件和磁盘信息,内存映射文件等区域
我一直是访客http://www.pinvoke.net/的常客,并发现它是一个很好的资源.但是,必须直接使用DllImport函数,然后每次定位所需的结构和枚举都很慢并且容易出错.
(我确实意识到在可能的情况下以100%托管代码执行操作几乎总是更好的方法,但是有很多东西,特别是在Windows窗体中,您只能使用托管代码来执行此操作.)
目前专注于Windows XP,但未来可能会转向Windows 7.
我想从用户那里获得网络登录凭据.
我正在使用带有C#的.NET 3.5.到目前为止我使用了这个CredUIPromptForCredentials电话(关于如何使用它的一个非常有用的链接可以在这里找到)
我的问题是CredUIPromptForCredentialsAPI调用显示旧的Windows 2000/XP凭据对话框而不是新的Vista/7.
我在msdn上读到我应该使用CredUIPromptForWindowsCredentials函数.
有人可以发布一个如何在C#中使用它的例子吗?我还需要能够获得输入的凭据.
我正在接受带有char**(即指向字符串的指针)的代码:
int DoSomething(Whatever* handle, char** error);
Run Code Online (Sandbox Code Playgroud)
基本上,它需要处理其状态,如果出现问题,它会返回错误代码和可选的错误消息(内存分配在外部并通过第二个函数释放.这部分我已经发现:)).
但是,我不确定如何处理C#.我目前有什么:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static unsafe extern int DoSomething(IntPtr handle, byte** error);
public static unsafe int DoSomething(IntPtr handle, out string error) {
byte* buff;
int ret = DoSomething(handle, &buff);
if(buff != 0) {
// ???
} else {
error = "";
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我已经戳了戳,但我无法弄清楚如何把它变成一个byte[]适合喂食的UTF8Encoding.UTF8.GetString()
我是在正确的轨道上吗?
编辑:为了更明确,库函数分配内存,必须通过调用另一个库函数释放.如果一个解决方案没有给我一个指针,我可以释放,解决方案是不可接受的.
额外问题:如上所述,此库使用UTF-8作为其字符串.我是否需要在P/Invokes中做任何特殊操作,或者仅string用于正常const char*参数?
我假设我需要使用pinvoke但我不确定需要哪些函数调用.
详细方案.遗留应用程序将运行.我将为该应用程序提供Handle.我需要:a)将该应用程序带到顶部(在所有其他窗口之前).b)使其成为活动窗口.
需要哪些Windows函数调用?
如何将数据(文本)从托管程序集流式传输到本机库并将数据(文本)流式传输回托管程序集?
具体来说,我想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.
简而言之的问题是:如何释放从本机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) 我开发了一个函数,它返回给定窗口句柄的窗口图标.看起来像这样.
private static BitmapSource GetWindowIcon(IntPtr windowHandle)
{
var hIcon = default(IntPtr);
hIcon = SendMessage(windowHandle, WM_GETICON, ICON_BIG, IntPtr.Zero);
if (hIcon == IntPtr.Zero)
hIcon = GetClassLongPtr(windowHandle, GCL_HICON);
if (hIcon == IntPtr.Zero)
{
hIcon = LoadIcon(IntPtr.Zero, (IntPtr)0x7F00/*IDI_APPLICATION*/);
}
if (hIcon != IntPtr.Zero)
{
return Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
} else {
throw new InvalidOperationException("Could not load window icon.");
}
}
Run Code Online (Sandbox Code Playgroud)
我结合使用此功能GetForegroundWindow来获取活动窗口的图标.
但是,它似乎为通用应用程序产生了相同的暗淡图标.
是否有可能以某种方式从正在运行的通用应用程序中获取平铺图像或图标?
我认为委托实例可以与函数实例互换.
请使用以下代码:
delegate int AddDelegate(int a, int b);
AddDelegate DelegateInstance;
public void DoStuff()
{
//I can call this without a delegate "instance":
MethodThatTakesAdd(Add);
//I can also call it WITH a delegate "instance"
DelegateInstance = Add;
MethodThatTakesAdd(DelegateInstance);
}
public int Add(int a, int b)
{
return a + b;
}
public void MethodThatTakesAdd(AddDelegate addFunction)
{
Console.WriteLine(addFunction(1, 2).ToString());
}
Run Code Online (Sandbox Code Playgroud)
两种方式称它为APPEAR是等价的,如果你只使用C#,你将永远不会看到差异(至少我还没有达到这一点).但是,我最近是一个回调到这个托管代码的非托管代码,它们的处理方式不同.例如,在一个场景中,如果我直接将函数用作回调(即使我的对象实例被保留),我也会得到错误"对垃圾收集的委托进行了回调".使用"委托实例"可以解决问题.
那里有人知道有什么区别吗?