程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 寫一個Windows上的守護進程(5)文件系統重定向,守護進程重定向

寫一個Windows上的守護進程(5)文件系統重定向,守護進程重定向

編輯:C++入門知識

寫一個Windows上的守護進程(5)文件系統重定向,守護進程重定向


寫一個Windows上的守護進程(5)文件系統重定向

在Windows上經常操作文件或注冊表的同學可能知道,有“文件系統/注冊表重定向”這麼一回事。大致來說就是32位程序在64位的Windows上運行時,操作系統會把對System32文件夾的訪問重定向到SysWow64下,把對HKEY_LOCAL_MACHINE\SOFTWARE的訪問重定向到HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node下。當然不止這些路徑和注冊表。詳情請查看MSDN:https://msdn.microsoft.com/en-us/library/aa384187.aspx 和https://msdn.microsoft.com/en-us/library/aa384232(v=vs.85).aspx 。

我們通常為了方便發布,都只會編譯一份32位的程序,不會編譯64的程序。如果代碼中涉及到了訪問文件和注冊表,那就要考慮這個問題了。

Windows提供了兩個API(准確的說是3個,但其中一個已不推薦使用了)來禁用文件系統/注冊表重定向:Wow64DisableWow64FsRedirection,Wow64RevertWow64FsRedirection。顧名思義,前者用於禁用,後者用於恢復。

有的同學可能就說了:我一直禁用就行了,干嘛還要恢復?這你就想少了,有的代碼段可能並不關心是否有重定向,所以並沒有考慮這個問題,假若這個代碼段的結果會影響多個線程,而你剛好又把包含這個代碼段的某一線程的重定向禁用了,那就成了有的線程禁用了重定向,有的線程沒有禁用,獲取的結果就不一致了。

一般我們在會有重定向問題的函數調用前禁用重定向,調用完畢後,恢復重定向。這很容易讓人想到使用RAII手法:在類構造函數中禁用,析構函數中恢復:

class scoped_disable_wow64_fsredirection : public boost::noncopyable
{
public:
    scoped_disable_wow64_fsredirection();

    ~scoped_disable_wow64_fsredirection();

private:
    static bool disable(void **ppOldValue);
    static bool revert(void *pOldValue);

private:
    void *_pOldValue;
};

構造函數的實現中調用了disable,析構函數的實現中調用了revert。

其中disable就是調用了Wow64DisableWow64FsRedirection,revert就是調用了Wow64RevertWow64FsRedirection。

注:類名字這麼長是為了能夠達到“顧名思義”的程度。還沒想到什麼更好的名字。哎,起名真是個頭疼的事。

但是我們不能直接調用這兩個Windows API,為什麼呢?

static boost::once_flag once_; typedef int (__stdcall *fnWow64DisableWow64FsRedirection)(void *); typedef int (__stdcall *fnWow64RevertWow64FsRedirection)(void *); static fnWow64DisableWow64FsRedirection g_fnWow64DisableWow64FsRedirection = NULL; static fnWow64RevertWow64FsRedirection g_fnWow64RevertWow64FsRedirection = NULL; static void load_wow64_funcs() { g_fnWow64DisableWow64FsRedirection = reinterpret_cast<fnWow64DisableWow64FsRedirection> (WindowsUtil::load_function("Kernel32.dll", "Wow64DisableWow64FsRedirection")); g_fnWow64RevertWow64FsRedirection = reinterpret_cast<fnWow64RevertWow64FsRedirection> (WindowsUtil::load_function("Kernel32.dll", "Wow64RevertWow64FsRedirection")); } scoped_disable_wow64_fsredirection::scoped_disable_wow64_fsredirection() : _pOldValue(NULL) { boost::call_once(once_, load_wow64_funcs); disable(&_pOldValue); } scoped_disable_wow64_fsredirection::~scoped_disable_wow64_fsredirection() { revert(_pOldValue); } bool scoped_disable_wow64_fsredirection::disable(void **ppOldValue) { bool ret = true; if (g_fnWow64DisableWow64FsRedirection) { if (!g_fnWow64DisableWow64FsRedirection(ppOldValue)) { ErrorLogLastErr("Wow64DisableWow64FsRedirection fail"); ret = false; } } return ret; } bool scoped_disable_wow64_fsredirection::revert(void *pOldValue) { bool ret = true; if (g_fnWow64RevertWow64FsRedirection) { if (!g_fnWow64RevertWow64FsRedirection(pOldValue)) { ErrorLogLastErr("Wow64RevertWow64FsRedirection fail"); ret = false; } } return ret; }

這裡用了前面文章講到的call_once去加載這兩個函數。

load_function封裝了GetModuleHandleA- GetProcAddress兩個函數的調用,詳情請參看源碼。

 

使用時,僅需定義一個類實例就可以了。切記,要盡量縮小作用域,以免影響其他代碼段。

 

源碼:https://git.oschina.net/mkdym/DaemonSvc.git (主)&& https://github.com/mkdym/DaemonSvc.git (提升逼格用的)。

 

2015年11月1日星期日

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved