本文是仿照Trayconizer软件制作。
本文的最小化工具是能够随意控制一个程序并使之最小化,恢复的软件。如在命令行中运行:
Trayconizer.exe C;\windows\notepad.exe;
将会打开一个记事本,当点击最小化按钮时,会影藏到后台运行,并在托盘中显示记事本的图标,双击记事本恢复窗口,右键点击弹出“Restore”,“Close”菜单。当记事本关闭后,工具软件也会关闭。工具软件是一直在后台运行的,不会显示窗口。
用到了3个枚举窗口函数。
// 枚举窗口函数
BOOL CALLBACK fnAdd(HWND hwnd,LPARAM lParam)
{
ShowWindowAsync(hwnd,SW_MINIMIZE);
return TRUE;
}
// 枚举窗口,将图标从图片删除,Restore菜单
BOOL CALLBACK fnDelRestore(HWND hwnd,LPARAM lParam)
{
Shell_NotifyIcon(NIM_DELETE,&g_nid);
ShowWindowAsync(hwnd,SW_SHOW);
ShowWindowAsync(hwnd,SW_RESTORE);
SetForegroundWindow(hwnd);
return TRUE;
}
// 枚举窗口函数,将图标从托盘删除,Close菜单
BOOL CALLBACK fnDelClose(HWND hwnd,LPARAM lParam)
{
Shell_NotifyIcon(NIM_DELETE,&g_nid);
PostMessage(hwnd,WM_CLOSE,0,0);
return TRUE;
}
使用钩子来截取应用程序的最小化消息。
// 窗口最小化处理函数
void CALLBACK MinProc(HWINEVENTHOOK hWinEventHook,DWORD dwEvent,HWND hwnd,LONG idObject,LONG idChild,DWORD dwEventThread,DWORD dwMsEventTime)
{
#ifdef _DEBUG_
WCHAR pwchMsg[128] = { 0 };
wsprintf(pwchMsg,_T("%x %x\n"),dwEvent,dwEventThread);
WriteConsole(g_hOutput,pwchMsg,wcslen(pwchMsg),NULL,NULL);
#endif
if(dwEvent == EVENT_SYSTEM_MINIMIZESTART) // 最小化
{
g_nid.cbSize = sizeof(NOTIFYICONDATA);
g_nid.uID = MY_TRAY_ICON_ID;
g_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
g_nid.hWnd = g_hWnd;
g_nid.uCallbackMessage = WM_MYMSG;
wcscpy_s(g_nid.szTip,g_pwchCmdLine);
HICON hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_SMALL,0);
if(NULL == hIcon)
{
hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_SMALL2,0);
if(hIcon == NULL)
{
hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_BIG,0);
if(hIcon == NULL)
{
hIcon = (HICON)GetClassLong(hwnd,GCL_HICON);
if(hIcon == NULL)
{
SHFILEINFO stFileInfo;
::SHGetFileInfo(g_pwchCmdLine,0,&stFileInfo,sizeof(stFileInfo),SHGFI_ICON);
hIcon = stFileInfo.hIcon;
if(NULL==hIcon)
hIcon = LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TRAYCONIZER));
}
}
}
}
g_nid.hIcon = hIcon;
Shell_NotifyIcon(NIM_ADD,&g_nid);
ShowWindow(hwnd,SW_HIDE);
}
/*
else if(dwEvent == EVENT_SYSTEM_MINIMIZEEND)
{
EnumThreadWindows(g_dwTrayPid,fnDelRestore,0);
}
else if(dwEvent == EVENT_OBJECT_DESTROY) // 关闭
{
SendMessage(g_hWnd,WM_CLOSE,0,0);
}*/
}
使用线程监视应用进程是否已经关闭。
// 等待进程关闭,然后结束进程
DWORD CALLBACK WaitForClose(LPVOID lpParam)
{
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,g_dwTrayPid);
WaitForSingleObject(hProc,INFINITE);
SendMessage(g_hWnd,WM_CLOSE,0,0);
return 0;
}
完整源码:
// Traynizer.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "Trayconizer.h"
#include "shellapi.h"
//#define _DEBUG_
HINSTANCE g_hInst = NULL;
const int WM_MYMSG = WM_USER + 1;
const int MY_TRAY_ICON_ID = 152;
const int IDM_RESTORE = 2001;
const int IDM_CLOSE = 2002;
const LPWSTR gc_aMinimize = _T("-minimize");
HWND g_hWnd = NULL;
LPWSTR g_lpAppName = _T("Win32");
WCHAR g_pwchCmdLine[128];
NOTIFYICONDATA g_nid = { 0 };
DWORD g_dwTrayPid,g_dwTrayTid;
#ifdef _DEBUG_
HANDLE g_hOutput = NULL; // 输出窗口句柄
#endif
// 主窗口回调函数
LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
// 枚举窗口函数,将图标添加到托盘
BOOL CALLBACK fnAdd(HWND hwnd,LPARAM lParam);
// 枚举窗口函数,将图标从托盘删除,Restore菜单
BOOL CALLBACK fnDelRestore(HWND hwnd,LPARAM lParam);
// 枚举窗口函数,将图标从图片删除,Close菜单
BOOL CALLBACK fnDelClose(HWND hwnd,LPARAM lParam);
// 窗口最小化处理函数
void CALLBACK MinProc(HWINEVENTHOOK hWinEventHook,DWORD dwEvent,HWND hwnd,LONG idObject,LONG idChild,DWORD dwEventThread,DWORD dwMsEventTime);
// 等待进程关闭
DWORD CALLBACK WaitForClose(LPVOID lpParam);
// 结束进程
BOOL TerminateProcessFromID(DWORD id);
// 解析命令行
BOOL DecordCmdLine(LPWSTR lpwstrCmd);
// 主函数
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
#ifdef _DEBUG_
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
//wcscpy(lpCmdLine,_T("-minimize C:\\windows\\notepad.exe"));
BOOL bFlag = DecordCmdLine(lpCmdLine);
/*********************************************** 进程创建过程 **/
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi = { 0 };
if(wcslen(lpCmdLine)<=0)
{
MessageBoxW(NULL,
_T("Trayconizer 1.1.1, by WhitSoft Development\n")
_T("http://www.whitsoftdev.com/trayconizer/\n")
_T("\n")
_T("The easiest way to use Trayconizer is to set the target of a shortcut to the path of the Trayconizer executable f")
_T("ollowed by the path of the program you want to Trayconize. For example:\n")
_T("C:\\path\\to\\Trayconizer.exe C:\\Windows\\Regedit.exe\n")
_T("\n")
_T("You can also tell Trayconizer to start the program in the Trayconized state using the -minimize command line swit")
_T("ch. For example:\n")
_T("C:\\path\\to\\Trayconizer.exe -minimize C:\\Windows\\Regedit.exe\n")
_T("\n")
_T("Note that not all programs can be Trayconized, so your mileage may vary. Enjoy!"),
_T("Trayconizer"),
0x40u);
ExitProcess(0);
return 0;
}
if(!CreateProcess(NULL,lpCmdLine,0,0,0,0,0,0,&si,&pi))
{
WCHAR pwchMsg[128];
DWORD dwErr = GetLastError();
if(dwErr == 740)
{
wsprintf(pwchMsg,_T("Unable to start %s . require Administrator!"),lpCmdLine);
}
else
{
wsprintf(pwchMsg,_T("Unable to start %s . %d"),lpCmdLine,GetLastError());
}
MessageBox(NULL,pwchMsg,_T("Trayconizer"),MB_OK | MB_ICONINFORMATION);
ExitProcess(0);
return 0;
}
g_dwTrayPid= pi.dwProcessId;
g_dwTrayTid = pi.dwThreadId;
WaitForInputIdle(pi.hProcess,0xffffffff);
#ifdef _DEBUG_
WCHAR pwchMsg[128];
wsprintf(pwchMsg,_T("pid:%d tid:%d\n"),g_dwTrayPid,g_dwTrayTid);
WriteConsole(g_hOutput,pwchMsg,wcslen(pwchMsg),NULL,NULL);
#endif
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
wcscpy(g_pwchCmdLine,lpCmdLine);
/*********************************************************/
/*************** 主窗口创建过程 ***************/
HWND hwnd = FindWindow(g_lpAppName,_T("Trayconizer"));
if(hwnd)
{
g_hWnd = hwnd;
}
else
{
WNDCLASS wndcls = { 0 };
wndcls.style = CS_HREDRAW | CS_VREDRAW;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = WinProc;
wndcls.lpszClassName = g_lpAppName;
wndcls.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_TRAYCONIZER));
wndcls.hCursor = LoadCursor(NULL,IDC_ARROW);
wndcls.lpszMenuName = NULL;
wndcls.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
if(!RegisterClass(&wndcls)){
MessageBox(NULL,_T("注册窗口类失败"),_T("tips"),MB_ICONINFORMATION | MB_OK);
return 0;
}
g_hWnd = CreateWindow(g_lpAppName,_T("Trayconizer"),WS_OVERLAPPEDWINDOW,
0,0,0,0,
NULL,NULL,hInstance,0);
if(g_hWnd == NULL)
{
MessageBox(NULL,_T("窗口创建失败!"),0,0);
TerminateProcessFromID(g_dwTrayPid);
ExitProcess(0);
return 0;
}
g_hInst = hInstance;
}
/****************************************************/
if(!SetWinEventHook(EVENT_MIN,EVENT_MAX,NULL,MinProc,g_dwTrayPid,g_dwTrayTid,WINEVENT_OUTOFCONTEXT))
{
WCHAR pwchMsg[64];
wsprintf(pwchMsg,_T("SetWinEventHook failed . %d"),GetLastError());
MessageBox(NULL,pwchMsg,0,MB_ICONINFORMATION | MB_OK);
TerminateProcessFromID(g_dwTrayPid);
ExitProcess(0);
return 0;
}
if(bFlag) // 最小化窗口
{
if(!EnumThreadWindows(g_dwTrayTid,fnAdd,0))
{
DWORD dwErr = GetLastError();
WCHAR lpwstr[64] = { 0 };
wsprintf(lpwstr,_T("EnumThreadWindows failed . %d"),dwErr);
MessageBox(NULL,lpwstr,_T("Trayconizer"),MB_OK | MB_ICONINFORMATION);
TerminateProcessFromID(g_dwTrayPid);
SendMessage(g_hWnd,WM_CLOSE,-1,0);
ExitProcess(0);
return 0;
}
}
DWORD dwId;
HANDLE hThrd = CreateThread(NULL,NULL,WaitForClose,NULL,0,&dwId);
if(NULL == hThrd)
{
WCHAR pwchMsg[64];
wsprintf(pwchMsg,_T("CreateThread failed . %d"),GetLastError());
MessageBox(NULL,pwchMsg,_T("tip"),MB_OK | MB_ICONINFORMATION);
TerminateProcessFromID(g_dwTrayPid);
SendMessage(g_hWnd,WM_CLOSE,0,0);
ExitProcess(0);
return 0;
}
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//解析命令行
BOOL DecordCmdLine(LPWSTR lpwstrCmd)
{
int len = wcslen(lpwstrCmd);
LPWSTR lpwstrtmp = new WCHAR[len];
memset(lpwstrtmp,0,sizeof(lpwstrtmp));
if(*lpwstrCmd == _T('-'))
{
int ispace = 0;
for(ispace =0;ispace<len;ispace++)
{
lpwstrtmp[ispace] = lpwstrCmd[ispace];
if(lpwstrCmd[ispace] == _T(' '))
{
lpwstrtmp[ispace] = 0;;
break;
}
}
if(ispace != 0 && ispace < len)
{
if(wcscmp(lpwstrtmp,gc_aMinimize) == 0)
{
LPWSTR lpwstrNewCmd = new WCHAR[len-ispace+2];
memset(lpwstrNewCmd,0,sizeof(lpwstrNewCmd));
int j = 0;
for(int i=ispace+1;i<len;i++,j++)
lpwstrNewCmd[j] = lpwstrCmd[i];
lpwstrNewCmd[j] = 0;
wcscpy(lpwstrCmd,lpwstrNewCmd);
delete[] lpwstrNewCmd;
return TRUE;
}
}
}
return FALSE;
}
// 窗口回调函数
LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 1;
case WM_COMMAND:
{
switch(wParam)
{
case IDM_CLOSE:
EnumThreadWindows(g_dwTrayTid,fnDelClose,0);
PostMessage(g_hWnd,WM_CLOSE,0,0);
return 0;
case IDM_RESTORE:
EnumThreadWindows(g_dwTrayTid,fnDelRestore,0);
return 0;
}
}break;
case WM_MYMSG:
switch(lParam)
{
case WM_LBUTTONDBLCLK:
EnumThreadWindows(g_dwTrayTid,fnDelRestore,0);
break;
case WM_RBUTTONUP:
{
POINT pt;
GetCursorPos(&pt);
HMENU hMenu = CreatePopupMenu();
AppendMenu(hMenu,MF_INSERT,IDM_RESTORE,_T("Restore"));
AppendMenu(hMenu,MF_INSERT,IDM_CLOSE,_T("Close"));
SetMenuDefaultItem(hMenu,IDM_RESTORE,0);
TrackPopupMenu(hMenu,TPM_RIGHTBUTTON,pt.x,pt.y,NULL,hwnd,NULL);
DestroyMenu(hMenu);
}break;
}
break;
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}
// 枚举窗口函数
BOOL CALLBACK fnAdd(HWND hwnd,LPARAM lParam)
{
ShowWindowAsync(hwnd,SW_MINIMIZE);
return TRUE;
}
// 枚举窗口,将图标从图片删除,Restore菜单
BOOL CALLBACK fnDelRestore(HWND hwnd,LPARAM lParam)
{
Shell_NotifyIcon(NIM_DELETE,&g_nid);
ShowWindowAsync(hwnd,SW_SHOW);
ShowWindowAsync(hwnd,SW_RESTORE);
SetForegroundWindow(hwnd);
return TRUE;
}
// 枚举窗口函数,将图标从托盘删除,Close菜单
BOOL CALLBACK fnDelClose(HWND hwnd,LPARAM lParam)
{
Shell_NotifyIcon(NIM_DELETE,&g_nid);
PostMessage(hwnd,WM_CLOSE,0,0);
return TRUE;
}
// 窗口最小化处理函数
void CALLBACK MinProc(HWINEVENTHOOK hWinEventHook,DWORD dwEvent,HWND hwnd,LONG idObject,LONG idChild,DWORD dwEventThread,DWORD dwMsEventTime)
{
#ifdef _DEBUG_
WCHAR pwchMsg[128] = { 0 };
wsprintf(pwchMsg,_T("%x %x\n"),dwEvent,dwEventThread);
WriteConsole(g_hOutput,pwchMsg,wcslen(pwchMsg),NULL,NULL);
#endif
if(dwEvent == EVENT_SYSTEM_MINIMIZESTART) // 最小化
{
g_nid.cbSize = sizeof(NOTIFYICONDATA);
g_nid.uID = MY_TRAY_ICON_ID;
g_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
g_nid.hWnd = g_hWnd;
g_nid.uCallbackMessage = WM_MYMSG;
wcscpy_s(g_nid.szTip,g_pwchCmdLine);
HICON hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_SMALL,0);
if(NULL == hIcon)
{
hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_SMALL2,0);
if(hIcon == NULL)
{
hIcon = (HICON)SendMessage(hwnd,WM_GETICON,ICON_BIG,0);
if(hIcon == NULL)
{
hIcon = (HICON)GetClassLong(hwnd,GCL_HICON);
if(hIcon == NULL)
{
SHFILEINFO stFileInfo;
::SHGetFileInfo(g_pwchCmdLine,0,&stFileInfo,sizeof(stFileInfo),SHGFI_ICON);
hIcon = stFileInfo.hIcon;
if(NULL==hIcon)
hIcon = LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TRAYCONIZER));
}
}
}
}
g_nid.hIcon = hIcon;
Shell_NotifyIcon(NIM_ADD,&g_nid);
ShowWindow(hwnd,SW_HIDE);
}
/*
else if(dwEvent == EVENT_SYSTEM_MINIMIZEEND)
{
EnumThreadWindows(g_dwTrayPid,fnDelRestore,0);
}
else if(dwEvent == EVENT_OBJECT_DESTROY) // 关闭
{
SendMessage(g_hWnd,WM_CLOSE,0,0);
}*/
}
// 等待进程关闭,然后结束进程
DWORD CALLBACK WaitForClose(LPVOID lpParam)
{
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,g_dwTrayPid);
WaitForSingleObject(hProc,INFINITE);
SendMessage(g_hWnd,WM_CLOSE,0,0);
return 0;
}
// 通过进程ID关闭进程
BOOL TerminateProcessFromID(DWORD id)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,id);
if(hProcess!=NULL)
{
return TerminateProcess(hProcess,0);
}
CloseHandle(hProcess);
return FALSE;
}