鉴于此C API声明如何将其导入C#?
int _stdcall z4ctyget(CITY_REC *, void *);
Run Code Online (Sandbox Code Playgroud)
我已经能够做到这一点:
[DllImport(@"zip4_w32.dll",
CallingConvention = CallingConvention.StdCall,
EntryPoint = "z4ctygetSTD",
ExactSpelling = false)]
private extern static int z4ctygetSTD(ref CITY_REC args, void * ptr);
Run Code Online (Sandbox Code Playgroud)
当然在C#中,"void*"无法编译.
一些谷歌搜索表明它应该被翻译为"对象".这似乎应该工作.但其他人表示"Void*在C/C++术语中被称为函数指针,在C#术语中是一个委托".在这里,这并不是很有意义,因为它会委托给谁?通过谷歌搜索找到的其他API的类似调用使用相应API中的其他函数.但是在这个API中没有其他调用是有意义的.
该调用的文档显示了一个示例:
z4ctyget(&city, “00000”);
Run Code Online (Sandbox Code Playgroud)
这似乎表明甚至可以传递静态值.
它将使用object代替void*进行编译.我不知道这是否正确,我没有机会对其进行测试(许可问题).
使用PInvoke时会发生什么异常,或者方法返回值处理的所有错误都是由开发人员根据需要检查和引发异常?
我认为委托实例可以与函数实例互换.
请使用以下代码:
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#,你将永远不会看到差异(至少我还没有达到这一点).但是,我最近是一个回调到这个托管代码的非托管代码,它们的处理方式不同.例如,在一个场景中,如果我直接将函数用作回调(即使我的对象实例被保留),我也会得到错误"对垃圾收集的委托进行了回调".使用"委托实例"可以解决问题.
那里有人知道有什么区别吗?
这是我的ClickMouse()函数的代码:
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
private const long MOUSEEVENTF_LEFTDOWN = 0x02;
private const long MOUSEEVENTF_LEFTUP = 0x04;
private const long MOUSEEVENTF_RIGHTDOWN = 0x08;
private const long MOUSEEVENTF_RIGHTUP = 0x10;
private void ClickMouse()
{
long X = Cursor.Position.X;
long Y = Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
出于某种原因,当我的程序来到此代码时,它会抛出此错误消息:
检测到PInvokeStackImbalance消息:调用PInvoke函数'WindowsFormsApplication1!WindowsFormsApplication1.Form1 :: mouse_event'使堆栈失去平衡.这很可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.
请帮忙?
我有一些代码本地win32.自从我升级到.NET 4以来,代码开始抛出一个MethodAccessException:
通过安全透明方法'Tek.Audio.Midi.MidiDevice.GetDevices()'尝试通过方法'Tek.Native.Windows.Multimedia.midiInGetNumDevs()'调用本机代码失败.对于调用本机代码,方法必须是安全关键或安全性安全关键.
这是发生了什么:
Program.Main方法调用library1 public staticTek.Audio.Midi.MidiDevice.GetDevices()GetDevices()调用library2的公共静态pinvoke Tek.Native.Windows.Multimedia.midiInGetNumDevs()(是的,不好的做法,无论如何)涉及的类,方法和程序集上唯一与安全相关的属性是library1上的AllowPartiallyTrustedCallers,我甚至不知道原因.
令我感到羞耻的是,我承认我对.NET的安全性一无所知.我该怎么做才能防止这种异常?虽然我在这里,有什么好文章可以让我开始使用.NET安全性吗?
我有一个具有cdecl回调的ac库.我如何从c#中使用这些.
一切似乎都说他们必须是stdcall回调
要清楚:
delegate int del();
[dllimport("mylib.dll",CallingConvention=CallingConvention.Cdecl)]
public static extern int funcwithcallback(del foo);
Run Code Online (Sandbox Code Playgroud)
其中del必须被称为cdecl-wise
我正在尝试在F#应用程序中使用P/Invoke设置一个低级键盘钩子.Win32函数SetWindowsHookEx接受HOOKPROC第二个参数,我将其表示为委托(int * IntPtr * IntPtr) -> IntPtr,类似于在C#中处理它的方式.在调用方法时,我得到一个MarshalDirectiveException声明,委托参数无法封送,因为
通用类型无法编组
我不确定如何涉及泛型,因为具体指定了所有类型.任何人都可以对此有所了解吗?代码如下.
编辑
这可能与F#编译器处理类型签名的方式有关 - Reflector指示委托LowLevelKeyboardProc实现为接受一个类型的参数的方法Tuple<int, IntPtr, IntPtr>- 并且将存在不可编组的泛型类型.有没有办法解决这个问题,或者F#函数是不是能够被编组到本机函数指针?
let WH_KEYBOARD_LL = 13
type LowLevelKeyboardProc = delegate of (int * IntPtr * IntPtr) -> IntPtr
[<DllImport("user32.dll")>]
extern IntPtr SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, IntPtr hMod, UInt32 threadId)
[<DllImport("kernel32.dll")>]
extern IntPtr GetModuleHandle(string lpModuleName)
let SetHook (proc: LowLevelKeyboardProc) =
use curProc = Process.GetCurrentProcess ()
use curMod = curProc.MainModule
SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curMod.ModuleName), 0u)
Run Code Online (Sandbox Code Playgroud) 我有一个错误的第三方DLL文件,在执行一段时间后,开始抛出访问冲突异常.当发生这种情况时,我想重新加载该DLL文件.我怎么做?
可能重复:
Windows API和.net语言
我想从.NET Framework调用本机Windows API.我希望有一个简单的方法,我可以像其他.NET API一样从高级层调用本机API.请参阅您知道的任何资源.任何帮助将不胜感激.
约束执行区域是C#/ .Net的一个特性,它允许开发人员尝试从关键的代码区域中提升"三大"异常--OutOfMemory,StackOverflow和ThreadAbort.
CER通过推迟ThreadAborts,准备调用图中的所有方法来实现这一点(因此不会发生JIT,这可能导致分配),并确保有足够的堆栈空间来适应随后的调用堆栈.
典型的不间断区域可能如下所示:
public static void GetNativeFlag()
{
IntPtr nativeResource = new IntPtr();
int flag;
// Remember, only the finally block is constrained; try is normal.
RuntimeHelpers.PrepareConstrainedRegions();
try
{ }
finally
{
NativeMethods.GetPackageFlags( ref nativeResource );
if ( nativeResource != IntPtr.Zero ) {
flag = Marshal.ReadInt32( nativeResource );
NativeMethods.FreeBuffer( nativeResource );
}
}
}
Run Code Online (Sandbox Code Playgroud)
上述内容大部分都很好,因为CER内部没有任何规则被破坏 - 所有.Net分配都在CER之外,Marshal.ReadInt32()具有兼容性ReliabilityContract,我们假设我的NativeMethods被类似地标记,以便VM可以正确地考虑他们在准备CER时.
因此,除了所有这些之外,您如何处理分配必须在CER内部发生的情况?分配违反规则,因为很有可能获得OutOfMemoryException.
在查询本机API(SSPI的QuerySecurityPackageInfo)时,我遇到了这个问题,这会迫使我违反这些规则.本机API确实执行自己的(本机)分配,但如果失败,我只得到一个空的结果,所以没有什么大不了的.但是,在它分配的结构中,它存储了一些未知大小的C字符串.
当它返回指向它所分配的结构的指针时,我必须复制整个事物,并分配空间来存储这些c字符串作为.Net字符串对象.毕竟,我应该告诉它释放分配.
但是,由于我在CER中执行.Net分配,我违反规则并可能泄漏一个句柄.
处理这个问题的正确方法是什么?
对于它的价值,这是我天真的方法:
internal static SecPkgInfo GetPackageCapabilities_Bad( string packageName )
{
SecPkgInfo info; …Run Code Online (Sandbox Code Playgroud)