我想知道是否有任何方法可以在VS 2010中调试从C#PInvoke调用的c ++ dll.我试图将项目附加到c#应用程序但它没有工作 - 没有停在断点处.
我还尝试在C++项目中使用OutputDebugString记录任何内容,但没有使用PInvoke调用打印.尽管存在这些问题,但实际功能运行良好.
任何建议将被认真考虑.
我想当我使用IntPtr.Size时我应该得到8.但是我仍然使用Widnows 7 x64在x64机器上获得4个,为什么?
我遇到的情况CloseHandle是,SEHException在调试器下运行时,PInvoke调用将在.NET 4应用程序中抛出.与其他遇到类似问题从3.5迁移到4的问题不同,我并没有特别担心这种行为,并且已经找到了问题(第三方库CloseHandle在同一个句柄上调用了两次).但是,我很困惑为什么在.NET 3.5应用程序中不会发生这种行为.
以下小但完整的示例演示了我遇到的行为(在XP SP3和Win 7 x64上测试,总是编译为x86):
class Program
{
static void Main(string[] args)
{
try
{
var hFileMapping = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04 /* read write */, 0, 0x1000, null);
CloseHandle(hFileMapping);
CloseHandle(hFileMapping);
Console.WriteLine("No exception");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
[DllImport("kernel32", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle); …Run Code Online (Sandbox Code Playgroud) 所以,这个问题已经出现了很多变种,在看了几个后我仍然无法弄明白.
这是C代码:
typedef struct
{
unsigned long Identifier;
char Name[128];
} Frame;
Frame GetFrame(int index);
Run Code Online (Sandbox Code Playgroud)
这是C#代码:
struct Frame
{
public ulong Identifier;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 128)]
public char[] Name;
}
[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern Frame GetFrame(int index);
Run Code Online (Sandbox Code Playgroud)
这是我在C#中尝试过的最后一次尝试,看起来非常符合逻辑,但我得到的错误是"方法的签名与PInvoke不兼容".所以,我有点迷失下一步的尝试.任何帮助表示赞赏.
谢谢,凯文
Kevin 更新了这个作为我的答案的编辑
我应该改变我的C代码:
void GetFrame(int index, Frame * f);
Run Code Online (Sandbox Code Playgroud)
并使用C#代替:
struct Frame
{
public uint Identifier;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)]
public string Name;
}
[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] …Run Code Online (Sandbox Code Playgroud) 我的项目在.NET Frame 3.5中成功运行且没有错误.但是,当我将它定位到.NET Frame工作4.我得到了错误:
" 对PInvoke函数的调用使堆栈失衡.这可能是因为托管的PInvoke签名与非托管目标签名不匹配. "
我使用了非托管库,如下所示:
[StructLayout(LayoutKind.Sequential )]
public class DGNElemCore
{
public int offset;
public int size;
public int element_id;
public int stype;
public int level;
public int type;
public int complex;
public int deleted;
public int graphic_group;
public int properties;
public int color;
public int weight;
public int style;
public int attr_bytes;
public IntPtr attr_data;
public int raw_bytes;
public IntPtr raw_data;
}
[DllImport("DgnLib.dll", EntryPoint = "DGNOpen")]
public static extern IntPtr DGNOpen(string fileName, int bUpdate)
Run Code Online (Sandbox Code Playgroud)
你知道如何解决这个错误吗?
我有以下C++函数定义,我试图通过托管代码通过PInvoke调用:
bool FooBar(SIZE_T* arg1);
Run Code Online (Sandbox Code Playgroud)
我的管理声明如下:
[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref uint arg1);
Run Code Online (Sandbox Code Playgroud)
有些人可能会注意到我最终做的同样的错误.这不是64位便携式.SIZE_T的大小可变(32-64位),指针也是如此.在托管大小上,指针正确转换为64位,但uint没有,并且您最终可以在arg1的高位中使用垃圾.这是一个特别持久的错误,因为垃圾通常只是零:(
我已经开始工作的唯一解决方案是以下管理声明:
[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref IntPtr arg1);
Run Code Online (Sandbox Code Playgroud)
这当然有效,因为IntPtr可以正确地改变它的大小.在我的代码中,我只是将IntPtr视为一个整数,它可以工作,虽然它看起来像一个丑陋的黑客.在我看来应该有一些方法来正确指定,也许使用UnmanagedType.SysUInt,但我无法提出任何其他工作解决方案.
让我们说我正在访问第三方库,其文档声明我可以使用pInvoke或创建互操作库并使用COM.这两种技术有什么区别,为什么我可以选择其中一种?
我遇到了锁定Windows工作站的示例:
using System.Runtime.InteropServices;
...
[DllImport("user32.dll", SetLastError = true)]
static extern bool LockWorkStation();
...
if (!LockWorkStation())
throw new Win32Exception(Marshal.GetLastWin32Error()); // or any other thing
Run Code Online (Sandbox Code Playgroud)
这个片段有一个纯粹的托管替代方案吗?即,没有P-Invoke.
我有一个从C#应用程序调用的非托管C++ DLL,我试图让C#应用程序捕获所有异常,以便在由于非托管异常导致dll失败的情况下,用户将得到一个半合适的错误消息(C#app是一个实现它自己的http处理程序的Web服务).
我遇到的问题是并非所有类型都被捕获.因此,如果我创建以下内容并执行C#应用程序,则dll会抛出错误并终止整个应用程序.有任何想法吗?
这是在VS2005中使用.Net framework v2创建的
C++ - Test.h
#ifndef INC_TEST_H
#define INC_TEST_H
extern "C" __declspec(dllexport) void ProcessBadCall();
#endif
Run Code Online (Sandbox Code Playgroud)
C++ - Test.cpp
#include <iostream>
#include <vector>
using namespace std;
void ProcessBadCall()
{
vector<int> myValues;
int a = myValues[1];
cout << a << endl;
}
Run Code Online (Sandbox Code Playgroud)
C# - Program.cs
class Program
{
[DllImport("Test.dll", EntryPoint="ProcessBadCall")]
static extern void ProcessBadCall();
static void Main(string[] args)
{
try
{
ProcessBadCall();
}
catch (SEHException ex)
{
Console.WriteLine("SEH Exception: {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个WPF窗口WindowStyle="None"(用于自定义按钮,没有标题),无法调整大小.设置ResizeMode以NoResize删除我想要保留的空气边界.
我可以设置最小/最大尺寸属性并完成它,除了:
所以,我有一个简单的方案,让我99%的方式:
public class BorderedWindowNoResize : Window
{
[DllImport( "DwmApi.dll" )]
public static extern int DwmExtendFrameIntoClientArea(
IntPtr hwnd,
ref MARGINS pMarInset );
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern IntPtr DefWindowProc(
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam );
public BorderedWindowNoResize()
{
Loaded += BorderedWindowNoResize_Loaded;
}
private void BorderedWindowNoResize_Loaded( object sender, RoutedEventArgs e )
{
IntPtr mainWindowPtr = new WindowInteropHelper( this ).Handle;
HwndSource mainWindowSrc = HwndSource.FromHwnd( mainWindowPtr ); …Run Code Online (Sandbox Code Playgroud)