增强型写过滤器api c#

时间:2014-09-03 16:41:45

标签: c# api

我正在使用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;
    }

2 个答案:

答案 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;
}