Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes, the virtual disk API supports the ability to create and mount a volume without assigning it a drive letter. This is done by passing <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd323693%28v=vs.85%29.aspx"><code>ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER</code></a> to <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd323692%28v=vs.85%29.aspx"><code>AttachVirtualDisk</code></a></p> <pre><code>// This call requires elevated privileges to succeed. ::AttachVirtualDisk( handle, // Handle returned by CreateVirtualDisk or OpenVirtualDisk NULL, ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, // no provider-specific flags 0, // no parameters NULL); </code></pre> <p>The difficult part is accessing the volume without a drive letter. The virtual disk API does not provide a straight forward way of getting a list of volumes that are on the virtual drive. This is important since you must access the volume through a UNC path as the drive letter is not available. To get the UNC path you need to enumerate all mounted volumes to find the volume(s) located on the virtual hard drive. This is done by opening each mounted volume and using <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb968800%28v=vs.85%29.aspx"><code>DeviceIoControl</code></a> to retrieve the device information associated with the file handle.</p> <p>The included example performs the following steps to create, mount and access a <em>hidden</em> volume on our virtual drive.</p> <ol> <li>Create or open the virtual disk file with <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd323659%28v=vs.85%29.aspx"><code>CreateVirtualDisk</code></a> or <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd323680%28v=vs.85%29.aspx"><code>OpenVirtalDisk</code></a> respectively.</li> <li>Attach the virtual disk with <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd323692%28v=vs.85%29.aspx"><code>AttachVirtualDisk</code></a>. <em>You must have elevated privileges for this step to succeed</em>.</li> <li>Initialize the device.</li> <li>Create a volume on the device.</li> <li>Enumerate mounted volumes to find the ones on the virtual disk.</li> </ol> <p>[<em>Steps 3 and 4 need to be done manually from the Disk Management control panel. This can of course be done programmatically but would add a lot more code to the example.</em>]</p> <pre><code>#include &lt;iostream&gt; #include &lt;fstream&gt; #include &lt;string&gt; #include &lt;virtdisk.h&gt; #pragma comment(lib, "virtdisk.lib") // Fix unresolved link error static const GUID VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = { 0xEC984AEC, 0xA0F9, 0x47e9, 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B }; #define ARRAY_SIZE(a) \ ((sizeof(a) / sizeof(*(a))) / \ static_cast&lt;size_t&gt;(!(sizeof(a) % sizeof(*(a))))) DWORD CreateDisk(PCWSTR virtualDiskFilePath, HANDLE *handle) { VIRTUAL_STORAGE_TYPE storageType = { VIRTUAL_STORAGE_TYPE_DEVICE_VHD, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT }; CREATE_VIRTUAL_DISK_PARAMETERS parameters = {}; parameters.Version = CREATE_VIRTUAL_DISK_VERSION_1; parameters.Version1.MaximumSize = 1024 * 1024 * 1024; parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE; parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE; parameters.Version1.SourcePath = NULL; int result = ::CreateVirtualDisk( &amp;storageType, virtualDiskFilePath, VIRTUAL_DISK_ACCESS_ALL, NULL, CREATE_VIRTUAL_DISK_FLAG_NONE, 0, &amp;parameters, NULL, handle); return result; } DWORD OpenDisk(PCWSTR virtualDiskFilePath, HANDLE *handle) { VIRTUAL_STORAGE_TYPE storageType = { VIRTUAL_STORAGE_TYPE_DEVICE_VHD, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT }; OPEN_VIRTUAL_DISK_PARAMETERS parameters = { OPEN_VIRTUAL_DISK_VERSION_1 }; parameters.Version1.RWDepth = 1024; return ::OpenVirtualDisk( &amp;storageType, virtualDiskFilePath, VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &amp;parameters, handle); } int main(int argc, char *argv[]) { LPTSTR virtualDiskFilePath = _T("c:\\source\\drive.vhd"); HANDLE handle; DWORD result; ULONG bytesUsed; bool vhdCreated = false; // Create or open a virtual disk file result = CreateDisk(virtualDiskFilePath, &amp;handle); if(result == ERROR_FILE_EXISTS) { result = OpenDisk(virtualDiskFilePath, &amp;handle); if(result != ERROR_SUCCESS) { std::wcout &lt;&lt; "Unable to open virtual disk" &lt;&lt; std::endl; return 1; } } else if(result != ERROR_SUCCESS) { std::wcout &lt;&lt; "Unable to create virtual disk" &lt;&lt; std::endl; return 1; } else { vhdCreated = true; } // Now that the virtual disk is open we need to mount it. // // FROM MSDN: // To attach and detach a virtual disk, you must also have the // SE_MANAGE_VOLUME_NAME privilege present in your token. This privilege // is stripped from an administrator's token when User Account Control is // in use, so you may need to elevate your application to gain access to // the unrestricted token that includes this privilege. result = ::AttachVirtualDisk( handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, // no provider-specific flags 0, // no parameters NULL); if(result != ERROR_SUCCESS) { std::wcout &lt;&lt; "Unable to attach virtual disk" &lt;&lt; std::endl; return 1; } if(result == ERROR_SUCCESS &amp;&amp; vhdCreated == true) { std::wcout &lt;&lt; "Virtual disk image created. Go into the Computer Management admin panel" &lt;&lt; std::endl &lt;&lt; "and add a volume and format it.\n" &lt;&lt; std::endl; system("pause"); } // Now we need to grab the device name \\.\PhysicalDrive# TCHAR physicalDriveName[MAX_PATH]; DWORD physicalDriveNameSize = ARRAY_SIZE(physicalDriveName); result = ::GetVirtualDiskPhysicalPath(handle, &amp;physicalDriveNameSize, physicalDriveName); if(result != ERROR_SUCCESS) { std::wcout &lt;&lt; "Unable to retrieve virtual disk path" &lt;&lt; std::endl; return 1; } const std::wstring deviceName = physicalDriveName; // HACK!!! Wait for windows to complete the mount. Sleep(2500); // In order to get the UNC path of the volumes located on the virtual disk we // need to enumerate all mounted volumes and check which device they are located // on. std::wstring volumeName; TCHAR volumeNameBuffer[MAX_PATH]; HANDLE hVol = ::FindFirstVolume(volumeNameBuffer, ARRAY_SIZE(volumeNameBuffer)); if(hVol == INVALID_HANDLE_VALUE) { std::wcout &lt;&lt; "Unable to find first volume" &lt;&lt; std::endl; return 1; } do { // Get rid of trailing backslash so we can open the volume size_t len = wcslen(volumeNameBuffer); if (volumeNameBuffer[len-1] == '\\') { volumeNameBuffer[len-1] = 0; } HANDLE volumeHandle = ::CreateFile( volumeNameBuffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); if(volumeHandle == INVALID_HANDLE_VALUE) { std::wcout &lt;&lt; "Unable to open volume " &lt;&lt; volumeNameBuffer &lt;&lt; std::endl; } else { // We can grab the id of the device and use it to create a // proper device name. STORAGE_DEVICE_NUMBER deviceInfo = {0}; if (::DeviceIoControl( volumeHandle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &amp;deviceInfo, sizeof(deviceInfo), &amp;bytesUsed, NULL)) { std::wstring tmpName( std::wstring(L"\\\\.\\PhysicalDrive") + std::to_wstring((long long)deviceInfo.DeviceNumber)); if(_wcsicmp(tmpName.c_str(), deviceName.c_str()) == 0) { volumeName = std::wstring(volumeNameBuffer) + L"\\\\"; CloseHandle(volumeHandle); break; } } CloseHandle(volumeHandle); } } while(::FindNextVolume(hVol, volumeNameBuffer, ARRAY_SIZE(volumeNameBuffer)) != FALSE); ::FindVolumeClose(hVol); if(volumeName.size() == 0) { std::wcout &lt;&lt; "Unable to locate a volume on this device" &lt;&lt; std::endl; return 1; } std::wcout &lt;&lt; "Device: " &lt;&lt; physicalDriveName &lt;&lt; std::endl; std::wcout &lt;&lt; "Volume: " &lt;&lt; volumeName &lt;&lt; std::endl; std::wcout &lt;&lt; "\n\nSuccess! Now create the file!" &lt;&lt; std::endl; // Now let's create a file for fits and giggles std::ofstream output; output.open(volumeName + L"hello.txt"); if(output.fail()) { std::wcout &lt;&lt; "Unable to open output file." &lt;&lt; std::endl; return 1; } output.close(); // Volume will be unmounted when the application closes system("pause"); return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload