Я использую Visual Studio 2010 и кодировку в С#.
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 вместо hardcoding на "C:". Тем не менее, я все еще учился, и у меня возникли проблемы с использованием команды "EwfMgrGetProtectedVolumeList". Эта команда api вернет имя тома, в котором мне нужно запустить другие команды ewfapi. Однако эта команда возвращает переменную "PEWF_VOLUME_NAME_ENTRY", которую мне нужно определить. Здесь я застреваю. В C++ файл заголовка определяет эту переменную, но в С# заголовочные файлы не существует. Должен ли я преобразовать код C++ в код С#, чтобы использовать структуры, определенные в файле заголовка? В настоящее время я использую работу, выполняя команды с помощью командной строки, которая работает безупречно. Но мне любопытно и хочу узнать "правильный"/лучший способ сделать это в С#. Пожалуйста, дайте мне знать о любом опыте использования команд api в С#. Спасибо.
Это код, который я пытаюсь преобразовать в С#. Я не уверен, как преобразовать Declarators в C++ в С#.
typedef struct _EWF_VOLUME_NAME_ENTRY
{
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR Name[1];
} EWF_VOLUME_NAME_ENTRY, * PEWF_VOLUME_NAME_ENTRY;
Это преобразованный код С# без деклараторов:
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 Easy ". Он включает ссылку на программу, которую вы можете дать ей подписи C/C++, и она вернет вам грубую версию подписи.NET P/Invoke.
Незначительная настройка на ответ Скотта. Имя - это строка с нулевым завершением, поэтому увеличьте 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;
}
ewfapi.dll
посвящены целые сайты (я проверял, не виделewfapi.dll
).