(源码)小工具箱:锁屏,闹钟,定时关机,关闭显示器

由于日常需要一个锁屏小软件,但又不想去装一些别人的软件,就想着自己写一个小软件来供自己日常使用。软件的主要功能有:锁屏,闹钟,定时关机,关机显示屏功能。

下面将分别介绍这几种功能的实现,采用的是VC++实现。在这里只讲解主要技术功能的实现,就不贴所有的代码了,贴不下!!!

一:逻辑

主要界面逻辑如下:

我知道这个图逻辑很烂,不过这只是自己使用的小软件而已 ,没必要那么认真,是吧,嘿嘿!整个界面的实现是模拟QQ设置界面来写的,这也是个不错的VC界面设计的例子。

二:实现

1.实现主窗口隐藏

在OnInitDialog中贴上如下代码即可

//隐藏在任务栏上的图标
	ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);
	//隐藏窗口
	WINDOWPLACEMENT wp;
	wp.length=sizeof(WINDOWPLACEMENT);
	wp.showCmd=SW_HIDE;
	SetWindowPlacement(&wp);
解释:

隐藏任务栏图标:
ModifyStyleEx的作用是修改窗口的风格,此函数的厉害之处在于可以在窗口创建之后修改窗口的风格,虽然有些属性修改不了,当然这也已经很不错了,不是吗。。。嘿嘿!

此函数的原型为:

BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );

第一个参数是指将要去除的窗口的属性,第二个参数是指将要增加的窗口的属性,第三个嘛,是用来表示是否调用::SetWindowPos函数的,0表示不调用,非零那就是调用了,具体参数值那就去查看MSDN吧!

WS_EX_APPWINDOW:在MSDN给出的解释是:Forces a top-level window onto the taskbar when the window is visible 含义是:把顶层的可见窗口放到任务栏上,去除这个属性当然在任务栏上也就没了,哈哈哈,简单吧

WS_EX_TOOLWINDOW:既然WS_EX_APPWINDOW就已经实现了在任务栏的隐藏那还要这个参数干嘛,直接ModifyStyleEx(WS_EX_APPWINDOW,0)不就行了吗?是的,是行了,不过这样隐藏的不彻底,用ALT+TAB就会发现他,所以要弄到这个参数,MSDN上给出的这个参数的含义是:

  • Creates a tool window, which is a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.
我就不翻译了,反正我的英语也不好,仅限于看懂的地步。。。

隐藏窗口:

这里用到了一个结构体WINDOWPLACEMENT,这个结构体中包含了窗口在屏幕上的位置信息,他有一个参数showcmd指定了当前窗口的显示状态,为SW_HIDE时表示隐藏窗口,是其他窗口变为激活状态,在这里就是用它这个功能实现,也许有人认为用ShowWindow(SW_HIDE)可以实现,是可以实现,但是那会出现闪烁现象。

2.窗体贴图的实现

完成大致界面如下:


这个界面是在模拟QQ中的设置界面实现的,虽然没有QQ的好看但是已经很不错了,谁让人家QQ有那么多美工的,而我就孤家寡人一个,再说QQ的界面好像是用WTL写的吧?!跟咱这不一样,不说了。

在OnInitDialog函数中贴上如下代码:

ModifyStyle( WS_CAPTION, WS_MINIMIZEBOX, SWP_DRAWFRAME );//设置图标
	m_bmpBackGround.LoadBitmap(IDB_BITMAPBACKGROUND);//m_bmpBackGround这个肯定是CBitmap类型嘛
在OnPaint函数中贴上如下代码:
CPaintDC dc(this);
	CRect rect;
	GetClientRect(&rect);
	CDC dcMem;
	dcMem.CreateCompatibleDC(&dc);
	BITMAP bitmap;
	m_bmpBackGround.GetBitmap(&bitmap);
	CBitmap *pbmpOld = dcMem.SelectObject(&m_bmpBackGround);
	dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
至此,功能便完成了。

解释:

在OnInitDialog函数中的ModifyStyle与上面讲的ModifyStyleEx功能差不多,只是ModifyStyleExe是ModifyStye的扩展而已,至于现在用到的参数,就不说了,看含义:

WS_CAPTION:

  • Creates a window that has a title bar (implies the WS_BORDER style). Cannot be used with theWS_DLGFRAME style.

WS_MINMIZEBOX:

  • Creates a window that has a Minimize button.

SWP_DRAWFRAME的作用则是绘制窗口的边距。

在OnPaint函数中代码的作用则是创建一个设备兼容的位图,然后将这个位图贴到窗口上。这里要解释下StretchBlt的作用,它的作用是从原矩形中复制一个位图到目标矩形,必要时按目标设备设置的模式进行图像的伸缩和拉伸。

至于这个主设置窗口中再设置子窗口,很简单,就是Create一个窗口,设置窗口的属性为子窗口,然后调用SetWindowPos设置窗口的位置就行了。

3.锁屏功能的实现

a.如何设置窗口的透明度

设置窗口透明的方法

如下:

//设置窗口透明度
void CDemoTransDlg::SetTrans(int iTranss)
{
	float f = (float)iTranss;
	f = 1- f/100.0;
	int iTrans = 255*f;
	//窗口透明  
	HINSTANCE hInst = GetModuleHandle(_T("User32.DLL"));    
	if(hInst)      
	{          
		typedef BOOL (WINAPI *TestFun)(HWND,COLORREF,BYTE,DWORD);//取得SetLayeredWindowAttributes函数指针        
		TestFun mytest = (TestFun)GetProcAddress(hInst, "SetLayeredWindowAttributes");          
		if(mytest)            
			mytest(m_hWnd,0,iTrans,LWA_ALPHA);    
	}
}
只需要在设置窗口透明度的地方调用这个方法就行,我这里的这个方法里的参数iTranss是CSliderCtrl的值所以是0-100,而SetLayeredWindowAttributes的参数值是0-255,所以我的函数里有个转换,对了对了,差点忘了一点,要设置透明度的这个窗口必须是顶层窗口,也就是说不是子窗口,而且在调用这个方法时,必须事先调用
SetWindowLong(m_hWnd,GWL_EXSTYLE,GetWindowLong(m_hWnd,GWL_EXSTYLE)^WS_EX_LAYERED);
将窗体的风格设为:WS_EX_LAYERED才行滴,该风格一被设置,我们用这个函数就可以设置窗体的透明度了,呵呵!!!下面解释一下SetLayeredWindowAttributes这个函数。

SetLayeredWindwAttributes这个函数在User32.dll中,所以需要GetModeleHandle(_T("User32.DLL")),函数的原型如下:

//The SetLayeredWindowAttributes function sets the opacity and transparency color key of a layered window.
BOOL SetLayeredWindowAttributes(
								HWND hwnd,           // handle to the layered window
								COLORREF crKey,      // specifies the color key
								BYTE bAlpha,         // value for the blend function
								DWORD dwFlags        // action
								);

这个函数进行透明度的设置时有两种方式,主要是用dwFlags这个参数决定,其值可以为:LWA_COLORKEY和LWA_ALPHA这两个参数,当取LWA_COLORKEY时,bAlpha参数无效,窗体中所有颜色为crKey的地方将变为透明;当取LWA_ALPHA时,crKey参数无效,bAlpha控制透明度。LWA_COLORKEY和LWA_ALPHA这两个参数可以同时使用,颜色是crKey的区域为透明,其他区域的透明度有bAlpha控制。

b.热键


用RegisterHotKey注册热键,用UnregisterHotKey删除热键,然后响应WM_HOTKEY消息

LRESULT CMyOwnSoftDlg::OnHotKey(WPARAM wparam,LPARAM lparam)
{
	int ID=(int)wparam;
	if (ID == 0)
	{
		LockScreenFunc(TRUE);//立即锁屏
	}
	if (ID == 1 || ID == 2)
	{
		UnLockScreenFunc();
	}
	return 0;
}

c.锁屏

锁屏主要分为:直接锁屏(快捷键调用)、定时锁屏、设置完毕立即锁屏、指定时间内无操作自动锁屏 这四种触发方式,这里暂且不讨论这么分是否合理,这里只是讲述技术上如何实现^_^    ,锁屏方式有两种:透明度可调的窗体锁屏和创建新屏幕并启动指定程序锁屏

锁屏的主要操作是屏蔽鼠标消息,键盘某些快捷键消息,这些可以通过全局钩子来实现,而对于Ctrl+Alt+Del调用任务管理器的屏蔽我在这里用的是远程进程注入的方式,利用dll注入当然也是可以的,最简单的就是注册表操作来屏蔽这个组合键,不过在这里就不一一详述了。

以下部分代码是参考网络上的资源来写的,如果大家查过或者做过相关的东西,一定会觉得眼熟,只是在哪个网站查的已经记不清了。

屏蔽鼠标消息:(dll中文件源码,全局hook所以放在dll中)

/********************************
 * Mouse Hook procedure.        *
 * (Win 9x)                     *
 ********************************/
LRESULT CALLBACK MouseHookProc(int nCode, WORD wParam, DWORD lParam) 
{
	if(nCode >= 0)
	{
        if (wParam == WM_LBUTTONDBLCLK)
        {
            if (((MOUSEHOOKSTRUCT *)lParam)->hwnd == GetDesktopWindow())
            {
                return 1;
            }
        }
	}

    return CallNextHookEx(hHook, nCode, wParam, lParam); 
} 
/***********************************
 * Low Level Mouse Hook procedure. *
 * (Win NT4SP3+)                   *
 ***********************************/
LRESULT CALLBACK LowLevelMouseHookProc(int nCode, WORD wParam, DWORD lParam) 
{
	PMSLLHOOKSTRUCT p = (PMSLLHOOKSTRUCT)lParam;
	HWND hwnd = WindowFromPoint(p->pt);
	if (nCode >= 0)
	{
		if ((wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN) && (hwnd != hWnd && hWnd != GetParent(hwnd))/*GetDesktopWindow()*/)
		{
			return 1;
		}
	}
	return CallNextHookEx(hHook,nCode,wParam,lParam);
}
/*************************************************
* 函数名:DisableDesktop                         *
* 功能:Hide/Show Desktop                        *
* 参数:TRUE=SHOW,FALSE=HIDE                    *
**************************************************/
int WINAPI DisableDesktop(BOOL bShowHide)
{
	OSVERSIONINFO osvi;
	int iServicePack;
	char* p;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	for ( p=osvi.szCSDVersion;*p && !isdigit(*p);*p++);
	iServicePack = atoi(p);
	BOOL bIsWindowsNT4SP3orLater = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
									(osvi.dwMajorVersion == 4 && iServicePack>=3)||
									(osvi.dwMajorVersion >4));
	if (!bShowHide)
	{
		if (!hHook)
		{
			hHook = SetWindowsHookEx(bIsWindowsNT4SP3orLater ? WH_MOUSE_LL : WH_MOUSE,
									 bIsWindowsNT4SP3orLater ? (HOOKPROC)LowLevelMouseHookProc : (HOOKPROC)MouseHookProc,
									 hInst,
										0);

			DWORD dw = GetLastError();
			if (!hHook)
				return 0;
		}
	}
	else
	{
		if (hHook)
		{
			UnhookWindowsHookEx(hHook);
			hHook = NULL;
		}
	}
	if (iMode == EnableLock_Mode)
	{
		return SetWindowPos(FindWindow(NULL, "Program Manager"),
							NULL,
							0, 0, 0, 0,
							SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER);
	}
	return SetWindowPos(FindWindow(NULL, "Program Manager"),
						NULL,
						0, 0, 0, 0,
						bShowHide ? SWP_SHOWWINDOW : SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER);
}

屏蔽键盘消息:(dll中文件源码,全局hook所以放在dll中

/***********************************
 * Low Level Keyboard Hook procedure. *
 * (Win NT4SP3+)					  *
 ***********************************/
HHOOK hKeyboardHook;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WORD wParam, DWORD lParam) 
{
	if (nCode == HC_ACTION)
	{
		KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT*)lParam;
		if (
			// WIN key (for Start Menu)
			((pkh->vkCode == VK_LWIN) || (pkh->vkCode == VK_RWIN)) ||       
			// ALT+TAB
			(pkh->vkCode == VK_TAB && pkh->flags & LLKHF_ALTDOWN) ||       
			// ALT+ESC
			(pkh->vkCode == VK_ESCAPE && pkh->flags & LLKHF_ALTDOWN) ||
			// ENTER AND ESCAPE
			(pkh->vkCode==VK_RETURN || pkh->vkCode==VK_ESCAPE) ||
			// ALT+F4
			(pkh->vkCode == VK_F4 && pkh->flags & LLKHF_ALTDOWN) ||
			// CTRL+ESC
			((pkh->vkCode == VK_ESCAPE) && ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)) ||
			// CTRL+SHIFT+ESC
			((pkh->vkCode == VK_ESCAPE) && ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) && ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0)) ||
			// CTRL+ALT+DEL (Unfortunately doesn't work !)
			((pkh->vkCode == VK_DELETE) && ( (pkh->flags & LLKHF_ALTDOWN) != 0 ) && ( (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0))
			)
		{
			return 1;
		}
	}
	return CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
}
/************************************************
* 函数:DisableSwitchKey                        *
* 功能:屏蔽快捷键                              *
* 参数:TRUE=启用,不屏蔽,FALSE=屏蔽           *
*************************************************/
int WINAPI DisableSwitchKey(BOOL bSwitch)
{
	if (!bSwitch)
	{
		if (!hKeyboardHook)
		{
			hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)LowLevelKeyboardProc,hInst,0);
			if (!hKeyboardHook)
				return 0;
		}
	}
	else
	{
		UnhookWindowsHookEx(hKeyboardHook);
	}
	return 1;
}
禁用任务栏:

/******************************************
* 禁用任务栏                              *
* "Shell_TrayWnd"为任务栏的ClassName      *
*******************************************/
int WINAPI DisableTaskBar(BOOL bTask)
{
	HWND hwnd;
	hwnd = FindWindow("Shell_TrayWnd",NULL);
	if (!hwnd)
		return 0;
	if (iMode == EnableLock_Mode)
	{
		EnableWindow(hwnd,bTask ? TRUE : FALSE);
	}
	else
	{
		ShowWindow(hwnd,bTask ? SW_SHOW : SW_HIDE);
		UpdateWindow(hwnd);
	}
	return 1;	
}

以上三点中都很容易实现,对于hook的知识很简单,分为局部hook和全局hook,这里要hook掉所有程序中键盘和鼠标消息,所以需要在系统消息链中加一个环节,用全局hook,有关hook详细知识这里就不讲述了,大家可以百度或google等等,总之很简单滴;对于任务栏的禁用用的是通过查找窗口的标题名或类名来获取窗口的句柄,从而来对其进行操作,很简单,FindWindow,在这里是用EnableWindow来禁用和启用,也可以用ShowWindow来显示和隐藏,看你的需要啦,选择自己的方式嘛。。。

屏蔽CTRL+ALT+DEL:

CTRL+ALT+DEL是不能通过全局hook进行捕获的,它不进消息链,这里举出两种屏蔽方式,一种是通过注册表操作屏蔽(单数感觉这种方式不太好,总是太窗提示“被管理员禁用”啥玩意的),一种就是进程注入的方式

注册表操作屏蔽方式:

LPCTSTR KEY_DisableTaskMgr ="Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
HKEY hk;
		if (RegOpenKey(HKEY_CURRENT_USER,KEY_DisableTaskMgr,&hk)!=ERROR_SUCCESS)
		{
			RegCreateKey(HKEY_CURRENT_USER,KEY_DisableTaskMgr,&hk);
		}
		if (bDisable)
		{
			DWORD val = 1;
			if (RegSetValueEx(hk,"DisableTaskMgr",NULL,REG_DWORD,(BYTE*)&val, sizeof(val))!=ERROR_SUCCESS)
			{
				OutputDebugString("写注册表错误");
			}
			
		}
		else
		{
			if (RegDeleteValue(hk,"DisableTaskMgr")!=ERROR_SUCCESS)
			{
				OutputDebugString("删除注册表错误");
			}
			
		}
		RegCloseKey(hk);
操作注册表这没有什么好讲的,添加键值就行。

进程远程代码注入的方式:(这个方法是通过网络得来,是老外写的,用的是进程的远程代码注入,没用dll方式注入,虽然这种方式有些危险,什么危险?试试就知道,嘿嘿,最多重启下电脑就好,但是这种方法不用额外的dll)

/***************************************************************************
 * Copies InjectFunc(), GetSASWnd() , SASWindowProc() and INJDATA to the   *
 * remote process.                                                         *
 * Starts the execution of the remote InjectFunc(), which subclasses the   *
 * remote process default window procedure handler.                        *
 *                                                                         *
 * Return value: 0=failure, 1=success                                      *
 ***************************************************************************/

int InjectCode ()
{
	HANDLE		hProcess = 0;			// Process handle
	HMODULE		hUser32  = 0;			// Handle of user32.dll
	BYTE		*pCodeRemote;			// Address of InjectFunc() in the remote process.
	BYTE		*pGetSASWndRemote;		// Address of GetSASWnd() in the remote process.
	HANDLE		hThread	= 0;			// The handle and ID of the thread executing
	DWORD		dwThreadId = 0;			//   the remote InjectFunc().
	INJDATA		DataLocal;				// INJDATA structure
	BOOL		fUnicode;				// TRUE if remote process is Unicode
	int			nSuccess = 0;			// Subclassing succeded?
	DWORD		dwNumBytesCopied = 0;	// Number of bytes written to the remote process.
	DWORD		size;					// Calculated function size (= AfterFunc() - Func())
	int			SearchSize;				// SASWindowProc() dummy addr. search size
	int			nDummyOffset;			// Offset in SASWindowProc() of dummy addr.
	BOOL		FoundDummyAddr;			// Dummy INJDATA reference found in SASWindowProc() ?
	HWND		hSASWnd;				// Window handle of Winlogon process
	BYTE		*p;

	// Enable Debug privilege (needed for some processes)
    if (!EnablePrivilege(SE_DEBUG_NAME, TRUE))
		return 0;

	// Get handle of "USER32.DLL"
	hUser32 = GetModuleHandle("user32");
	if (!hUser32)
		return 0;

	// Get remote process ID
    PID = GetPIDFromName(szProcessName);
    if (PID == -1)
		return 0;

	// Open remote process
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
	if (!hProcess)
		return 0;

	__try 
	{
		// Initialize INJDATA for GetSASWnd() call
		strcpy(DataLocal.szClassName, "SAS Window class");
		strcpy(DataLocal.szWindowName, "SAS window");
		DataLocal.fnFindWindow = (FINDWINDOW) GetProcAddress(hUser32, "FindWindowA");
		if (DataLocal.fnFindWindow == NULL)
			__leave;

		// Allocate memory in the remote process and write a copy of initialized INJDATA into it
		size = sizeof(INJDATA);
		pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);		
		if (!pDataRemote)
			__leave;
		if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
			__leave;

		// Allocate memory in remote process and write a copy of GetSASWnd() into it
		size = (PBYTE)AfterGetSASWnd - (PBYTE)GetSASWnd;
		pGetSASWndRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);		
		if (!pGetSASWndRemote)
			__leave;
		if (!WriteProcessMemory(hProcess, pGetSASWndRemote, &GetSASWnd, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
			__leave;
		
		// Start execution of remote GetSASWnd()
		hThread = CreateRemoteThread(hProcess, 
									 NULL, 
									 0, 
									 (LPTHREAD_START_ROUTINE) pGetSASWndRemote,
									 pDataRemote, 
									 0 , 
									 &dwThreadId);
		// Failed
		if (!hThread)
			__leave;

		// Wait for GetSASWnd() to terminate and get return code (SAS Wnd handle)
		WaitForSingleObject(hThread, INFINITE);
		GetExitCodeThread(hThread, (PDWORD) &hSASWnd);

		// Didn't found "SAS window"
		if (!hSASWnd)
			__leave;

		// Cleanup
		VirtualFreeEx(hProcess, pGetSASWndRemote, 0, MEM_RELEASE);
		VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
		pGetSASWndRemote = NULL;
		pDataRemote = NULL;
		
		// Allocate memory in remote process and write a copy of SASWindowProc() into it
		size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
		pSASWinProcRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);		
		if (!pSASWinProcRemote)
			__leave;
		if (!WriteProcessMemory(hProcess, pSASWinProcRemote, &SASWindowProc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
			__leave;

		// Is remote process unicode ?
		fUnicode = IsWindowUnicode(hSASWnd);

		// Initialize the INJDATA structure
		DataLocal.fnSetWindowLong = (SETWINDOWLONG)  GetProcAddress(hUser32, fUnicode ? "SetWindowLongW" : "SetWindowLongA");
		DataLocal.fnCallWindowProc = (CALLWINDOWPROC) GetProcAddress(hUser32, fUnicode ? "CallWindowProcW": "CallWindowProcA");
		DataLocal.fnSASWndProc = (WNDPROC) pSASWinProcRemote;
		DataLocal.hwnd = hSASWnd;

		if (DataLocal.fnSetWindowLong  == NULL || 			
			DataLocal.fnCallWindowProc == NULL)
		{
			__leave;		
		}

		// Allocate memory in the remote process and write a copy of initialized INJDATA into it
		size = sizeof(INJDATA);
		pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);		
		if (!pDataRemote)
			__leave;
		if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
			__leave;

		// Change dummy INJDATA address in SASWindowProc() by the real INJDATA pointer
		p = (PBYTE)&SASWindowProc;
		size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
		SearchSize = size - sizeof(DWORD) + 1;
		FoundDummyAddr = FALSE;

		for (; SearchSize > 0; p++, SearchSize--)
		{
			if (*(DWORD *)p == DUMMY_ADDR)	// Found 
			{
				nDummyOffset = p - (PBYTE)&SASWindowProc; 
				if (!WriteProcessMemory(hProcess, pSASWinProcRemote + nDummyOffset, &pDataRemote, sizeof(pDataRemote), &dwNumBytesCopied) ||
					dwNumBytesCopied != sizeof(pDataRemote))
				{
					__leave;
				}
				FoundDummyAddr = TRUE;
				break;
			}
		}

		// Couldn't change the dummy INJDATA addr. by the real addr. in SASWindowProc() !?!
		// Don't execute the remote copy of SASWindowProc() because the pData pointer is invalid !
		if (!FoundDummyAddr)
		{
			__leave;
		}

		// Allocate memory in the remote process and write a copy of InjectFunc() to the allocated memory
		size = (PBYTE)AfterInjectFunc - (PBYTE)InjectFunc;
		pCodeRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!pCodeRemote)
			__leave;
		if (!WriteProcessMemory(hProcess, pCodeRemote, &InjectFunc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
			__leave;

		// Start execution of remote InjectFunc()
		hThread = CreateRemoteThread(hProcess, 
									 NULL, 
									 0, 
									 (LPTHREAD_START_ROUTINE) pCodeRemote,
									 pDataRemote, 
									 0 , 
									 &dwThreadId);
		if (!hThread)
			__leave;

		// Wait for InjectFunc() to terminate and get return code
		WaitForSingleObject(hThread, INFINITE);
		GetExitCodeThread(hThread, (PDWORD) &nSuccess);
	}

	__finally 
	{
		// Failed ?
		if (!nSuccess)
		{
			// Release memory for INJDATA and SASWindowProc()
			if (pDataRemote)
				VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
			if (pSASWinProcRemote)
				VirtualFreeEx(hProcess, pSASWinProcRemote, 0, MEM_RELEASE);
			pDataRemote = NULL;
			pSASWinProcRemote = NULL;
		}

		// Release remote GetSASWnd()
		if (pGetSASWndRemote)	
			VirtualFreeEx(hProcess, pGetSASWndRemote, 0, MEM_RELEASE);

		// Release remote InjectFunc() (no longer needed)
		if (pCodeRemote)	
			VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);

		if (hThread)			
			CloseHandle(hThread);

	}

	CloseHandle(hProcess);

	// Disable the DEBUG privilege
	EnablePrivilege(SE_DEBUG_NAME, FALSE);

	return nSuccess;	// 0=failure; 1=success
}


/**********************************************************************
 * Copies EjectFunc() to the remote process and starts its execution. *
 * The remote EjectFunc() restores the old window procedure.          *
 *                                                                    *
 *	Return value: 0=failure, 1=success                                *
 **********************************************************************/

int EjectCode ()
{
	HANDLE		hProcess;				// Remote process handle
	DWORD		*pCodeRemote;			// Address of EjectFunc() in the remote process
	HANDLE		hThread = NULL;			// The handle and ID of the thread executing
	DWORD		dwThreadId = 0;			//   the remote EjectFunc().
	int			nSuccess	= 0;		// EjectFunc() success ?
	DWORD		dwNumBytesCopied = 0;	// Number of bytes written to the remote process. 
	DWORD		size;					// Calculated function size (= AfterFunc() - Func())

	// Enable Debug privilege (needed for some processes)
	EnablePrivilege(SE_DEBUG_NAME, TRUE);

	// Remote INDATA and SASWindowProc() must exist 
	if (!pDataRemote || !pSASWinProcRemote)
		return 0;

	// Open the process
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
	if (hProcess == NULL)
		return 0;

	// Allocate memory in the remote process and write a copy of EjectFunc() to the allocated memory
	size = (PBYTE)AfterEjectFunc - (PBYTE)EjectFunc;
	pCodeRemote = (PDWORD) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!pCodeRemote)
	{
		CloseHandle(hProcess);
		return 0;
	}
	if (!WriteProcessMemory(hProcess, pCodeRemote, &EjectFunc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
	{
		VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
		CloseHandle(hProcess);
		return 0;
	}

	// Start execution of the remote EjectFunc()
	hThread = CreateRemoteThread(hProcess, 
								 NULL, 
								 0, 
								 (LPTHREAD_START_ROUTINE) pCodeRemote,
								 pDataRemote, 
								 0 , 
								 &dwThreadId);
	// Failed
	if (!hThread)
	{
		goto END;
	}

	// Wait for EjectFunc() to terminate and get return code
	WaitForSingleObject(hThread, INFINITE);	
	GetExitCodeThread(hThread, (PDWORD) &nSuccess);	

	// Failed to restore old window procedure ?
	// Then leave INJDATA and the SASWindowProc()
	if (nSuccess == 0)		
		goto END;			
							
	// Release memory for remote INJDATA and SASWindowProc()
	if (pDataRemote)
		VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
	if (pSASWinProcRemote)
		VirtualFreeEx(hProcess, pSASWinProcRemote, 0, MEM_RELEASE);
	pDataRemote = NULL;
	pSASWinProcRemote = NULL;

//	MessageBeep(0);		// success

END:		
	if (hThread)
		CloseHandle(hThread);

	// Release EjectFunc() memory
	if (pCodeRemote)
		VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);

	CloseHandle(hProcess);

	// Disable the DEBUG privilege
	EnablePrivilege(SE_DEBUG_NAME, FALSE);

	return nSuccess;	// 0=failure; 1=success
}
这里只给出了主要的两个函数:注入,卸载;由于代码太多,没办法都给出,不过整体思路流程都有了。下面再给一个注入的窗口回调函数

static LRESULT CALLBACK SASWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// INJDATA pointer. 
	// Must be patched at runtime !
	INJDATA* pData = (INJDATA *)DUMMY_ADDR;

	if (uMsg == WM_HOTKEY)
	{
		// Ctrl+Alt+Del
		if (lParam == MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE))
			return 1;

		// Ctrl+Shift+Esc
		if (lParam == MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE))
			return 1;
	}

	// Call the original window procedure
	return pData->fnCallWindowProc(pData->fnOldSASWndProc, hwnd, uMsg, wParam, lParam);		
}

在这个函数里便是真正的屏蔽了调用任务管理器的快捷调用方式,(不过经测试在win7下好像有点问题,木起作用。。。大家一起看看吧),有关代码注入的详细实现方法,我就不讲了,其实我也不是很精通,仅限于了解,再说在这里讲一时半会是讲不完滴,给大家推荐一个网址,codeproject上的一篇文章,讲的很详细,几种方法都有,而且各种注意事项都说的很详细: Three Ways to Inject Your Code into Another Process

OK,至此,锁屏主要功能已经实现了,只有那个什么几种触发方式,没什么可讲的,就是SetTimer什么什么的,这都是小的逻辑问题了,都加都能实现的。下面是两张锁屏后的效果截图,是我在虚拟机中win7下的截屏:

透明窗体锁屏:


创建新屏幕锁屏:

至此锁屏部分便已完成。

d.闹钟

在这一块没什么可以说的,就是setTimer设定定时器,到时间了闹就是了,这里唯一可以提的两点就是:音乐的播放(直接调用API,没什么讲的)和提示窗口的显示方式(这里是模仿QQ好友上线提示方式,右下角淡入淡出或上下移动提示)。

提示效果图:(音乐你们就听不了喽)


音乐播放:

m_Audio = MCIWndCreate(this->GetSafeHwnd(),AfxGetInstanceHandle(), WS_CHILD|MCIWNDF_NOMENU,m_AlarmSct.sMusicPath);
m_snd =MCIWndGetLength(m_Audio);//得到文件长度
MCIWndHome(m_Audio); 
MCIWndPlay(m_Audio);
大致相关函数就这么多,具体的那你就查MSDN或google去吧。

淡入淡出和上下移动:

DWORD dword = ::GetTickCount();

if (m_bFad_in_Fad_out)//淡入淡出效果
{
	if(nIDEvent == START_TIME)
	{
		m_nAlpha += 15;
		m_bflag = SetDlgAlpha(m_nAlpha);
		if(!m_bflag || m_nAlpha >= 255)
		{
			KillTimer(START_TIME);
			//开始计算停留
			m_dStart = GetTickCount();
			SetTimer(STAY_TIME,100,NULL);
		}
	}
	else if(nIDEvent == STAY_TIME)
	{
		if(dword - m_dStart >= m_snd)
		{
			m_dStart = 0;
			KillTimer(STAY_TIME);
			SetTimer(CLOSE_TIME,50,NULL);
		}
	}
	else if(nIDEvent == CLOSE_TIME)
	{
		m_nAlpha -= 15;
		m_bflag = SetDlgAlpha(m_nAlpha);
		if(!m_bflag || m_nAlpha <= 0)
		{
			KillTimer(CLOSE_TIME);
			if (m_AlarmSct.iDelay > 0)
			{
				SetTimer(DELAYTIME,m_AlarmSct.iDelay*60*1000,NULL);
			}
			else
			{
				DestroyWindow();
			}
		}
	}
}
else  //上下移动效果
{		
	//static int nHeight = 0;

	//处于顶层的最大化窗口的缺省尺寸
	int nFullHeight = GetSystemMetrics(SM_CYMAXIMIZED);
	int nFullWidth  = GetSystemMetrics(SM_CXMAXIMIZED);

	CRect rc;
	GetClientRect(rc);
	int ndlgWidth = rc.Width();
	int ndlgHeigth = rc.Height();

	rc.left = nFullWidth - ndlgWidth - 10;
	rc.right = rc.left + ndlgWidth;

	if(nIDEvent == START_TIME)
	{
		if(m_nHeight <= ndlgHeigth)
		{
			m_nHeight+= 10;
			rc.top = nFullHeight - m_nHeight;
			rc.bottom = rc.top + ndlgHeigth;
			MoveWindow(&rc,FALSE);
			ShowWindow(SW_SHOWNORMAL);
			Invalidate(FALSE);
		}
		else
		{
			KillTimer(START_TIME);
			//开始计算停留
			m_dStart = GetTickCount();
			SetTimer(STAY_TIME,100,NULL);
		}
	}
	else if(nIDEvent == STAY_TIME)
	{
		if(dword - m_dStart >= m_snd)
		{
			m_dStart = 0;
			KillTimer(STAY_TIME);
			SetTimer(CLOSE_TIME,50,NULL);
		}
	}
	else if(nIDEvent == CLOSE_TIME)
	{
		if(m_nHeight >= 0)
		{
			m_nHeight-= 10;
			rc.top = nFullHeight - m_nHeight;
			rc.bottom = rc.top + ndlgHeigth;
			MoveWindow(&rc,FALSE);
			ShowWindow(SW_SHOWNORMAL);
		}
		else
		{
			KillTimer(CLOSE_TIME);
			if (m_AlarmSct.iDelay > 0)
			{
				SetTimer(DELAYTIME,m_AlarmSct.iDelay*60*1000,NULL);
			}
			else
			{
				DestroyWindow();
			}
		}

	}

}
以上代码是OnTimer中的部分,不过逻辑这两种效果的实现方法已经很明确了。

e.定时关机

这里主要给出关机部分的实现,其他没啥可说的

BOOL CShutDownShowDlg::CloseWindows()
{
	// Get the Windows version.
	DWORD dwVersion = GetVersion();
	BOOL bIsNT = FALSE;
	if (dwVersion < 0x80000000)                // Windows NT/2000
		bIsNT = TRUE;
	//else if (dwWindowsMajorVersion < 4)	 // Win32s
	//else	 // Windows 95/98 -- No build number

	if (bIsNT)   // Win2000
	{
		static HANDLE hToken;
		static TOKEN_PRIVILEGES tp;
		static LUID luid;
		::OpenProcessToken( GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ;
		::LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &luid );
		tp.PrivilegeCount           = 1;
		tp.Privileges[0].Luid       = luid;
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
		::AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL );
	}

	::ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0);	//关机



	return TRUE;
}
f.关闭显示器

代码:

// 关闭显示器
void CMyOwnSoftDlg::OnClosemonitor()
{
	//也可向HWND_BROADCAST句柄发送消息
	Sleep(500);
	// Turn off monitor
	SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
	// Turn on monitor
	// SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);
	// Low power monitor
	// SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 1);
}
g.其他

设置窗口全屏:

void CLockProcDlg::SetFullScreen()
{
	int frameWidth =  GetSystemMetrics(SM_CXFRAME);
	int frameHeight = GetSystemMetrics(SM_CYFRAME);
	int captionHeight = GetSystemMetrics(SM_CYCAPTION);
	int screenWidth = GetSystemMetrics(SM_CXSCREEN);
	int screenHeight = GetSystemMetrics(SM_CYSCREEN);
	CRect rect;
	GetClientRect(&rect);
	rect.left = rect.left - frameWidth;
	rect.top = rect.top - frameHeight - captionHeight ;
	rect.bottom = rect.top + screenHeight + 2 * frameHeight + captionHeight;
	rect.right = rect.left + screenWidth + 2 * frameWidth;
	ShowWindow(SW_HIDE);
	SetWindowPos(&wndTopMost, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW);
}

在窗口绘制文字(双缓冲):

void CLockProcDlg::PaintMonitorStatic(int iYPos,CString sStr,int nFontSize,CString nFontMode)
{
	CSize csize;
	CRect rect;
	CBitmap bitmap;
	CDC dcMemSave;
	CFont font;
	CDC *pDC = GetDC();
	font.CreatePointFont(nFontSize,nFontMode);
	dcMemSave.CreateCompatibleDC(NULL);
	dcMemSave.SelectObject (&font);
	csize = dcMemSave.GetTextExtent(sStr);
	bitmap.CreateCompatibleBitmap(pDC,csize.cx,csize.cy);
	dcMemSave.SelectObject(&bitmap);
	
	dcMemSave.SetBkMode(OPAQUE);
	dcMemSave.SetBkColor(::GetSysColor(COLOR_BTNFACE));
	dcMemSave.SetTextColor (RGB(255,55,0));
	dcMemSave.TextOut (0,0,sStr);
	font.DeleteObject ();
	GetClientRect(&rect);
	pDC->BitBlt(rect.right-csize.cx,iYPos,csize.cx,csize.cy,&dcMemSave,0,0,SRCCOPY);
	bitmap.DeleteObject();
	dcMemSave.DeleteDC();
}

好啦,不写了,大概的东西就这么多。

现在程序写完了,可是想要给别人用,总不能,把整个配置文件啊,exe文件啊,还有dll文件直接复制给别人吧,对,要做一个安装包,怎么做那,请移步另一篇日志: inno setup打包实例,这个打包实例就是对这个程序的打包。

有网友要源码,现把源码连接附上,代码很粗糙,不要见笑:http://download.csdn.net/detail/wanglx2012/8044211


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值