增强的写过滤器api c#
本文关键字:api 过滤器 增强的 | 更新日期: 2023-09-27 18:20:28
我使用的是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++中的Declarator转换为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;
}
您的尝试实际上非常接近,它只需要一些属性来帮助编译器(事实上,如果没有它们,它可能会工作)
[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);
}
}
注意,这段代码是在浏览器中编写的,未经测试,但我认为它应该可以工作。
EDIT:重要提示,如果您在foreach
之外使用此函数,而是手动处理IEnumerable
,请确保将其处理掉,否则finally块将不会执行,并且您将出现内存泄漏(当您离开循环范围时,foreach
会自动为您调用dispose)。
顺便说一句,你可能想看看MSDN杂志的这篇旧文章:"让PInvoke变得容易"。它包含一个指向程序的链接,您可以为该程序提供C/C++签名,它将为您返回.NET P/Invoke签名的粗略版本。
对斯科特的回答进行了小调整。名称是一个以null结尾的字符串,因此增加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;
}