win32 最小化工具

本文是仿照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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值