最近在做项目的时候遇到了一个头疼的问题,因为程序要在64位的PE环境下运行,但是我们的程序是32位的程序,那么问题就来了,因为我要使用diskpart来操作磁盘,于是我就用system("diskpart /s script.txt"),结果屏幕一闪而过,发现脚本里的内容并没有执行,我擦嘞,这啥情况,于是我换ShellExecute/ShellExecuteEx,WinExec,CreateProcess,发现都不行,但是使用cmd程序直接使用diskpart /s script.txt 却是ok的,这是毛情况。
于是我写了一个bat批处理文件,里面写了
diskpart /s script.txt
pause
然后执行这个批处理文件,发现了问题,diskpart不是内部或外部命令,也不是一个程序。
我擦嘞,这不科学啊,我直接用cmd执行diskpart是ok的啊?
这时我想起来周会上主管说的一句话,由于执行程序的用户不同,每个用户所能看到的文件也是不一样的,会不会是因为用户不一样导致的呢?
于是我修改程序用程序调起了一个cmd窗口,自己再打开一个cmd窗口,发现用户相同,但是不同的是程序起来的cmd后面有 *32,这个或许就是问题所在了吧?
于是我右击进程查看属性,发现两个cmd分别是 system32 和 sysWOW64目录下面的cmd文件。
于是我到sysWOW64文件夹里面去找diskpart.exe文件,果真没找到,原来是在制作PE的时候没有把32位的diskpart加进去,因为diskpart执行需要其他文件和服务配合,简单的拷贝32位的diskpart进来也是不可行的,于是我就直接运行system32位的diskpart.exe不就行了吗?
我兴冲冲的去改程序了。
ShellExecuteEx需要的结构体文件名称属性改成"x:\\windows\\system32\\diskpart.exe"不就ok了吗?
执行,我擦嘞,又是一闪而过,看看结果,脚本里的代码还是没有执行。
真特码 你伤害了我,却"一闪而过”。
于是我使用同样的方式调用了一下cmd,发现cmd竟然是sysWOW64位下面的,我明明指定了路径的啊,怎么会走错道了呢?
百度一瞅,发现了问题,原来有个词叫重定向,64位系统下面,如果你的程序是32位的,那么系统会把 system32这个目录重定向到sysWOW64下面,这样无论你怎么搞,你起来的程序肯定是sysWOW64下面的程序,怪不得之前执行不了diskpart呢?
那咋办呢?
百度继续。。。
恩,找到了,微软老爷子给了一个接口可以临时解除重定向,木有错,是他,是他,就是他:
Wow64DisableWow64FsRedirection(PVOID *OldValue);
同时老爷子也说了,Wow64RevertWow64FsRedirection(PVOID OldValue) 这个函数和他是青梅竹马,一定要一起使用,这就是我为什么说临时解除,你丫用过不给人恢复,出来问题你负责啊。
下面贴一下使用方法(msdn上面的)
#define _WIN32_WINNT 0x0501
#include <windows.h>
PVOID OldValue;
HANDLE hFile;
BOOL bRet = Wow64DisableWow64FsRedirection (&OldValue);
if (bRet == TRUE)
{
// Open a file
hFile = CreateFile(TEXT("c:\\windows\\system32\\notepad.exe"),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Restore the previous WOW64 file system redirection value.
Wow64RevertWow64FsRedirection (OldValue);
}
if( INVALID_HANDLE_VALUE != hFile )
{
// Use the file handle
}
我们在使用时最好加一个64位判断(只针对32的程序,64位程序是无法再32位系统上运行的)
//true 表示是64位操作系统,false表示不是(只针对32位程序)
BOOL IsWow64()
{
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL bIsWow64 = FALSE;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle(_T("kernel32")), "IsWow64Process");
if (NULL != fnIsWow64Process)
{
fnIsWow64Process(GetCurrentProcess(),&bIsWow64);
}
return bIsWow64;
}
这样我们在判断需要解除重定向的时候再去解除。