最近在做项目的时候遇到了一个头疼的问题,因为程序要在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; 
}

这样我们在判断需要解除重定向的时候再去解除。