不显示对话框格式化磁盘的方法

我们都知道格式化磁盘会弹出如下图所示的这样的一个对话框。

20140316210304

编写格式化磁盘的程序的时候,我们需要用到SHFormatDrive这个API,同样的,他也会弹出一个对话框。出现对话框当然是为了安全考虑,防止磁盘被用户不知情的情况下格式化,导致数据丢失。但是,某些情况下,确实希望静默的去格式化,而不去打扰用户,例如格式化Ramdisk。那么就需要找点一个办法要求不弹出对话框的格式化磁盘。既然Windows并没有提供这样的API,那我们只能深入分析下调用过程,找出可以使用的API。

怎么找的就不想说了,无非用ProcMon看一下堆栈就清楚明白了。在fmifs.dll中有一些导出的API可以帮助完成这一的任务,比如FormatEx,FormatEx2。

这里简单的描述下FormatEx的用法:
函数原型是

1
2
3
4
5
6
7
8
9
10
VOID WINAPI FormatEx(
LPCWSTR DriveRoot,
MEDIA_TYPE MediaType,
LPCWSTR FileSystemTypeName,
LPCWSTR Label,
BOOL QuickFormat,
ULONG ClusterSize,
FILE_SYSTEM_CALLBACK Callback
);

参数
DriveRoot —— 盘符,如”K:\”
MediaType —— 磁盘类型,如FixedMedia
FileSystemTypeName —— 要格式化的文件系统,如”NTFS”
Label —— 标签,随便写吧
QuickFormat —— 快速格式化
ClusterSize —— 簇大小
Callback —— 状态回调函数

回调函数原型

1
2
3
4
5
6
typedef BOOLEAN (__stdcall *FILE_SYSTEM_CALLBACK)(
ULONG Command,
ULONG Action,
PVOID pData
);

Command 表示Action和pData的意义,比如Command = 0表示pData是进度,Command = 11表示完成。还有其他的状态,例如错误等等,这些google一下就知道了。这个函数返回TRUE表示函数继续运行,FALSE表示停止格式化。

比如,下面是格式化K盘:

1
2
FormatEx(L"K:\", FixedMedia, L"NTFS", L"0CCh", TRUE, 4096, FormatExCallback);

Tips

一个有意思的warning —— C4930

C4930是微软的C++编译器提示的一个警告,在维基百科中,把造成这种警告的语句描述成最让人为难的解析的语句。那么这里我们看看到底是有多么为难,这个可以帮助我们进一步了解C++和编译器。

那么首先,我最开始发现这个问题是在类似这样的代码中碰到的。

1
2
3
std::ifstream s("d:\\xxx.txt");
std::string str(std::istream_iterator<char>(s), std::istream_iterator<char>());

如果编译这个,编译器会毫不留情地扔给你一个C4930警告,提示编译器不知道怎么做,所以跳过编译。如果你没看懂这警告,后果就是这句话根本不会编译进去,即使编译通过了,运行也会和设想的不同。

先说个简单的C4930的例子吧。

1
2
MyClass sample();

这句代码非常简单,也很容易明白。如果这么写,那么编译器就混乱,因为这句话可以是描述:
1.一个变量的定义,调用默认构造。
2.一个函数的声明。
所以编译器就傻了,他把这个认为是函数声明,所以不会做任何事情。
同样的事情发生在

1
2
std::string str(std::istream_iterator<char>(s), std::istream_iterator<char>());

这里,我们实际上就是给string的构造函数传入iterator来构造这个string。但是编译器可不是这么觉得,他认为这句话应该这样解析:一个返回string的函数,函数名为str,函数参数有两个并且类型相同,都是istream_iterator,不同的是一个有参数名s,一个省略了参数名!

编译器这么解析,也真没错,我们就只能通过修改代码来明确目的了。通常的做法是给第一个iterator外加上括
号:

1
2
std::string str((std::istream_iterator<char>(s)), std::istream_iterator<char>());

不过,我写这两行代码也就是为了偷懒读取一个文件的字符串,所以我可以干脆改成一行:

1
2
std::string str(std::istream_iterator<char>(std::ifstream("d:\\xxx.txt")), std::istream_iterator<char>());

这样就能顺利编译运行了。

最近在看新版的《The C++ Standard Library A Tutorial and Reference》里面也看到了这个东西,很有意思所
以拿出来说下。而且新版的书中,已经包含了C++11的解释,很有意思。

Tips