2016-03-30 25 views
0

我想在外部窗口的標題欄中放置一個按鈕,就像Teamviewer對Quickconnect功能的操作一樣,或者像Chrome一樣在右上角切換用戶。如何將「teamviewer quickconnect」樣式的按鈕實現到外部窗口中?

我知道這是How is Teamviewers Quickconnect button accomplished?

重複我只是想知道,是否有可能得到一個工作示例或實現這一個開放源代碼程序的鏈接。給出的答案對我來說相當先進。如在,我怎麼「鉤」和「攔截」WM_NCPAINT消息等等。

回答

1

這是最簡單的例子,我可以開發:

你需要的Visual Studio,加2項目的解決方案:

enter image description here

第一個項目(HookDLL)是一個dll項目,第二(運行程序)是一個Win32控制檯項目

在main.cpp中

(在項目運行的應用程序)補充一點:

__declspec(dllimport) void RunHook(); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    RunHook(); 
    return 0; 
} 

在dllmain按鈕中。CPP(在HookDLL項目)添加以下代碼:

#include <Windows.h> 
#include <stdio.h> 

HINSTANCE hinstDLL; 
HHOOK hhook_wndproc; 
HWND b = NULL; 
HBRUSH blue_brush = NULL, yellow_brush, red_brush; 
int button_status = 0; 

LRESULT CALLBACK DefaultWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(Msg) 
    { 
    case WM_CREATE: 
     if(!blue_brush) 
     { 
      blue_brush = CreateSolidBrush(RGB(0, 0, 255)); 
      yellow_brush = CreateSolidBrush(RGB(255, 255, 0)); 
      red_brush = CreateSolidBrush(RGB(255, 0, 0)); 

     } 
     break; 
    case WM_PAINT: 
     { 
      HBRUSH b; 
      PAINTSTRUCT ps; 
      HDC hdc = BeginPaint(hwnd, &ps); 
      switch(button_status) 
      { 
      case 0: 
       b = blue_brush; 
       break; 
      case 1: 
       b = yellow_brush; 
       break; 
      default: 
       b = red_brush; 
      } 
      FillRect(hdc, &ps.rcPaint, b); 
      EndPaint(hwnd, &ps); 
     } 
     return 0; 
    case WM_MOUSEMOVE: 
     if(button_status == 0) 
     { 
      SetTimer(hwnd, 1, 100, NULL); 
      button_status = 1; 
      InvalidateRect(hwnd, NULL, false); 
     } 
     return 0; 
    case WM_TIMER: 
     { 
      POINT pt; 
      GetCursorPos(&pt); 
      if(button_status == 1 && WindowFromPoint(pt) != hwnd) 
      { 
       KillTimer(hwnd, 1); 
       button_status = 0; 
       InvalidateRect(hwnd, NULL, false); 
      } 
     } 
     return 0; 
    case WM_MOUSELEAVE: 
     button_status = 0; 
     InvalidateRect(hwnd, NULL, false); 
     return 0; 
    case WM_LBUTTONDOWN: 
     button_status = 2; 
     InvalidateRect(hwnd, NULL, false); 
     return 0; 
    case WM_LBUTTONUP: 
     if(button_status == 2) MessageBox(GetParent(hwnd), "teamviewer like button clicked", "Message", MB_OK); 
     button_status = 1; 
     InvalidateRect(hwnd, NULL, false); 
     return 0; 
    } 
    return DefWindowProc(hwnd, Msg, wParam, lParam); 
} 

void InitButton(HWND parent, int xPos, int yPos) 
{ 
    WNDCLASS wc; 

    wc.style = 0; 
    wc.lpfnWndProc = DefaultWindowProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hinstDLL; 
    wc.hIcon = NULL; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = NULL; 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = "DEFAULT_CLASS"; 
    RegisterClass(&wc); 
    b = CreateWindowEx(WS_EX_TOOLWINDOW, "DEFAULT_CLASS", NULL, WS_BORDER | WS_POPUP | WS_VISIBLE, xPos, yPos, 20, 20, parent, NULL, hinstDLL, NULL); 
} 

LRESULT WINAPI HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) 
{ 
    if(nCode >= 0 && lParam != 0) 
    { 
     CWPRETSTRUCT *msg = (CWPRETSTRUCT*)lParam; 
     if(!IsWindow(msg->hwnd) || (GetWindowLong(msg->hwnd, GWL_STYLE) & WS_CHILD) != 0) return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam); 
     switch(msg->message) 
     { 
     case WM_SHOWWINDOW: 
      if(!b && msg->wParam != 0) 
      { 
       b = (HWND)1;// see NOTES 5 
       RECT a; 
       GetWindowRect(msg->hwnd, &a); 
       InitButton(msg->hwnd, a.right - 150, a.top); 
      } 
      break; 
     case WM_SIZE: 
      if(GetParent(b) == msg->hwnd) 
      { 
       RECT a; 
       GetWindowRect(msg->hwnd, &a); 
       SetWindowPos(b, 0, a.right - 150, a.top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER); 
      } 
      break; 
     case WM_SIZING: 
     case WM_MOVING: 
      if(GetParent(b) == msg->hwnd) 
      { 
       RECT* lprc = (LPRECT) msg->lParam; 
       SetWindowPos(b, 0, lprc->right - 150, lprc->top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER); 
      } 
     } 
    } 
    return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam); 
} 

__declspec(dllexport) void RunHook() 
{ 
    hhook_wndproc = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProc, hinstDLL, 0); 
    char aux[10]; 
    gets_s(aux); 
    UnhookWindowsHookEx(hhook_wndproc); 
} 

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 
{ 
    switch (ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
     hinstDLL = hModule; 
     break; 
    case DLL_THREAD_ATTACH: 
    case DLL_THREAD_DETACH: 
    case DLL_PROCESS_DETACH: 
     break; 
    } 
    return TRUE; 
} 

現在,使項目爲正在運行的應用項目>項目依賴的DLL項目depedent:

enter image description here

注: 1)我不使用NC畫圖代碼,因爲並不總是有效,如果Windows緩衝非客戶區域,則會擦除自定義的NC畫圖按鈕

2)在64位環境中,您需要爲32位應用程序運行32位掛鉤,64位應用程式

3),你不能調試鉤子,在連接到另一個PROCCESS,我建議你在你的應用程序和線程窗口調試它,而在另一個proccess後期測試時,工作

4)我使用一個按鈕狀的方式爲簡單起見

5)這一行

b = (HWND)1; 

我用它來「解決」一個多線程的問題,我建議你做出更好的代碼(同步化)這種情況下

是如何工作的:

  • 運行應用程序
  • ,當它開始安裝一個掛鉤
  • 打開任何其他應用程序(同32/64位,見注2)
  • 你必須在標題欄左側看到一個藍色按鈕
  • 單擊它並看到一個消息框
  • 對於完成掛鉤:只需在控制檯窗口按ENTER鍵

代碼流:

  • 運行的應用程序只是調用RunHook()在DLL程序和DLL做的DLL工作
  • RunHook()開始鉤HookCallWndProc(全球)
  • HookCallWndProc捕獲所需的消息並使用InitButton()過程創建窗口按鈕
  • DefaultWindowProc處理按鈕消息
相關問題