• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-90  評(píng)論-947  文章-0  trackbacks-0
             

            目錄:

            2009-2010小結(jié)(一)畢業(yè)前夕
            2009-2010小結(jié)(二)初入職場(chǎng)
            2009-2010小結(jié)(三)加班考驗(yàn)
            2009-2010小結(jié)(四)抑郁重重
            2009-2010小結(jié)(五)離職始末

            前一陣子看到好些人都發(fā)小結(jié)了,長(zhǎng)的有10年的,短的有1年的,洋洋灑灑,淋漓盡致,各顯神通,看得好不暢快,其中也不乏值得回味的、讓人深思的東西。哥覺得哥不是那樣子牛逼的人,所以就不湊那個(gè)熱鬧了^_^ 不過,總結(jié)還是要的,有總結(jié)才有進(jìn)步,在這個(gè)尋常的夜晚,哥來(lái)個(gè)遲到的總結(jié)。

            就從找工作說起吧。2008年秋季,對(duì)應(yīng)的是我的應(yīng)屆生招聘的時(shí)期。9月底,各大IT公司就紛紛來(lái)開宣講會(huì)了。最開始的是淘寶,可是那時(shí)候哥還沉浸在開學(xué)的喜悅中,完全不知道,錯(cuò)過了。然后才開始誠(chéng)惶誠(chéng)恐地收集這些信息。接下來(lái)支付寶啊,百度啊,騰訊啊,阿里阿,網(wǎng)易啊,接踵而至,一直持續(xù)到10月底才告一段落。遺憾的是,哥是個(gè)菜逼+傻逼,基本上都是在一面或者更早掛掉。分享幾個(gè)事例證明我的傻逼:

            1、去支付寶面試的路上,接到個(gè)電話,趕緊問:是支付寶嗎?對(duì)方回答,我是百度的。沒聽清,繼續(xù)問:是支付寶嗎?答:是百度……
            2、有個(gè)測(cè)試崗位,面試官問:你對(duì)測(cè)試有什么了解?很自信地回答:基本上沒什么了解。

            一線公司就這樣全部錯(cuò)過了。現(xiàn)在還保留的一些記憶是,百度的面試官很耐心,但老是問些聽也沒聽過的破算法;騰訊的面試官說話語(yǔ)速很快,面試也很快,大概10幾分鐘搞定,也不知道說錯(cuò)什么了導(dǎo)致被這么快否定,哥稱之為“閃電面”;阿里的那期試卷出得相當(dāng)爛,很多題目重復(fù),還不止一次,還是錯(cuò)的,直接做不下去,一定要狠狠鄙視。

            10月中以后,大大小小的聽過沒聽過的公司基本上都來(lái)了。也去過幾場(chǎng)現(xiàn)場(chǎng)招聘的,發(fā)放了一些簡(jiǎn)歷。其中有一個(gè)公司比較叼,忘了叫什么名字的。到攤位上問,你們是做哪方面的?結(jié)果那人說:你坐下來(lái)自我介紹一下。繼續(xù)問:你們做哪方面的我都不知道,我怎么知道適不適合啊?那人語(yǔ)重心長(zhǎng)的說,你一個(gè)勁地問做什么的,無(wú)非是技術(shù)啊業(yè)務(wù)啊,這些有那么重要么?你就沒有信心介紹一下自己么?直接無(wú)語(yǔ),站起來(lái)走人。同行的一同學(xué)覺得這個(gè)方式對(duì)口,就去自我介紹了。

            還面了2家小公司,一個(gè)是在百腦匯附近的,可能跟金融有點(diǎn)關(guān)系。招聘會(huì)上我已經(jīng)注意到了那個(gè)人,特別認(rèn)真,說話也比較中肯,后來(lái)面試也是那個(gè)人。筆試的試卷比較靠譜,做得很順利。當(dāng)然不是說我做得順利才說它靠譜,這點(diǎn)客觀性哥還是有的。他們很看重?cái)?shù)學(xué)的樣子,可能覺得我數(shù)學(xué)系出身,應(yīng)該可以吧。所以面試的時(shí)候叫了個(gè)數(shù)學(xué)系的人來(lái)面我數(shù)學(xué),問一些求導(dǎo)啊,概率啊之類的,暈死。分析方面的淺顯問題,還算馬馬虎虎能搞定,其他的就。。。后來(lái)我直接說,不要問我概率啊統(tǒng)計(jì)啊,數(shù)理統(tǒng)計(jì)我可是考了50分的。那哥們不好意思的走了。他們還要看成績(jī)單!哥給他一份真實(shí)的成績(jī)單,讓他直接苦笑數(shù)聲!曬下當(dāng)年的成績(jī)吧:

            成績(jī)單

            最后的結(jié)果是備胎,他們要等前面的人回應(yīng)。不過他們這么看重成績(jī)單以及數(shù)學(xué),讓哥當(dāng)時(shí)也想好了,總之哥沖著編程去的,不是沖著金融去的。

            另外一家,就是后來(lái)給了我第一份工作的那一家。面試在玉泉附近的百合花酒店。說實(shí)話,這次是我那一陣子最舒心的一次面試,好歹也看我簡(jiǎn)歷上寫了什么,也算是問了些簡(jiǎn)歷上涉及的東西。早上一面,當(dāng)天下午二面。之前我還沒有經(jīng)歷過二面,于是打電話給HR姐姐問二面面的是技術(shù)還是談別的,被告知面技術(shù)。結(jié)果被談人生談理想了。其中他說公司主要業(yè)務(wù)應(yīng)該算是做Linix的,如果讓你做Linux,有什么想法?我回想了一下,前不久我好像問過百度GG類似的問題(大概說我擔(dān)心Linux經(jīng)驗(yàn)不足會(huì)影響工作blabla),于是就把他的回答有一句沒一句的給復(fù)述了一遍。結(jié)尾比較尷尬,對(duì)方一個(gè)勁的問還有問題沒,我想來(lái)想去前前后后想了解的都問完了,這可怎么辦,正在這時(shí),外面催了一下,于是看了看表,說,下面還有好幾個(gè)人吧,我就問到這里吧。。。逃離。。。

            到此為止一個(gè)offer也沒拿到,著手準(zhǔn)備考研了。分析了一下,政治是靠覺悟的,背書沒用;英語(yǔ)是靠人品的,背單詞我才不干;數(shù)學(xué)考的應(yīng)該沒平時(shí)學(xué)的深,難度上問題不大,可是那些很實(shí)用的計(jì)算技巧數(shù)學(xué)系的人反而是一無(wú)所知的,需要復(fù)習(xí);計(jì)算機(jī)是人家的專業(yè)課我的業(yè)余課,除了C/C++/數(shù)據(jù)結(jié)構(gòu),其他的也要復(fù)習(xí)。于是準(zhǔn)備了數(shù)學(xué)和計(jì)算機(jī)的參考書,準(zhǔn)備好好復(fù)習(xí)。第一天,呆圖書館整天,不錯(cuò);第二天,堅(jiān)持;第三天;繼續(xù)堅(jiān)持。第四天,外出有點(diǎn)事,結(jié)果接到了電話,是那家公司給了offer。這下哥可是欣喜若狂啊,馬上打電話向室友啊誰(shuí)啊宣布。手拿一把offer的牛人請(qǐng)不要笑,我等從未見過offer的土人,當(dāng)時(shí)就是很興奮的,很歇斯底里的,很神經(jīng)質(zhì)的。。。

            找工作真是太累了,這邊跑那邊跑,找信息,琢磨簡(jiǎn)歷,還要等待。。。真是讓人心力憔悴。于是決定告一段落,不要找工作了,三方神馬的全部簽了。至于考研?那當(dāng)然要考的,錢都交了。復(fù)習(xí)?算了吧。。彪悍的考生是不需要復(fù)習(xí)的。

            那個(gè)寒假過的還是蠻舒心的,后事已定,無(wú)憂無(wú)慮。只是HR打了一次電話,問什么時(shí)候能去實(shí)習(xí)。新學(xué)期開始,又打了一次電話。真是的,本來(lái)就說好3月份的,還差大半個(gè)月,急什么呢。我為我畢設(shè)的選擇感到驕傲,那可是數(shù)學(xué)系帶畢設(shè)的老師中唯一一個(gè)做計(jì)算機(jī)相關(guān)的啊!我們要做的是使用ASP.Net做一個(gè)學(xué)術(shù)會(huì)議管理系統(tǒng)。在畢設(shè)之前,我就咨詢了下帶課導(dǎo)師,把之前寫的ASP的、ASP.Net的破系統(tǒng)發(fā)給他鑒定,所以在畢設(shè)團(tuán)隊(duì)的地位哥還是蠻高的。有一件比較為難的事情是,倒數(shù)第二學(xué)期的小畢設(shè),每個(gè)人都要上臺(tái)講課的,有個(gè)同學(xué),還是我隔壁寢室的哥們,是后來(lái)選的,老師不知道講給他安排什么主題了,最后讓他講下我之前發(fā)給他的一個(gè)博客系統(tǒng)。這。。。害得我好幾次小心翼翼的問老師,這可以么?真的可以么?

            我把租房、搬東西這類事情都搞定后,3月2日正式去實(shí)習(xí)了。(天色已暗,欲知后事如何,且聽下回分解。)

            posted @ 2011-01-16 00:42 溪流 閱讀(2154) | 評(píng)論 (7)編輯 收藏

            前言:
            DLL 是個(gè)很久遠(yuǎn)的文件格式,以至于它只支持導(dǎo)出函數(shù)(請(qǐng)忽略 .net 的 DLL)。至于導(dǎo)出 class,也是由于編譯系統(tǒng)的支持才勉勉強(qiáng)強(qiáng)能進(jìn)行,只能靜態(tài)加載,實(shí)際上對(duì)于DLL文件來(lái)說它導(dǎo)出的還是函數(shù)。——以上,個(gè)人的一點(diǎn)淺顯理解。

            問題:
            有沒有存在一種好的方式,讓DLL能夠被動(dòng)態(tài)加載,并且能夠方便地得到里面的 C++ class 信息?
            備選:
            1、別想了,老老實(shí)實(shí)地用吧,還是導(dǎo)出純C函數(shù)= =
            2、大膽的導(dǎo)出 class 吧,如果動(dòng)態(tài)加載,自己去拼那些編譯后名字吧。。
            3、COM 形式?可是,要注冊(cè)到系統(tǒng)中去,憑空多了系統(tǒng)注冊(cè)表依賴
            4、還有嗎?
            5、甚至可以拋開DLL,有沒有類似的一種方式,可用于二進(jìn)制代碼的模塊劃分以及閉源的代碼重用?

            (至于跨平臺(tái)啥的先不考慮吧,暫定Windows平臺(tái)下吧)

            請(qǐng)不吝指教~

            posted @ 2010-12-18 22:35 溪流 閱讀(2265) | 評(píng)論 (15)編輯 收藏

            首先,寫這玩意兒的目的有

            1. 看到 MetaWeblog API,覺得蠻有趣,想玩玩看;
            2. 用下之前寫的 xl::Array、xl::List、xl::Map、xl::String、xl::QIPtr,以檢驗(yàn)可靠性;
            3. 曬曬去年這個(gè)時(shí)候?qū)懙?XmlParser,這個(gè)很久的將來(lái)肯定重寫過的然后才能進(jìn) xlLib,這個(gè)版本只是拿來(lái)玩玩的;
            4. 熟悉下 WinHttp API,WinINet 時(shí)不時(shí)冒出個(gè) bug,揪心;(這個(gè)……其實(shí)一開始想用socket寫然后同時(shí)支持linux的,可是想著想著突然記起件事情,linux上界面我不會(huì)寫啊,所以。。跨毛平臺(tái)啊)
            5. 某同事在 CSDN 寫博客,一會(huì)兒說“我自己寫自己的,不要?jiǎng)e人看”,一會(huì)兒卻又抱怨沒人看不好玩,我說來(lái)吧搬到CppBlog吧這兒很熱鬧很好玩~!嗯,先把工具準(zhǔn)備好,接下來(lái)可以天天曉之以理動(dòng)之以情。

            由于 google code 上已經(jīng)有一個(gè)玩意兒叫 Blog Mover 了,所以我只好起個(gè)很繞口的名字 Blog Transporter 了,簡(jiǎn)稱 BlogTrans。

            源代碼:http://blogtrans.codeplex.com/
            下載:http://blogtrans.codeplex.com/releases/54948/download/162649

            功能有:抓下最近的 N 篇博文,包括圖片,轉(zhuǎn)發(fā)到新的位置。兩個(gè)博客都要求支持 MetaWeblog API。

            嗯,開始用了~~假設(shè)我要把我的 cppblog 里的頭 5 篇文章轉(zhuǎn)到 csdn 上去。先填好兩邊的賬號(hào)信息:

            image

            中間填個(gè)數(shù)字,表示要抓幾篇。。。只能從最新的往下數(shù)多少篇。。然后那個(gè)勾勾表示是否要抓下圖片傳到目標(biāo)博客上。好,按下 Start!

            image

            然后就開始了,等啊等,就好了。于是,現(xiàn)在我的 CSDN 博客就有了 5 篇文章,大家可以看下效果:http://blog.csdn.net/xixiaoliu
            格式神馬的,應(yīng)該都還在吧。。。就是有一個(gè)不好,Windows Live Writer 發(fā)的圖片,他會(huì)在圖片上再加個(gè)鏈接鏈到自己,我目前沒有去分析這個(gè)鏈接。

            每篇博客之間我設(shè)置了 5 秒間隔,這是有原因的。。剛才,我測(cè)試的時(shí)候把 CppBlog 上的 37 篇全搞到 CSDN 上去,一刻不停地搞。。。結(jié)果發(fā)了 33 篇,后面 4 篇全出錯(cuò)。。。用瀏覽器訪問,403 forbidden。。。果斷重啟路由器,才重新打開。。。

            好啦,廣告完畢!大家多吐口水多幫忙找bug,然后把親朋好友都拉到 CppBlog 來(lái)打架吧~~~!

            順便,360快點(diǎn)推出安全聊天吧,周教主果然眼光犀利打遍全網(wǎng)無(wú)敵手啊~

            posted @ 2010-10-30 01:57 溪流 閱讀(1734) | 評(píng)論 (4)編輯 收藏

            由于 C++ 成員函數(shù)的調(diào)用機(jī)制問題,對(duì)C語(yǔ)言回調(diào)函數(shù)的 C++ 封裝是件比較棘手的事。為了保持C++對(duì)象的獨(dú)立性,理想情況是將回調(diào)函數(shù)設(shè)置到成員函數(shù),而一般的回調(diào)函數(shù)格式通常是普通的C函數(shù),尤其是 Windows API 中的。好在有些回調(diào)函數(shù)中留出了一個(gè)額外參數(shù),這樣便可以由這個(gè)通道將 this 指針傳入。比如線程函數(shù)的定義為:

            typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
                LPVOID lpThreadParameter
                );
            typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;

            這樣,當(dāng)我們實(shí)現(xiàn)線程類的時(shí)候,就可以:

            class Thread
            {
            private:
                HANDLE m_hThread;

            public:
                BOOL Create()
                {
                    m_hThread = CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, NULL);
                    return m_hThread != NULL;
                }

            private:
                DWORD WINAPI ThreadProc()
                {
                    // TODO
                    return 0;
                }

            private:
                static DWORD WINAPI StaticThreadProc(LPVOID lpThreadParameter)
                {
                    ((Thread *)lpThreadParameter)->ThreadProc();
                }
            };

            不過,這樣,成員函數(shù) ThreadProc() 便喪失了一個(gè)參數(shù),這通常無(wú)傷大雅,任何原本需要從參數(shù)傳入的信息都可以作為成員變量讓 ThreadProc 來(lái)讀寫。如果一定有些什么是非從參數(shù)傳入不可的,那也可以,一種做法,創(chuàng)建線程的時(shí)候傳入一個(gè)包含 this 指針信息的結(jié)構(gòu)。第二種做法,對(duì)該 class 作單例限制——如果現(xiàn)實(shí)情況允許的話。

            所以,有額外參數(shù)的回調(diào)函數(shù)都好處理。不幸的是,Windows 的窗口回調(diào)函數(shù)沒有這樣一個(gè)額外參數(shù):

            typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

            這使得對(duì)窗口的 C++ 封裝變得困難。為了解決這個(gè)問題,一個(gè)很自然的想法是,維護(hù)一份全局的窗口句柄到窗口類的對(duì)應(yīng)關(guān)系,如:

            #include <map>

            class Window
            {
            public:
                Window();
                ~Window();
               
            public:
                BOOL Create();

            protected:
                LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);

            protected:
                HWND m_hWnd;

            protected:
                static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
                static std::map<HWND, Window *> m_sWindows;
            };

            在 Create 的時(shí)候,指定 StaticWndProc 為窗口回調(diào)函數(shù),并將 hWnd 與 this 存入 m_sWindows:

            BOOL Window::Create()
            {
                LPCTSTR lpszClassName = _T("ClassName");
                HINSTANCE hInstance = GetModuleHandle(NULL);

                WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };
                wcex.lpfnWndProc   = StaticWndProc;
                wcex.hInstance     = hInstance;
                wcex.lpszClassName = lpszClassName;

                RegisterClassEx(&wcex);

                m_hWnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

                if (m_hWnd == NULL)
                {
                    return FALSE;
                }

                m_sWindows.insert(std::make_pair(m_hWnd, this));

                ShowWindow(m_hWnd, SW_SHOW);
                UpdateWindow(m_hWnd);

                return TRUE;
            }

            在 StaticWindowProc 中,由 hWnd 找到 this,然后轉(zhuǎn)發(fā)給成員函數(shù):

            LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                std::map<HWND, Window *>::iterator it = m_sWindows.find(hWnd);
                assert(it != m_sWindows.end() && it->second != NULL);

                return it->second->WndProc(message, wParam, lParam);
            }

            (m_sWindows 的多線程保護(hù)略過,下同)

            據(jù)說 MFC 采用的就是類似的做法。缺點(diǎn)是,每次 StaticWndProc 都要從 m_sWindows 中去找 this。由于窗口類一般會(huì)保存窗口句柄,回調(diào)函數(shù)里的 hWnd 就沒多大作用了,如果這個(gè) hWnd 能夠被用來(lái)存 this 指針就好了,那么就能寫成這樣:

            LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                return ((Window *)hWnd)->WndProc(message, wParam, lParam);
            }

            這樣看上去就爽多了。傳說中 WTL 所采取的 thunk 技術(shù)就是這么干的。之前,只是聽過這遙遠(yuǎn)的傳說,今天,終于有機(jī)會(huì)走進(jìn)這個(gè)傳說去看一看。參考資料是一篇不知原始出處的文章《深入剖析WTL—WTL框架窗口分析》,以及部分 WTL 8.0 代碼,還有其他亂七八糟的文章。

            WTL 的思路是,每次在系統(tǒng)調(diào)用 WndProc 的時(shí)候,讓它鬼使神差地先走到我們的另一處代碼,讓我們有機(jī)會(huì)修改堆棧中的 hWnd。這處代碼可能是類似這樣的:

            __asm
            {
                mov dword ptr [esp+4], pThis  ;調(diào)用 WndProc 時(shí),堆棧結(jié)構(gòu)為:RetAddr, hWnd, message, wParam, lParam, ... 故 [esp+4]
                jmp WndProc
            }

            由于 pThis 和 WndProc 需要被事先修改(但又無(wú)法在編譯前定好),所以我們需要運(yùn)行的時(shí)候去修改這部分代碼。先弄一個(gè)小程序探測(cè)下這兩行語(yǔ)句的機(jī)器碼:

            LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                return 0;
            }

            int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
            {
                MessageBox(NULL, NULL, NULL, MB_OK);

                __asm
                {
                    mov dword ptr [esp+4], 1
                    jmp WndProc
                }

                return 0;
            }

            最前面的 MessageBox 是為了等下調(diào)試的時(shí)候容易找到進(jìn)入點(diǎn)。

            然后使用 OllyDbg,在 MessageBoxW 上設(shè)置斷點(diǎn),執(zhí)行到該函數(shù)返回:

            image

            這里我們看到,mov dword ptr [esp+4] 的機(jī)器碼為 C7 44 24 04,后面緊接著的一個(gè) DWORD 是 mov 的第二個(gè)操作數(shù)。jmp 的機(jī)器碼是 e9,后面緊接著的一個(gè) DWORD 是跳轉(zhuǎn)的相對(duì)地址。其中 00061000h - 0006102Bh = FFFFFFD5h。

            于是定義這樣一個(gè)結(jié)構(gòu):

            #pragma pack(push,1)
            typedef struct _StdCallThunk
            {
                DWORD   m_mov;          // = 0x042444C7
                DWORD   m_this;         // = this
                BYTE    m_jmp;          // = 0xe9
                DWORD   m_relproc;      // = relative distance
            } StdCallThunk;
            #pragma pack(pop)

            這個(gè)結(jié)構(gòu)可以作為窗口類的成員變量存在。我們的窗口類現(xiàn)在變成了這樣子:

            class Window
            {
            public:
                Window();
                ~Window();

            public:
                BOOL Create();

            protected:
                LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);

            protected:
                HWND         m_hWnd;
                StdCallThunk m_thunk;

            protected:
                static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
            };

            似乎少了點(diǎn)什么……創(chuàng)建窗口的時(shí)候,我們是不能直接把回調(diào)函數(shù)設(shè)到 StaticWndPorc 中去的,因?yàn)檫@個(gè)函數(shù)是希望被寫成這樣子的:

            LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                return ((Window *)hWnd)->WndProc(message, wParam, lParam);
            }

            那么至少需要一個(gè)臨時(shí)的回調(diào)函數(shù),在這個(gè)函數(shù)里去設(shè)置新的回調(diào)函數(shù)(設(shè)到 m_thunk 上),再由 m_thunk 來(lái)調(diào)用 StaticWndProc,StaticWndProc 再去調(diào)用 WndProc,這樣整個(gè)過程就通了。

            但是,臨時(shí)回調(diào)函數(shù)還是需要知道從 hWnd 到 this 的對(duì)應(yīng)關(guān)系。可是現(xiàn)在我們不能照搬用剛才的 m_sWindows 了。因?yàn)榇翱谠趧?chuàng)建過程中就會(huì)調(diào)用到回調(diào)函數(shù),需要使用到 m_sWindows 里的 this,而窗口被成功創(chuàng)建之前,我們沒法提前拿到 HWND 存入 m_sWindows。現(xiàn)在,換個(gè)方法,存當(dāng)前線程 ID 與 this 的對(duì)應(yīng)關(guān)系。這樣,這個(gè)類變成了:

            #include <map>

            class Window
            {
            public:
                Window();
                ~Window();

            public:
                BOOL Create();

            protected:
                LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);

            protected:
                HWND         m_hWnd;
                StdCallThunk m_thunk;

            protected:
                static LRESULT CALLBACK TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

                static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
                static std::map<DWORD, Window *> m_sWindows;
            };

            然后實(shí)現(xiàn) Create 和 TempWndProc:

            BOOL Window::Create()
            {
                LPCTSTR lpszClassName = _T("ClassName");
                HINSTANCE hInstance = GetModuleHandle(NULL);

                WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };
                wcex.lpfnWndProc   = TempWndProc;
                wcex.hInstance     = hInstance;
                wcex.lpszClassName = lpszClassName;

                RegisterClassEx(&wcex);

                DWORD dwThreadId = GetCurrentThreadId();
                m_sWindows.insert(std::make_pair(dwThreadId, this));

                m_thunk.m_mov = 0x042444c7;
                m_thunk.m_jmp = 0xe9;

                m_hWnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

                if (m_hWnd == NULL)
                {
                    return FALSE;
                }
               
                ShowWindow(m_hWnd, SW_SHOW);
                UpdateWindow(m_hWnd);

                return TRUE;
            }

            LRESULT CALLBACK Window::TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                std::map<DWORD, Window *>::iterator it = m_sWindows.find(GetCurrentThreadId());
                assert(it != m_sWindows.end() && it->second != NULL);

                Window *pThis = it->second;
                m_sWindows.erase(it);

                WNDPROC pWndProc = (WNDPROC)&pThis->m_thunk;

                pThis->m_thunk.m_this = (DWORD)pThis;
                pThis->m_thunk.m_relproc = (DWORD)&Window::StaticWndProc - ((DWORD)&pThis->m_thunk + sizeof(StdCallThunk));

                m_hWnd = hWnd;
                SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pWndProc);

                return pWndProc(hWnd, message, wParam, lParam);
            }

            差不多可以了,調(diào)試一下。結(jié)果,在 thunk 的第一行出錯(cuò)了。我原以為地址算錯(cuò)了神馬的,嘗試把 thunk.m_mov 改為 0x90909090,再運(yùn)行,還是出錯(cuò)。于是傻掉了……過了好一會(huì)兒才意識(shí)到,可能是因?yàn)?thunk 在數(shù)據(jù)段,無(wú)法被執(zhí)行。可是,很久很久以前偶滴一個(gè)敬愛的老師在 TC 中鼓搗程序運(yùn)行時(shí)改變自身代碼時(shí),貌似無(wú)此問題啊。。。然后查呀查,原來(lái)是 Windows 在的數(shù)據(jù)執(zhí)行保護(hù)搞的鬼。于是,需要用 VirtualAlloc 來(lái)申請(qǐng)一段有執(zhí)行權(quán)限的內(nèi)存。WTL 里面也是這么做的,不過它似乎維護(hù)了一塊較大的可執(zhí)行內(nèi)存區(qū)作為 thunk 內(nèi)存池,我們這里從簡(jiǎn)。最后,整個(gè)流程終于跑通了。最終代碼清單如下:

            #include <Windows.h>
            #include <assert.h>
            #include <map>
            #include <tchar.h>

            #pragma pack(push,1)
            typedef struct _StdCallThunk
            {
                DWORD   m_mov;
                DWORD   m_this;
                BYTE    m_jmp;
                DWORD   m_relproc;

            } StdCallThunk;
            #pragma pack(pop)

            class Window
            {
            public:
                Window();
                ~Window();

            public:
                BOOL Create();

            protected:
                LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);

            protected:
                HWND          m_hWnd;
                StdCallThunk *m_pThunk;

            protected:
                static LRESULT CALLBACK TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
                static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
                static std::map<DWORD, Window *> m_sWindows;
            };

            std::map<DWORD, Window *> Window::m_sWindows;

            Window::Window()
            {

            }

            Window::~Window()
            {
                VirtualFree(m_pThunk, sizeof(StdCallThunk), MEM_RELEASE);
            }

            BOOL Window::Create()
            {
                LPCTSTR lpszClassName = _T("ClassName");
                HINSTANCE hInstance = GetModuleHandle(NULL);

                WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };
                wcex.lpfnWndProc   = TempWndProc;
                wcex.hInstance     = hInstance;
                wcex.lpszClassName = lpszClassName;
                wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

                RegisterClassEx(&wcex);

                DWORD dwThreadId = GetCurrentThreadId();
                m_sWindows.insert(std::make_pair(dwThreadId, this));

                m_pThunk = (StdCallThunk *)VirtualAlloc(NULL, sizeof(StdCallThunk), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                m_pThunk->m_mov = 0x042444c7;
                m_pThunk->m_jmp = 0xe9;

                m_hWnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

                if (m_hWnd == NULL)
                {
                    return FALSE;
                }
               
                ShowWindow(m_hWnd, SW_SHOW);
                UpdateWindow(m_hWnd);

                return TRUE;
            }

            LRESULT Window::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
            {
                switch (message)
                {
                case WM_LBUTTONUP:
                    MessageBox(m_hWnd, _T("LButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);
                    break;
                case WM_RBUTTONUP:
                    MessageBox(m_hWnd, _T("RButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);
                    break;
                case WM_DESTROY:
                    PostQuitMessage(0);
                    break;
                default:
                    break;
                }

                return DefWindowProc(m_hWnd, message, wParam, lParam);
            }

            LRESULT CALLBACK Window::TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                std::map<DWORD, Window *>::iterator it = m_sWindows.find(GetCurrentThreadId());
                assert(it != m_sWindows.end() && it->second != NULL);

                Window *pThis = it->second;
                m_sWindows.erase(it);

                WNDPROC pWndProc = (WNDPROC)pThis->m_pThunk;

                pThis->m_pThunk->m_this = (DWORD)pThis;
                pThis->m_pThunk->m_relproc = (DWORD)&Window::StaticWndProc - ((DWORD)pThis->m_pThunk + sizeof(StdCallThunk));

                pThis->m_hWnd = hWnd;
                SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pWndProc);

                return pWndProc(hWnd, message, wParam, lParam);
            }

            LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                return ((Window *)hWnd)->WndProc(message, wParam, lParam);
            }

            int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
            {
                Window wnd;
                wnd.Create();

                MSG msg;

                while (GetMessage(&msg, NULL, 0, 0))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }

                return (int)msg.wParam;
            }

            剛才有一處,存 this 指針的時(shí)候,我很武斷地把它與當(dāng)前線程 ID 關(guān)聯(lián)起來(lái)了,其實(shí)這正是 WTL 本身的做法。它用 CAtlWinModule::AddCreateWndData 存的 this,最終會(huì)把當(dāng)前線程 ID 和 this 作關(guān)聯(lián)。我是這么理解的吧,同一線程不可能同時(shí)有兩處在調(diào)用 CreateWindow,所以這樣取回來(lái)的 this 是可靠的。

            好了,到此為止,邊試驗(yàn)邊記錄的,不知道理解是否正確。歡迎指出不當(dāng)之處,也歡迎提出相關(guān)的問題來(lái)考我,歡迎介紹有關(guān)此問題的新方法、新思路,等等,總之,請(qǐng)各位看官多指教哈。

            posted @ 2010-10-24 16:44 溪流 閱讀(6650) | 評(píng)論 (40)編輯 收藏

            我自認(rèn)為一向是很不感冒Linux那些東東的,也不知道為什么,前兩天突然就心血來(lái)潮去搞一番LFS。于是很有紀(jì)念意義,特此記錄。

            起先準(zhǔn)備搞的是 LFS 6.1,因?yàn)橹挥?6.1 有官方中文手冊(cè)。但是我的宿主系統(tǒng)是 Arch Linux 2010.05,也許太新了,剛開始編譯 gcc 4.0.3 就過不了。后來(lái)就放棄了,換 6.7 的玩。

            說到底這是件很無(wú)聊的事情。打過的最多的命令就是
            tar -xzvf ...
            tar -xvjf ...
            ./configure ...
            make
            make install
            rm -rf ...

            這么一套操作重復(fù)個(gè)百來(lái)下,加上無(wú)休止的等待,就成了。

            以為成了,結(jié)果出狀況了:

            失敗

            似乎好像大概可能它找不到硬盤,而且我明明要 sda2 的,它卻找了 sdb2。

            第一,在 8.4.2  grub-mkconfig -o /boot/grub/grub.cfg 的時(shí)候,grub的配置文件是利用它的命令自動(dòng)生成的,結(jié)果它找錯(cuò)了。可能是因?yàn)槲乙婚_始裝的時(shí)候拿塊硬盤是sdb,它就認(rèn)sdb了。或者是之前那條命令 grub-install --grub-setup=/bin/true /dev/sda 我自作聰明地以為它要實(shí)際操作,把最后的sda換成了sdb的緣故吧。

            第二是因?yàn)槲以?VMWare 上跑,虛擬硬盤是 SCSI 的,編譯內(nèi)核之前沒配置對(duì)。后來(lái)看到了 http://www.cnblogs.com/benben7466/archive/2009/04/01/1427404.html,于是把 fusion mpt 中的全選上了(文章中的 Fusion MPT (base + ScsiHost) drivers 我沒找到,于是全選了= =),重新編譯內(nèi)核,啟動(dòng)成功。

            謹(jǐn)以此截圖留念:

            成功

            流水賬結(jié)束了。正文開始。

            我想談?wù)剬?duì) LFS 中的工具鏈切換的理解。請(qǐng)?jiān)试S我把 binutil 和 gcc 簡(jiǎn)稱為編譯系統(tǒng),把 glibc 簡(jiǎn)稱為運(yùn)行庫(kù)。用下面這張圖簡(jiǎn)單表示一下:

            image

            首先,利用宿主系統(tǒng)的編譯系統(tǒng)編譯出一個(gè)依賴于宿主運(yùn)行庫(kù)的新的編譯系統(tǒng)(Pass1),和獨(dú)立的新的運(yùn)行庫(kù)(Pass1)。然后再利用運(yùn)行在宿主運(yùn)行庫(kù)上的新的編譯系統(tǒng)(Pass1)編譯出依賴于新的運(yùn)行庫(kù)(Pass1)的新的編譯系統(tǒng)(Pass2)。這樣,產(chǎn)生了一個(gè)脫離宿主的編譯環(huán)境,利用這個(gè)編譯環(huán)境編譯出其他工具,一起作為臨時(shí)系統(tǒng)使用。

            再在臨時(shí)系統(tǒng)中,編譯出目標(biāo)系統(tǒng)中要用的運(yùn)行庫(kù)(Pass2)和依賴于目標(biāo)運(yùn)行庫(kù)(Pass2)的編譯系統(tǒng)(Pass3)。目標(biāo)系統(tǒng)中的編譯環(huán)境搭建完畢。最后使用這個(gè)編譯環(huán)境編譯出目標(biāo)系統(tǒng)上的其他軟件。

            不知道這個(gè)陳述有沒有問題?如果沒說錯(cuò)的話,問題來(lái)了。其實(shí),得到的臨時(shí)系統(tǒng),已經(jīng)是一個(gè)不依賴于宿主的系統(tǒng)了,何不把這個(gè)作為 LFS 的目標(biāo)系統(tǒng)呢?理由似乎只有“使它更純凈”之類的了。如果追求純凈,多搞一遍是不夠的,還是不純凈的;既然反正不純凈,為啥多做一遍呢?

            由此,我想到了挺久以前我一直壓抑在心里的問題:同一個(gè)環(huán)境下的編譯器的升級(jí)問題。加入已經(jīng)有了 1.0 版的編譯器執(zhí)行文件和 2.0 版的編譯器源代碼,要如何產(chǎn)生 2.0 版的編譯器的執(zhí)行文件呢?是拿 1.0 版的去編譯 2.0 的源代碼,然后直接發(fā)布?還是再用新的 2.0 版的編譯器再編譯一遍(兩遍、三遍)?6.1 版的 LFS 手冊(cè)部分解決了這個(gè)疑問,它提到了在 gcc pass1 的時(shí)候做 bootstrap,即編譯一次后用產(chǎn)生的新編譯器編譯第二遍,再用產(chǎn)生的新的編譯器編譯第三遍,比較第二遍與第三遍結(jié)果是否相同。(LFS 6.7無(wú)此要求。)不知道這里的相同是指逐字節(jié)相同嗎?如果是,這在理論上可能嗎?我的想法是,已有的1.0版可能存在一個(gè)固有問題(或者不稱為問題,叫“特征”吧),它可能將影響到后面的一切,2.0 的編譯器不管自舉幾遍,或許總是無(wú)法完全消滅來(lái)自 1.0 的某些影響?

            不知道現(xiàn)在理論上是怎樣回答這個(gè)問題的。工程上又是如何對(duì)待這個(gè)問題的呢?

            這也許是個(gè)比較深層次的問題。抑或只是一個(gè)很膚淺的問題,只是我心生執(zhí)念罷了。期待解惑 ~_~

            posted @ 2010-10-19 00:59 溪流 閱讀(2707) | 評(píng)論 (13)編輯 收藏
            僅列出標(biāo)題
            共18頁(yè): First 7 8 9 10 11 12 13 14 15 Last 
            模特私拍国产精品久久| 国产成人久久精品一区二区三区| 国产福利电影一区二区三区,免费久久久久久久精 | 久久中文骚妇内射| 久久免费美女视频| 亚洲欧美日韩精品久久亚洲区| 久久精品国产99国产精品导航| 国产欧美久久久精品| 亚洲欧美成人久久综合中文网 | 久久亚洲AV成人出白浆无码国产| 91精品国产综合久久婷婷| 久久久久人妻一区精品果冻| 久久精品国产亚洲av麻豆蜜芽| 欧美综合天天夜夜久久| 久久无码中文字幕东京热| 91精品免费久久久久久久久| 亚洲女久久久噜噜噜熟女| 国产亚洲成人久久| 久久综合九色综合97_久久久| 热99RE久久精品这里都是精品免费 | 久久精品国产亚洲AV蜜臀色欲| 久久电影网2021| 久久久久久夜精品精品免费啦| 久久99国产精品成人欧美| 国产91久久精品一区二区| 久久婷婷五月综合97色直播| 久久精品综合一区二区三区| 狠狠色丁香婷婷综合久久来| 精品熟女少妇av免费久久| 久久精品国产亚洲AV香蕉| 久久精品视频一| 热久久最新网站获取| 午夜福利91久久福利| 日本久久中文字幕| 亚洲国产成人精品91久久久| 久久国产V一级毛多内射| 国内精品伊人久久久久网站| 久久综合九色综合久99| 国产精品激情综合久久| 国产成人精品久久| 欧美日韩精品久久久免费观看|