全部博文(584)
分类: C/C++
2011-04-12 16:59:57
程序里有自动重启 Windows 系统的功能,当有多个 Windows 共存的时候 C: 根目录下的 boot.ini 文件包含类似下面的内容:
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Professional"
multi(0)disk(0)rdisk(0)partition(2)\WINDOWS="Windows XP Professional" /fastdetect
我们会判断当前系统所在的驱动器,然后改写 boot.ini 中的 default 值,以使得程序重启系统后进入当前启动的操作系统。例如在拥有以上 boot.ini 的系统上,用户手工从操作系统列表选择了启动处于 partition(2) 上的 Windows XP ,如果我们不作任何修改的重启系统,那么重启以后将进入当前的缺省操作系统 Windows 2000 而不是先前启动的 Windows XP。 GetSystemDirectory() 可以获得当前操作系统所在目录。
开始我们想当然的将盘符和分区作了以下映射
C: -> partition(1)
D: -> partition(2)
E: -> partition(3)
.......
后来这里被 Report 了一个 Bug, 在 Dell 600m 笔记本电脑上, 单一操作系统, 我们的程序无法正常重启系统。检查后发现这个型号的笔记本电脑有一个隐藏分区,而 C: 则是 partition(2)。我们必须寻找一个途径将驱动器号转换成分区号。
查阅 MSDN 后得知标准 Win32 API 的解决方法, 简单范例:
#include
#include
#include
#include
#include <iostream.h>
// Required to ensure correct PhysicalDrive IOCTL structure setup
#pragma pack(1)
int main(int argc, char** argv)
{
HANDLE hDrv = CreateFile("\\\\.\\C:",
GENERIC_READ, // Read only to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL);
if(!hDrv)
{
cout << "Error Can not open the Driver " << GetLastError();
return 0;
}
PARTITION_INFORMATION pinfo;
DWORD lpBytesReturned;
BOOL bSuccess = DeviceIoControl(
(HANDLE) hDrv, // handle to a partition
IOCTL_DISK_GET_PARTITION_INFO, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID) &pinfo, // output buffer
(DWORD) sizeof(pinfo), // size of output buffer
(LPDWORD) &lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) NULL // OVERLAPPED structure
);
CloseHandle(hDrv);
if(!bSuccess)
{
cout << "ERROR " << GetLastError();
return 0;
}
cout << pinfo.PartitionNumber;
return 1;
}