simple node and list merge

  1. #include "stdafx.h"
  2. #include <stdlib.h>
  3. #include <iostream>
  4. #include <iomanip>
  5. using namespace std;
  6. class Node
  7. {
  8. public:
  9. Node();
  10. ~Node();
  11. void SetData(int n) { m_data = n; };
  12. int GetData() { return m_data; };
  13. Node* Next() { return m_lpNext; };
  14. void SetNext(Node* newPos);
  15. void Print();
  16. protected:
  17. int m_data;
  18. Node* m_lpNext;
  19. };
  20. Node::Node() :m_data(0), m_lpNext(nullptr)
  21. {
  22. }
  23. Node::~Node()
  24. {
  25. cout << " begin to delete-" << GetData() << endl;
  26. }
  27. void Node::Print()
  28. {
  29. cout << "data=" << m_data << " next=" << m_lpNext << endl;
  30. }
  31. void Node::SetNext(Node* newPos)
  32. {
  33. if ( newPos )
  34. {
  35. m_lpNext = newPos;
  36. }
  37. }
  38. class NodeList
  39. {
  40. public:
  41. NodeList() :m_pHead(nullptr), m_pLast(nullptr)
  42. {
  43. };
  44. ~NodeList()
  45. {
  46. while (m_pHead)
  47. {
  48. Node* temp = m_pHead;
  49. m_pHead = temp->Next();
  50. delete temp;
  51. }
  52. m_pHead = nullptr;
  53. m_pLast = nullptr;
  54. };
  55. void Print()
  56. {
  57. Node * temp = m_pHead;
  58. while (temp)
  59. {
  60. temp->Print();
  61. temp = temp->Next();
  62. }
  63. }
  64. bool push_back(int n)
  65. {
  66. if (m_pHead == nullptr)
  67. {
  68. m_pHead = new Node;
  69. if (m_pHead)
  70. m_pHead->SetData(n);
  71. m_pLast = m_pHead;
  72. }
  73. else
  74. {
  75. Node* newPos = new Node;
  76. if (newPos)
  77. {
  78. newPos->SetData(n);
  79. m_pLast->SetNext(newPos);
  80. m_pLast = m_pLast->Next();
  81. }
  82. }
  83. return true;
  84. };
  85. //! add list2 to the last
  86. void MergeList(NodeList& list2)
  87. {
  88. Node* newHead = list2.GetHead();
  89. while (newHead)
  90. {
  91. push_back(newHead->GetData());
  92. newHead = newHead->Next();
  93. }
  94. };
  95. Node* GetHead()
  96. {
  97. return m_pHead;
  98. };
  99. protected:
  100. Node* m_pHead;
  101. Node* m_pLast;
  102. };
  103. int _tmain(int argc, _TCHAR* argv[])
  104. {
  105. NodeList nodeTest;
  106. nodeTest.push_back(1);
  107. nodeTest.push_back(2);
  108. nodeTest.push_back(3);
  109. nodeTest.push_back(4);
  110. nodeTest.push_back(5);
  111. nodeTest.push_back(6);
  112. nodeTest.Print();
  113. NodeList nodeTest2;
  114. nodeTest2.push_back(11);
  115. nodeTest2.push_back(22);
  116. nodeTest2.push_back(33);
  117. nodeTest2.push_back(44);
  118. nodeTest2.push_back(55);
  119. nodeTest2.push_back(66);
  120. nodeTest.MergeList(nodeTest2);
  121. nodeTest.Print(); // should print out 1,2,3,...11,22,33,...
  122. return 0;
  123. }
上面是第一个版本,没有sort的功能。
下面是带sort的功能。
===============================
#include "stdafx.h"#include <stdlib.h>#include <iostream>#include <iomanip>using namespace std;
 
class Node
{
public:
    Node();
    ~Node();
    void    SetData(int n) { m_data = n; };
    int     GetData() { return m_data; };
    Node*   Next() { return m_lpNext; };
    void    SetNext(Node* newPos);
    void    Print();
 
protected:
    int     m_data;
    Node*   m_lpNext;
};
 
Node::Node() :m_data(0), m_lpNext(nullptr)
{
 
}
 
Node::~Node()
{
    cout <<  " begin to delete-" << GetData() << endl;
}
 
void Node::Print()
{
    cout << "data=" << m_data << " next=" << m_lpNext << endl;
}
 
void Node::SetNext(NodenewPos)
{
    if ( newPos )
    {
        m_lpNext = newPos;
    }
}
 
class NodeList
{
public:
    NodeList() :m_pHead(nullptr), m_pLast(nullptr)
    {
 
    };
    ~NodeList()
    {
        while (m_pHead)
        {
            Node* temp = m_pHead;
            m_pHead = temp->Next();
            delete temp;
        }
 
        m_pHead = nullptr;
        m_pLast = nullptr;
    };
 
    void Print()
    {
        Node * temp = m_pHead;
        while (temp)
        {
            temp->Print();
            temp = temp->Next();
        }
    }
 
    bool    push_back(int n)
    {
        if (m_pHead == nullptr)
        {
            m_pHead = new Node;
            if (m_pHead)
                m_pHead->SetData(n);
 
            m_pLast = m_pHead;
        }
        else
        {
            Node* newPos = new Node;
            if (newPos)
            {
                newPos->SetData(n);
                m_pLast->SetNext(newPos);
                m_pLast = m_pLast->Next();
            }
        }
 
        return true;
    };
 
    bool push_back_sorted(int n)
    {
        if (m_pHead == nullptr)
        {
            m_pHead = new Node;
            if (m_pHead)
                m_pHead->SetData(n);
 
            m_pLast = m_pHead;
        }
        else
        {
            Node* newPos = new Node;
            if (newPos)
            {
                newPos->SetData(n);
 
                Node* pFind = LookupNewPos(n);
                if (pFind)
                {
                    Node* pFindNext = pFind->Next();
                    pFind->SetNext(newPos);
                    newPos->SetNext(pFindNext);
                    m_pLast = pFindNext ? pFindNext : newPos;
                }
                else
                {
                    Node* tempHeadNext = m_pHead;
                    m_pHead = newPos;
                    newPos->SetNext(tempHeadNext);
                }
            }
        }
 
        return true;
    };
 
    Node*   LookupNewPos(int n)
    {
        Node* tempCur = m_pHead;
        if (tempCur && !Sort(n, tempCur->GetData()))
            return nullptr;
 
        Node* tempFind = m_pHead;
        tempCur = m_pHead->Next();
        if (tempCur == nullptr)
            return tempFind;
 
        while (tempCur)
        {
            if (!Sort(n, tempCur->GetData()))
            {
                break;
            }
            else
            {
                tempFind = tempCur;
                tempCur = tempCur->Next();
            }
        }
 
        return tempFind ? tempFind : m_pHead;
    }
 
    //! can be override anybool    Sort(int n1int n2)
    {
        return (n1 > n2) ? true : false;
    }
 
    //! add list2 to the lastvoid MergeList(NodeListlist2)
    {
        Node* newHead = list2.GetHead();
        while (newHead)
        {
            push_back(newHead->GetData());
            newHead = newHead->Next();
        }
    };
 
    //! add list2 and sortedvoid MergeListSort(NodeListlist2)
    {
        Node* newHead = list2.GetHead();
        while (newHead)
        {
            push_back_sorted(newHead->GetData());
            newHead = newHead->Next();
        }
    };
 
    Node*   GetHead()
    {
        return m_pHead;
    };
protected:
    Node*   m_pHead;
    Node*   m_pLast;
};
 
int _tmain(int argc_TCHARargv[])
{
    NodeList nodeTest;
    nodeTest.push_back(1);
    nodeTest.push_back(2);
    nodeTest.push_back(3);
    nodeTest.push_back(4);
    nodeTest.push_back(5);
    nodeTest.push_back(6);
 
    nodeTest.Print();
 
    NodeList nodeTest2;
 
    nodeTest2.push_back(11);
    nodeTest2.push_back(22);
    nodeTest2.push_back(33);
    nodeTest2.push_back(44);
    nodeTest2.push_back(55);
    nodeTest2.push_back(66);
 
    nodeTest.MergeList(nodeTest2);
 
    nodeTest.Print();  // should print out 1,2,3,...11,22,33,...//test sorted node listNodeList sortNodeList;
    sortNodeList.push_back_sorted(4);
    sortNodeList.push_back_sorted(5);
    sortNodeList.push_back_sorted(3);
    sortNodeList.push_back_sorted(2);
    sortNodeList.push_back_sorted(14);
 
    sortNodeList.Print();   // should print: 2,3,4,5,14
 
    sortNodeList.MergeListSort(nodeTest2);
 
    sortNodeList.push_back_sorted(10);
    sortNodeList.push_back_sorted(18);
    sortNodeList.push_back_sorted(1);
 
    cout << "new merged:" << endl;
    sortNodeList.Print();   // should print: 2,3,4,5,14return 0;
}
Posted in 技术开发 | 5 Comments

delete all history of one file with sensitive data

一个命令一个命令的敲吧。这个试过是可以work的,记下来,

以备需要。

步骤一: 从你的资料库中清除文件

以Windows下为例(Linux类似), 打开项目的Git Bash,使用命令: 

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch path-to-your-remove-file' --prune-empty --tag-name-filter cat -- --all

其中, path-to-your-remove-file 就是你要删除的文件的相对路径(相对于git仓库的跟目录), 替换成你要删除的文件即可.

如果你要删除的文件很多, 可以写进一个.sh文件批量执行, 如果文件或路径里有中文, 由于MinGW或CygWin对中文路径设置比较麻烦, 你可以使用通配符*号, 例如: sound/music_*.mp3, 这样就把sound目录下以music_开头的mp3文件都删除了.

例如这样, del-music-mp3.sh:

#!/bin/bash

# git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch projects/Moon.mp3' --prune-empty --tag-name-filter cat -- --all
# git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch sound/Music_*.mp3' --prune-empty --tag-name-filter cat -- --all

 如果你看到类似下面这样的, 就说明删除成功了:

Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (266/266)
# Ref 'refs/heads/master' was rewritten

如果显示 xxxxx unchanged, 说明repo里没有找到该文件, 请检查路径和文件名是否正确.

注意: 补充一点, 如果你想以后也不会再上传这个文件或文件夹, 请把这个文件或文件夹添加到.gitignore文件里, 然后再push你的repo.

步骤二: 推送我们修改后的repo

以强制覆盖的方式推送你的repo, 命令如下:

git push origin master --force

这个过程其实是重新上传我们的repo, 比较耗时, 虽然跟删掉重新建一个repo有些类似, 但是好处是保留了原有的更新记录, 所以还是有些不同的. 如果你实在不在意这些更新记录, 也可以删掉重建, 两者也差不太多, 也许后者还更直观些.

执行结果类似下面:

复制代码
Counting objects: 4669, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4352/4352), done.
Writing objects: 100% (4666/4666), 35.16 MiB | 51 KiB/s, done.
Total 4666 (delta 1361), reused 0 (delta 0)
To https://github.com/defunkt/github-gem.git
 + beb839d...81f21f3 master -> master (forced update)
复制代码

 步骤三: 清理和回收空间

虽然上面我们已经删除了文件, 但是我们的repo里面仍然保留了这些objects, 等待垃圾回收(GC), 所以我们要用命令彻底清除它, 并收回空间.

命令如下:

复制代码
rm -rf .git/refs/original/

git reflog expire --expire=now --all

git gc --prune=now
Counting objects: 2437, done.# Delta compression using up to 4 threads.# Compressing objects: 100% (1378/1378), done.# Writing objects: 100% (2437/2437), done.# Total 2437 (delta 1461), reused 1802 (delta 1048)
git gc --aggressive --prune=now
Counting objects: 2437, done.# Delta compression using up to 4 threads.# Compressing objects: 100% (2426/2426), done.# Writing objects: 100% (2437/2437), done.# Total 2437 (delta 1483), reused 0 (delta 0)
复制代码

注: 绿色字部分是命令执行后的结果.Pasted from: http://www.cnblogs.com/shines77/p/3460274.html

Posted in 技术开发 | 2 Comments

29. 光头的那几年

光头的那几年

很亲切

江边 田野

你的笑容 天边

夕阳无限

醉了 真醉了

你是我的从前

我们在这里再见

手还是

挽着手

只是从前

我欠你一个军礼

吃一个大白兔

是我想念你的守候

是我们想念你们的时候

其实我还在等你

在我们熟悉的街口

其实这不是我写的

翻翻旧照片

你青春依旧

你的 ——老牛

光头的这些年

是我

春风拂起的无眠

Posted in 那年夏天 | Tagged | Leave a comment

学习下 WTL 的 thunk-转载的,写的很好

由于 C++ 成员函数的调用机制问题,对C语言回调函数的 C++ 封装是件比较棘手的事。为了保持C++对象的独立性,理想情况是将回调函数设置到成员函数,而一般的回调函数格式通常是普通的C函数,尤其是 Windows API 中的。好在有些回调函数中留出了一个额外参数,这样便可以由这个通道将 this 指针传入。比如线程函数的定义为:

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

这样,当我们实现线程类的时候,就可以:

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();
    }
};

不过,这样,成员函数 ThreadProc() 便丧失了一个参数,这通常无伤大雅,任何原本需要从参数传入的信息都可以作为成员变量让 ThreadProc 来读写。如果一定有些什么是非从参数传入不可的,那也可以,一种做法,创建线程的时候传入一个包含 this 指针信息的结构。第二种做法,对该 class 作单例限制——如果现实情况允许的话。

所以,有额外参数的回调函数都好处理。不幸的是,Windows 的窗口回调函数没有这样一个额外参数:

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

这使得对窗口的 C++ 封装变得困难。为了解决这个问题,一个很自然的想法是,维护一份全局的窗口句柄到窗口类的对应关系,如:

#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 的时候,指定 StaticWndProc 为窗口回调函数,并将 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,然后转发给成员函数:

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 的多线程保护略过,下同)

据说 MFC 采用的就是类似的做法。缺点是,每次 StaticWndProc 都要从 m_sWindows 中去找 this。由于窗口类一般会保存窗口句柄,回调函数里的 hWnd 就没多大作用了,如果这个 hWnd 能够被用来存 this 指针就好了,那么就能写成这样:

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

这样看上去就爽多了。传说中 WTL 所采取的 thunk 技术就是这么干的。之前,只是听过这遥远的传说,今天,终于有机会走进这个传说去看一看。参考资料是一篇不知原始出处的文章《深入剖析WTL—WTL框架窗口分析》,以及部分 WTL 8.0 代码,还有其他乱七八糟的文章。

WTL 的思路是,每次在系统调用 WndProc 的时候,让它鬼使神差地先走到我们的另一处代码,让我们有机会修改堆栈中的 hWnd。这处代码可能是类似这样的:

__asm
{
    mov dword ptr [esp+4], pThis  ;调用 WndProc 时,堆栈结构为:RetAddr, hWnd, message, wParam, lParam, … 故 [esp+4]
    jmp WndProc
}

由于 pThis 和 WndProc 需要被事先修改(但又无法在编译前定好),所以我们需要运行的时候去修改这部分代码。先弄一个小程序探测下这两行语句的机器码:

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 是为了等下调试的时候容易找到进入点。

然后使用 OllyDbg,在 MessageBoxW 上设置断点,执行到该函数返回:

image

这里我们看到,mov dword ptr [esp+4] 的机器码为 C7 44 24 04,后面紧接着的一个 DWORD 是 mov 的第二个操作数。jmp 的机器码是 e9,后面紧接着的一个 DWORD 是跳转的相对地址。其中 00061000h – 0006102Bh = FFFFFFD5h。

于是定义这样一个结构:

#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)

这个结构可以作为窗口类的成员变量存在。我们的窗口类现在变成了这样子:

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);
};

似乎少了点什么……创建窗口的时候,我们是不能直接把回调函数设到 StaticWndPorc 中去的,因为这个函数是希望被写成这样子的:

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

那么至少需要一个临时的回调函数,在这个函数里去设置新的回调函数(设到 m_thunk 上),再由 m_thunk 来调用 StaticWndProc,StaticWndProc 再去调用 WndProc,这样整个过程就通了。

但是,临时回调函数还是需要知道从 hWnd 到 this 的对应关系。可是现在我们不能照搬用刚才的 m_sWindows 了。因为窗口在创建过程中就会调用到回调函数,需要使用到 m_sWindows 里的 this,而窗口被成功创建之前,我们没法提前拿到 HWND 存入 m_sWindows。现在,换个方法,存当前线程 ID 与 this 的对应关系。这样,这个类变成了:

#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;
};

然后实现 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);
}

差不多可以了,调试一下。结果,在 thunk 的第一行出错了。我原以为地址算错了神马的,尝试把 thunk.m_mov 改为 0x90909090,再运行,还是出错。于是傻掉了……过了好一会儿才意识到,可能是因为 thunk 在数据段,无法被执行。可是,很久很久以前偶滴一个敬爱的老师在 TC 中鼓捣程序运行时改变自身代码时,貌似无此问题啊。。。然后查呀查,原来是 Windows 在的数据执行保护搞的鬼。于是,需要用 VirtualAlloc 来申请一段有执行权限的内存。WTL 里面也是这么做的,不过它似乎维护了一块较大的可执行内存区作为 thunk 内存池,我们这里从简。最后,整个流程终于跑通了。最终代码清单如下:

#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 指针的时候,我很武断地把它与当前线程 ID 关联起来了,其实这正是 WTL 本身的做法。它用 CAtlWinModule::AddCreateWndData 存的 this,最终会把当前线程 ID 和 this 作关联。我是这么理解的吧,同一线程不可能同时有两处在调用 CreateWindow,所以这样取回来的 this 是可靠的。

好了,到此为止,边试验边记录的,不知道理解是否正确。欢迎指出不当之处,也欢迎提出相关的问题来考我,欢迎介绍有关此问题的新方法、新思路,等等,总之,请各位看官多指教哈。

Posted in 技术开发 | Leave a comment

28.关于一个梦

昨天,做了一个梦。

日本,某个大学,我被应邀参加一个会议。
可是,不知道为什么,学校里正在开展一个学生运动,简称学运,
很不幸的是,我也被日本警察带进了所里。
没有拷问,没有虐待。
我悄悄的溜走了,还不忘带走一件警察的衣服。
可是我不会日语。
夜晚。
某个小店的灯亮着,招牌是“定制中山装”,oh,肯定是中国人。
于是我走进店里。
“老板,我需要一个向导”
“你想要做什么?”
“我要回中国”
……
梦醒了,中国梦!
Posted in 那年夏天 | Tagged | 2 Comments