我正在使用Visual Studio 2010并在c#中编码。
public partial class App : Application
{
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrOpenProtected(string lpVolume);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrCommit(IntPtr hDevice);
public static bool EWFcommit()
{
temp = true;
string strVolumeName = "C:";
hProVol = EwfMgrOpenProtected(strVolumeName);
temp = EwfMgrCommit(hProVol);
return temp;
}
}
我遇到的问题是这些命令在启用了EWF的计算机上不起作用。 我试图从ewfmanager获取卷名而不是将其硬编码为“C:”。但是,我还在学习,我在使用命令“EwfMgrGetProtectedVolumeList”时遇到了麻烦。这个api命令将返回运行其他ewfapi命令所需的VolumeName。但是,此命令返回我需要定义的“PEWF_VOLUME_NAME_ENTRY”变量。这是我被卡住的地方。 在C ++中,头文件定义了此变量,但在c#头文件中不存在。我是否必须将C ++代码转换为c#代码才能使用头文件中定义的结构? 目前,我正在使用通过命令提示符执行命令的工作,它完美无缺。但是,我很好奇,想要在c#中学习“正确”/最好的方法。 请告诉我在C#中使用api命令的任何经验。谢谢。
这是我试图转换为C#的代码。我不确定如何将C ++中的声明符转换为C#。
typedef struct _EWF_VOLUME_NAME_ENTRY
{
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR Name[1];
} EWF_VOLUME_NAME_ENTRY, * PEWF_VOLUME_NAME_ENTRY;
这是没有声明符的转换后的C#代码:
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
public string Name;
}
答案 0 :(得分:1)
你的尝试实际上非常接近,只需要一些属性来帮助编译器(实际上它可能没有它们)
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=1)]
public string Name;
}
要使用它,您的方法的P / Invoke签名将是。
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrGetProtectedVolumeList();
您还需要更多功能
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameListDelete(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrVolumeNameListIsEmpty(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameEntryPop(ref IntPtr list);
然后,您可以获得受保护卷的列表。
public IEnumerable<string> GetProtectedVolumeNames()
{
var listptr = EwfMgrGetProtectedVolumeList();
if(listptr == IntPtr.Zero)
throw new Win32Exception(); //the default constuctor calls Marshal.GetLastWin32Error() for you.
try
{
while(!EwfMgrVolumeNameListIsEmpty(listPtr))
{
var currentStruct = Marshal.PtrToStructure<EWF_VOLUME_NAME_ENTRY>(listPtr);
// Pre .NET 4.5.1 version
// var currentStruct = (EWF_VOLUME_NAME_ENTRY)Marshal.PtrToStructure(listPtr, typeof(EWF_VOLUME_NAME_ENTRY));
yield return currentStruct.Name;
EwfMgrVolumeNameEntryPop(ref listPtr);
}
}
finally
{
if(listptr != IntPtr.Zero)
EwfMgrVolumeNameListDelete(listptr);
}
}
请注意,此代码是在浏览器中编写的,未经测试,但我认为它应该有效。
编辑:重要提示,如果您在foreach
之外使用此功能,而是手动浏览IEnumerable
,请务必将其丢弃,否则最后一个块将无法执行,您将拥有内存泄漏(当你离开循环范围时,foreach
会自动为你调用disposes。)
在旁注中,您可能想查看这篇旧的MSDN杂志文章:“Making PInvoke Easy”。它包含一个程序的链接,您可以为其提供C / C ++签名,它将为您提供.NET P / Invoke签名的粗略版本。
答案 1 :(得分:0)
向Scotts答复的小调整。该名称是以空字符结尾的字符串,因此请增加SizeConst以获取名称的其余字符:
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=300)]
public string Name;
}