gpt4 book ai didi

c++ - 无法使用 SQL VDI(虚拟设备接口(interface))创建 strip 化备份

转载 作者:行者123 更新时间:2023-11-28 04:03:19 25 4
gpt4 key购买 nike

这是一个令人难以置信的远射,但这里是。我们正在使用 SQLVDI API(虚拟设备接口(interface))制作数据库备份实用程序。单一备份的实现没有问题。但是当我们开始实现 strip 备份(使用 virtual_device)时,我们遇到了 IClientVirtualDeviceSet2::OpenDevice 方法的问题。我们的虚拟设备集无法打开所有设备。仅返回第一个设备,在第二个设备上我们收到 VD_E_PROTOCOL 错误。任何建议将不胜感激。

我们的 C++ 代码。

public: Void ExecuteCommandEx(System::String^ command, array<Stream^>^ commandStreamListIn)
{
try
{
//Initialize COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "CoInitializeEx Failed HRESULT: {0}", hr));
}
//Get an interface to the virtual device set
IClientVirtualDeviceSet2* vds = NULL;
hr = CoCreateInstance(CLSID_MSSQL_ClientVirtualDeviceSet, NULL, CLSCTX_INPROC_SERVER, IID_IClientVirtualDeviceSet2, (void**)&vds);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Unable to get an interface to the virtual device set. Please check to make sure sqlvdi.dll is registered. HRESULT: {0}", hr));
}
//Configure the device configuration
VDConfig config = { 0 };
config.deviceCount = commandStreamListIn->Length; //The number of virtual devices to create
//Create a name for the device using a GUID
String^ DeviceName = Guid::NewGuid().ToString()->ToUpper(gcnew CultureInfo("en-US"));
WCHAR wVdsName[37] = { 0 };
Marshal::Copy(DeviceName->ToCharArray(), 0, (IntPtr)wVdsName, DeviceName->Length);
//Create the virtual device set
hr = vds->CreateEx(NULL, wVdsName, &config);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Unable to create and configure the virtual device set. HRESULT: {0}", hr));
}
//Format the command
List<String^>^ vdNames = gcnew List<String^>();
vdNames->Add(DeviceName);
for (int i = 0; i < commandStreamListIn->Length-1; i++)
{
String^ streamName = Guid::NewGuid().ToString()->ToUpper(gcnew CultureInfo("en-US"));
vdNames->Add(streamName);
}
command = String::Format(gcnew CultureInfo("en-US"), command, vdNames->ToArray());
//Create and execute a new thread to execute the command
Thread^ OdbcThread = gcnew Thread(gcnew ParameterizedThreadStart(this, &VdiDotNetEx::VdiEngineEx::ThreadFunc));
OdbcThread->Start(command);
//Configure the virtual device set
hr = vds->GetConfiguration(INFINITE, &config);
if (hr != NOERROR)
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "GetConfiguration Failed. HRESULT: {0}", hr));
}
if (FAILED(hr))
{
switch (hr)
{
case VD_E_ABORT:
throw gcnew ApplicationException("GetConfiguration was aborted.");
break;
case VD_E_TIMEOUT:
throw gcnew ApplicationException("GetConfiguration timed out.");
break;
default:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Un unknown exception was thrown during GetConfiguration. HRESULT: {0}", hr));
break;
};
}
int count = 0;
array<IClientVirtualDevice*>^ vDevices= gcnew array<IClientVirtualDevice*>(commandStreamListIn->Length);

//Open all devices on the device set
//VD_E_OPEN may be returned without problem. The client may call OpenDevice by means of a loop until this code is returned.
//If more than one device is configured(for example, n devices),
//the virtual device set will return n unique device interfaces.
//The first device has the same name as the virtual device set.
//Other devices are named as specified with the VIRTUAL_DEVICE clauses of the BACKUP / RESTORE statement.

while (hr!= VD_E_OPEN)
{
IClientVirtualDevice* vd = NULL;
hr = vds->OpenDevice(wVdsName, &vd);
switch(hr)
{
case VD_E_OPEN:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_OPEN. HRESULT: {0}", hr));
break;
case VD_E_BUSY:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_BUSY. HRESULT: {0}", hr));
break;
case VD_E_CLOSE:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_CLOSE. HRESULT: {0}", hr));
break;
case VD_E_UNEXPECTED:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_UNEXPECTED. HRESULT: {0}", hr));
break;
case VD_E_INVALID:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_INVALID. HRESULT: {0}", hr));
break;
case VD_E_NOTOPEN:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_NOTOPEN. HRESULT: {0}", hr));
break;
case VD_E_PROTOCOL:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_PROTOCOL. HRESULT: {0}", hr));
break;
}
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. HRESULT: {0}", hr));
}
vDevices[count] = vd;

count++;
}
for (int i = 0; i < count; i++)
{
ExecuteDataTransfer(vDevices[i], commandStreamListIn[i]);
}

//Wait for the thread that issued the backup / restore command to SQL Server to complete.
OdbcThread->Join();
}
catch (Exception ^ex)
{
Debug::WriteLine("VDI: Exception=" + ex->Message->ToString());
Debug::WriteLine("VDI: Trace=" + ex->StackTrace);
Console::WriteLine(ex->Message);
LogException(ex);
throw gcnew ApplicationException(ex->Message);
}
}

COM相关代码:(combaseapi.h)

#pragma region Application or OneCore Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
_Check_return_ WINOLEAPI
CoInitializeEx(
_In_opt_ LPVOID pvReserved,
_In_ DWORD dwCoInit
);

#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
#pragma endregion
_Check_return_ WINOLEAPI
CoCreateInstance(
_In_ REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter,
_In_ DWORD dwClsContext,
_In_ REFIID riid,
_COM_Outptr_ _At_(*ppv, _Post_readable_size_(_Inexpressible_(varies))) LPVOID FAR * ppv
);

最佳答案

根据 SQLVDI 文档,OpenDevice 不工作。例如,不要期望 VD_E_OPEN 作为结果,只需 0 即可。此外,不仅要将虚拟设备集名称传递给此方法,还要传递命令中每个 virtual_device 的 GUID。看看这个调整后的代码。

for(int i = 0; i < vdNames->Count; i++)
{
IClientVirtualDevice* vd = NULL;
WCHAR wDevName[37] = { 0 };

String^ vdName = vdNames[i];
Marshal::Copy(vdName->ToCharArray(), 0, (IntPtr)wDevName, vdName->Length);

hr = vds->OpenDevice(wDevName, &vd);
switch(hr)
{
case VD_E_BUSY:
DBGPRINTW(L"VDI: Exception 15\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_BUSY. HRESULT: {0}", hr));
break;
case VD_E_CLOSE:
DBGPRINTW(L"VDI: Exception 14\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_CLOSE. HRESULT: {0}", hr));
break;
case VD_E_UNEXPECTED:
DBGPRINTW(L"VDI: Exception 11\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_UNEXPECTED. HRESULT: {0}", hr));
break;
case VD_E_INVALID:
DBGPRINTW(L"VDI: Exception 06\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_INVALID. HRESULT: {0}", hr));
break;
case VD_E_NOTOPEN:
DBGPRINTW(L"VDI: Exception 02\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_NOTOPEN. HRESULT: {0}", hr));
break;
case VD_E_PROTOCOL:
DBGPRINTW(L"VDI: Exception 12\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_PROTOCOL. HRESULT: {0}", hr));
break;

}
if (FAILED(hr))
{
DBGPRINTW(L"VDI: Exception 08\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. HRESULT: {0}", hr));
}

vDevices[i] = vd;
count++;
}

关于c++ - 无法使用 SQL VDI(虚拟设备接口(interface))创建 strip 化备份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59156030/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com