似乎您唯一的绊脚石是格式化为 UDF。fmfifs.dll 中的 FormatEx 是一个 shim(或帮助程序)实用程序,它作为 Microsoft 可安装文件系统基础结构 ( IFS ) 的一部分将格式化任务分派给较低级别的驱动程序。IFS 基本上允许微软添加对新文件系统的支持。
对于 UDF,对应的库是 UUDF.DLL(此约定适用于其他文件系统,例如 NTFS 将由 UNTFS.DLL、UFAT.DLL 等处理)。您的 Windows XP 系统上是否存在此 dll?
查看使用depends.exe 导出的UUDF.dll,我看到了对各种功能的支持,包括臭名昭著的FormatEx。FormatEx 似乎是 cdecl 并且(查看反汇编)需要 16 个字节的参数(可能是 4 个参数)。虽然能够直接调用该函数会很方便,但它没有在任何地方记录,而且弄清楚参数会很痛苦。此外,我假设 fmifs.dll 会做正确的事情,如果可以的话。
UDF 支持多个修订版(请参阅 OSTA 规范) - 您的问题很可能是您在 WinXP 上的 UUDF.dll 版本与您的 DVD-RAM 格式化的 UDF 版本存在问题。
您可以做的是将DeviceIOControl函数与IOCTL_SCSCI_PASSHTHROUGH_DIRECT控制代码一起使用,这将使您能够直接与设备对话。应该可以使用 SCSI/MMC(多媒体命令)格式化 DVD-RAM - 查找FORMAT_UNIT 命令的描述。MMC 命令在http://www.t10.org/drafts.htm#MMC_Family T10 工作草稿中指定 - 它们很难掌握,但我相信注册后可以以访客身份下载副本。
如果简单的 (fmifs.dll) 方法不适合您,您将不得不以艰难的方式进行操作,或者找到第三方 dll 来帮助您。
更新:
查看 MSDN,XP Service Pack 2 支持 IMAPI2(Image Mastering API)。使用 fmifs.dll 的替代方法是使用 IDicFormat2Erase 接口的 EraseMedia() 函数擦除光盘,然后使用 IFileSystemImage 接口的 FileSystemsToCreate( ) 函数格式化为 UDF。可能比 DeviceIOControl 路由更简单。
因为我从来没有这样做过,所以我决定把一个简单的例子放在一起。它快速、肮脏且未经测试(在 DVD-RW 上创建了 UDF rev 2.50 文件系统,仅此而已),但它是一个起点(Visual Studio 2012):
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <Windows.h>
#include <imapi2.h>
#include <imapi2fs.h>
#include <imapi2error.h>
#include <imapi2fserror.h>
#include <comdef.h>
void ShowComError(HRESULT hr)
{
LPWSTR lpMsgBuf;
DWORD ret;
std::cout << "Failed - HRESULT = 0x" << std::hex << hr << std::endl;
ret = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(TEXT("imapi2.dll")),
hr,
0,
(LPWSTR) &lpMsgBuf,
0, NULL );
if(ret)
{
std::wcout << L"HRESULT: " << lpMsgBuf << std::endl;
LocalFree(lpMsgBuf);
}
}
int main()
{
IDiscMaster2* ppMaster = NULL;
IDiscRecorder2* ppRecorder = NULL;
IDiscFormat2Erase* ppFormat2 = NULL;
IDiscFormat2Data* ppFormat2Data = NULL;
IFileSystemImage* ppFileImage = NULL;
IStream* fs = NULL;
IFileSystemImageResult* res = NULL;
HRESULT hr = CoInitialize(NULL);
BSTR clientName = SysAllocStringLen(L"TestBurner", lstrlen(L"TestBurner"));
SAFEARRAY* multi = NULL; // multi-sessions
hr = CoCreateInstance(__uuidof(MsftDiscMaster2),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiscMaster2),
(void **) &ppMaster);
if (FAILED(hr))
{
ShowComError(hr);
//nothing-wrong-with-a-goto-when-its-heart's-in-the-right-place ;)
goto Clean_Up;
}
hr = CoCreateInstance(__uuidof(MsftDiscRecorder2),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiscRecorder2),
(void **) &ppRecorder);
if (FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = CoCreateInstance(__uuidof(MsftDiscFormat2Erase),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiscFormat2Erase),
(void**) &ppFormat2);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = CoCreateInstance(__uuidof(MsftDiscFormat2Data),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiscFormat2Data),
(void**) &ppFormat2Data);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = CoCreateInstance(__uuidof(MsftFileSystemImage),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IFileSystemImage),
(void**) &ppFileImage);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
// got here - get the optical drives
LONG countDevices;
hr = ppMaster->get_Count(&countDevices);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
VARIANT_BOOL supported;
hr = ppMaster->get_IsSupportedEnvironment(&supported);
// check if it's supported - if yes we use it to format
// and then break out...
if(SUCCEEDED(hr) && supported == VARIANT_TRUE)
{
BSTR deviceName;
for(LONG i = 0; i < countDevices; i++)
{
hr = ppMaster->get_Item(i, &deviceName);
if(SUCCEEDED(hr))
{
std::wcout << L"Using: " << deviceName << std::endl;
hr = ppRecorder->InitializeDiscRecorder(deviceName);
if(FAILED(hr)) goto Clean_Up;
hr = ppRecorder->AcquireExclusiveAccess(VARIANT_TRUE, clientName);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = ppFormat2->put_Recorder(ppRecorder);
if(FAILED(hr)) goto Clean_Up;
// need to set client_name before erasing
hr = ppFormat2->put_ClientName(clientName);
if(FAILED(hr)) ShowComError(hr);
//SysFreeString(clientName);
BSTR owner = NULL;
hr = ppRecorder->get_ExclusiveAccessOwner(&owner);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
if(owner)
{
std::wcout << owner << std::endl;
SysFreeString(owner);
}
// erase the disc
hr = ppFormat2->put_FullErase(VARIANT_TRUE);
if(FAILED(hr)) goto Clean_Up;
hr = ppFormat2->EraseMedia();
if(FAILED(hr))
{
ShowComError(hr); // Need to pull eventual errors out of imapi2error omitted...
//goto Clean_Up;
}
hr = ppFormat2Data->put_Recorder(ppRecorder);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = ppFormat2Data->put_ClientName(clientName);
if(FAILED(hr)) ShowComError(hr);
hr = ppFormat2->IsCurrentMediaSupported(ppRecorder, &supported);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
VARIANT_BOOL blank;
hr = ppFormat2Data->get_MediaHeuristicallyBlank(&blank);
if(blank == VARIANT_FALSE)
{
hr = ppFormat2Data->get_MultisessionInterfaces(&multi);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
}
/*hr = ppFileImage->ChooseImageDefaults(ppRecorder);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}*/
FsiFileSystems imported = FsiFileSystemNone;
if(multi)
{
hr = ppFileImage->put_MultisessionInterfaces(multi);
if(FAILED(hr))
{
ShowComError(hr);
}
hr = ppFileImage->ImportFileSystem(&imported);
}
if(imported == FsiFileSystemNone || imported == FsiFileSystemUnknown)
{
imported = FsiFileSystemUDF;
// ask for UDF revision 2.50
hr = ppFileImage->put_UDFRevision(0x250);
if(FAILED(hr))
{
ShowComError(hr);
}
}
hr = ppFileImage->put_FileSystemsToCreate(imported);
if(FAILED(hr))
{
ShowComError(hr);
}
hr = ppFileImage->CreateResultImage(&res);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = res->get_ImageStream(&fs);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = ppFormat2Data->put_ForceOverwrite(VARIANT_TRUE);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = ppFormat2Data->Write(fs);
if(FAILED(hr))
{
ShowComError(hr);
goto Clean_Up;
}
hr = ppRecorder->EjectMedia();
break;
}
}
}
// clean up
Clean_Up:
if(res) res->Release();
if(fs) fs->Release();
if(multi) SafeArrayDestroy(multi);
if(clientName) SysFreeString(clientName);
if(ppFileImage) ppFileImage->Release();
if(ppFormat2Data) ppFormat2Data->Release();
if(ppFormat2) ppFormat2->Release();
if(ppRecorder) ppRecorder->Release();
if(ppMaster) ppMaster->Release();
CoUninitialize();
/**/
std::cout << "Press any key to continue..." << std::endl;
std::cin.get();
return 0;
}