2017-11-10 13 views
1

표시되는 창없이 간단하게 트레이 아이콘으로 응용 프로그램을 만들려고합니다. 나는 여러 자습서와 함께 여기에 대한 답변을 시도했지만 이보다 더 이상 얻을 수 없었습니다. 컨텍스트 메뉴는 오른쪽 클릭이 완전히 비어있을 때 나타납니다. 나는 또한 그것이 작동하게되면 클릭 한 것을 탐지하는 방법을 알지 못합니다.시스템 트레이 컨텍스트 메뉴 공백

최종 목표는 컨텍스트 메뉴에서 두 가지 옵션 중 하나를 클릭하여 DNS 서버를 전환 할 수있게하는 것입니다.

#include <Windows.h> 
#include <shellapi.h> 
#include <tchar.h> 
#include <WinUser.h> 


HINSTANCE gInstance = NULL; 

LRESULT CALLBACK pWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 
    WNDCLASSEX wx; 
    HWND hWnd; 
    ZeroMemory(&wx, sizeof(WNDCLASSEX)); 

    wx.cbSize = sizeof(WNDCLASSEX); 
    wx.lpfnWndProc = pWndProc; 
    wx.hInstance = hInstance; 
    wx.lpszClassName = (LPCWSTR)"DNSChanger"; 
    RegisterClassEx(&wx); 
    CreateWindowEx(0, (LPCWSTR)"DNSChanger", (LPCWSTR)"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 
    gInstance = hInstance; 

    MSG stMsg; 
    while (GetMessage(&stMsg, NULL, 0, 0) > 0) 
    { 
     TranslateMessage(&stMsg); 
     DispatchMessage(&stMsg); 
    } 

    return 0; 
} 

LRESULT CALLBACK pWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    NOTIFYICONDATA niData; 
    ZeroMemory(&niData, sizeof(NOTIFYICONDATA)); 

    switch (uMsg) 
    { 
     case WM_CREATE: 
     { 
      niData.cbSize = sizeof(NOTIFYICONDATA); 
      niData.uID = 1; 
      niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 
      niData.hIcon = LoadIcon(gInstance, MAKEINTRESOURCE(IDI_SHIELD)); 
      niData.hWnd = hWnd; 
      niData.uCallbackMessage = WM_USER + 1; 

      Shell_NotifyIcon(NIM_ADD, &niData); 
     } 
     return 0; 

     case WM_DESTROY: 
     { 
      niData.hWnd = hWnd; 
      Shell_NotifyIcon(NIM_DELETE, &niData); 
     } 
     return 0; 

     case WM_USER + 1: 
     { 
      switch (LOWORD(lParam)) 
      { 
       case WM_RBUTTONUP: 
       { 
        POINT lpClickPoint; 
        HMENU hPopMenu; 

        UINT uFlag = MF_BYPOSITION | MF_UNCHECKED | MF_STRING; 
        GetCursorPos(&lpClickPoint); 
        hPopMenu = CreatePopupMenu(); 
        InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, WM_USER + 1, _T("Exit")); 
        SetForegroundWindow(hWnd); 
        TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL); 
       } 
      } 
     } 
    } 
} 

답변

0

(LPCWSTR)"DNSChanger"과 같은 캐스트는 사용하지 마십시오. 이는 컴파일러 오류 만 숨 깁니다. 프로그램이 전혀 작동하지 않는 유일한 이유는이 오류가 2 개의 다른 장소에서 반복되고 취소되기 때문입니다.

귀하는 L"DNSChanger"으로 작성하십시오.

창 절차는 응용 프로그램을 종료하려는 경우 PostQuitMessage(0);을 포함해야 WM_DESTROY에서 DefWindowProc(hWnd, uMsg, wParam, lParam);

을 반환해야합니다.

는 일부 WM_COMMAND 메시지로 IDM_EXIT 명령을 보내드립니다 메뉴

const int IDM_EXIT = 100; 
... 
InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit"); 

메뉴에서 사용할 새로운 상수를 정의합니다. 다음은 권장 변경 사항입니다.

HINSTANCE gInstance = NULL; 
const int IDM_EXIT = 100; 
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    static NOTIFYICONDATA niData = { sizeof(NOTIFYICONDATA) }; 

    switch(uMsg) 
    { 
    case WM_CREATE: 
    { 
     niData.uID = 1; 
     niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 
     niData.hIcon = LoadIcon(gInstance, IDI_SHIELD); 
     niData.hWnd = hWnd; 
     niData.uCallbackMessage = WM_USER + 1; 
     Shell_NotifyIcon(NIM_ADD, &niData); 
     return 0; 
    } 

    case WM_DESTROY: 
    { 
     niData.hWnd = hWnd; 
     Shell_NotifyIcon(NIM_DELETE, &niData); 
     PostQuitMessage(0); 
     return 0; 
    } 

    case WM_COMMAND: 
    { 
     if(LOWORD(wParam) == IDM_EXIT) 
      PostQuitMessage(0); 
     break; 
    } 

    case WM_USER + 1: 
    { 
     WORD cmd = LOWORD(lParam); 
     if (cmd == WM_RBUTTONUP || cmd == WM_LBUTTONUP) 
     { 
      POINT pt; 
      GetCursorPos(&pt); 
      HMENU hmenu = CreatePopupMenu(); 
      InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit"); 
      TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL); 
     } 
     break; 
    } 

    } 

    return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) 
{ 
    gInstance = hInstance; 
    WNDCLASSEX wx = { sizeof(WNDCLASSEX) }; 
    wx.lpfnWndProc = WndProc; 
    wx.hInstance = hInstance; 
    wx.lpszClassName = L"DNSChanger"; 
    RegisterClassEx(&wx); 

    CreateWindowEx(0, L"DNSChanger", L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 

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

감사합니다. 그건 고쳐졌고 이제는 출구 옵션을 가지고 여기에서 나머지를 끝낼 수 있어야합니다! 그러나 아이콘이 사라졌습니다 ... 방패 아이콘이 작업 표시 줄에 나타나기 전에는 아무 것도 변경되지 않았을 것입니다. – user3845041

+0

또한 MAKEINTRESOURCE (IDI_SHIELD)를 다음과 같이 변경했습니다. 'IDI_SHIELD'는''WinUser.h "'에'IDI_SHIELD'가'MAKEINTRESOURCE (32518)'로 정의되어 있기 때문에 이전의 잘못된 ID로 인해 표시 오류가 발생했을 수 있습니다. 아이콘 캐시를 지우려면 컴퓨터를 다시 시작해야합니다. 당신은 어쨌든 자신의 아이콘을 제공하고 싶습니다. –

+0

아이콘이 사라진 이유는 확실하지 않지만 제 자신을 추가 한 후에는 문제가 없었습니다. 프로그램이 완료되었습니다. 도움을 주셔서 감사합니다. 디버그에서 릴리스로 변경하는 것을 혼란스럽게 한 것은 컴파일하기 위해 모든 문자열에서 주요 'L'을 제거해야한다는 것을 의미합니다 ...? – user3845041