【原創】WinMo仿wp7關機、重啟、關屏(關機需HTCUtil支持)

--------------------------------------------------------------------------------------------------------------------------------------- .h
#include "RdWrtIni.h"
#include <time.h>
#include <atlbase.h>
#include <pm.h>


// 重啟數據定義
#define CTL_CODE( DeviceType, Function, Method, Access ) ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) )
#define FILE_DEVICE_HAL 0x00000101
#define METHOD_BUFFERED 0
#define FILE_ANY_ACCESS 0
#define IOCTL_HAL_REBOOT CTL_CODE(FILE_DEVICE_HAL, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)

extern "C" __declspec(dllimport) BOOL KernelIoControl(DWORD dwIoControlCode,
													  LPVOID lpInBuf,
													  DWORD nInBufSize,
													  LPVOID lpOutBuf,
													  DWORD nOutBufSize,
													  LPDWORD lpBytesReturned);

#define MAX_LOADSTRING 100
#define TimeInterval 1	// 計時器間隔
#define PROFILE		_T(".\\MetroOff.ini")

void DrawUI(HDC hDC, int type, int Distance);						// 繪圖操作
void FillSolidRect(HDC hDC, RECT rect, COLORREF clr);							// 填充純色(當Profile.isLoadImage == FALSE)
void CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime);	// 用作釋放光標后滑塊恢復原狀
void ShutDownWM();		// 僅支持HTC

struct Profile
{
	BOOL		isLoadImage;			// 是否加載圖片

	WCHAR		szScreenOff[MAX_PATH];	// 關屏圖片路徑
	WCHAR		szReboot[MAX_PATH];		// 重啟圖片路徑
	WCHAR		szShutDown[MAX_PATH];	// 關機圖片路徑

	COLORREF	clrScreenOff;			// 關屏色彩
	COLORREF	clrReboot;				// 重啟色彩
	COLORREF	clrShutDown;			// 關機色彩

	int			Status;					// 初始操作狀態:(0:關屏 1:關機 2:重啟)
};

Profile		g_Profile;	// 配置文件
int			g_Pos;		// 滑塊位置  注意:考慮最大最小值,防止超過最大位移
int			g_Width;	// 屏幕寬度
int			g_Height;	// 屏幕長度
POINT		g_Spt;		// 起始座標
POINT		g_Ept;		// 瞬時座標
UINT_PTR	g_TimerID;	// 定時器ID
HWND		g_hWnd;		// 全局窗口句柄
HFONT		g_FontL;	// 大字體											退出時銷毀
HFONT		g_FontS;	// 小字體											退出時銷毀
LOGFONT		g_lf;		// 初始化時使用

HDC			g_ScrDC;	// 原始桌面DC										退出時銷毀
HDC			g_BkgDC;	// 保存桌面的DC										退出時銷毀

HBITMAP		g_BkgBmp;	// 保存桌面的畫布									退出時銷毀
HBITMAP		g_BlkBmp;	// 內存畫布,用作滑塊貼圖							退出時銷毀

BOOL g_Drag;			// 是否在拖動滑塊
--------------------------------------------------------------------------------------------------------------------------------------- .cpp
// MetroOff.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "MetroOff.h"


// 全局变量:
HINSTANCE			g_hInst;			// 当前实例

// 此代码模块中包含的函数的前向声明:
ATOM			MyRegisterClass(HINSTANCE, LPTSTR);
BOOL			InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	MSG msg;

	// 执行应用程序初始化:
	if (!InitInstance(hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	// 主消息循环:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int) msg.wParam;
}

//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(hInstance, _T("MetroOff.ico"));
	wc.hCursor       = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = szWindowClass;

	return RegisterClass(&wc);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
    TCHAR szTitle[MAX_LOADSTRING] = _T("");		// 标题栏文本
    TCHAR szWindowClass[MAX_LOADSTRING] = _T("MetroOff");	// 主窗口类名

    g_hInst = hInstance; // 将实例句柄存储在全局变量中

    // 在应用程序初始化期间,应调用一次 SHInitExtraControls 以初始化
    // 所有设备特定控件,例如,CAPEDIT 和 SIPPREF。
    SHInitExtraControls();

    //如果它已经在运行,则将焦点置于窗口上,然后退出
    hWnd = FindWindow(szWindowClass, szTitle);	
    if (hWnd) 
    {
        // 将焦点置于最前面的子窗口
        // “| 0x00000001”用于将所有附属窗口置于前台并
        // 激活这些窗口。
        SetForegroundWindow((HWND)((ULONG) hWnd | 0x00000001));
        return 0;
    } 

    if (!MyRegisterClass(hInstance, szWindowClass))
    {
    	return FALSE;
    }

    hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, SW_HIDE);
    UpdateWindow(hWnd);

	// 加入初始化代碼
	g_Profile.isLoadImage = (BOOL)GetPrivateProfileInt(_T("Load"), _T("Bool"), 0, PROFILE);
	GetPrivateProfileString(_T("Image"), _T("ScreenOff"),	_T(""), g_Profile.szScreenOff,	MAX_PATH, PROFILE);
	GetPrivateProfileString(_T("Image"), _T("Reboot"),		_T(""), g_Profile.szReboot,		MAX_PATH, PROFILE);
	GetPrivateProfileString(_T("Image"), _T("ShutDown"),	_T(""), g_Profile.szShutDown,	MAX_PATH, PROFILE);
	g_Profile.clrScreenOff	= (COLORREF)GetPrivateProfileInt(_T("Color"), _T("ScreenOff"),	47746, PROFILE);
	g_Profile.clrReboot		= (COLORREF)GetPrivateProfileInt(_T("Color"), _T("Reboot"),		14851176, PROFILE);
	g_Profile.clrShutDown	= (COLORREF)GetPrivateProfileInt(_T("Color"), _T("ShutDown"),	13260, PROFILE);
	g_Profile.Status		= (int)GetPrivateProfileInt(_T("Initial"),	  _T("Status"),		0,		  PROFILE);

	g_Width  = GetSystemMetrics(SM_CXSCREEN);
	g_Height = GetSystemMetrics(SM_CYSCREEN);
	g_Pos    = g_Height / 2;
	g_Spt.x  = 0;
	g_Spt.y  = 0;
	g_Ept.x  = 0;
	g_Ept.y  = 0;
	g_TimerID = 0;
	g_hWnd   = hWnd;
	g_Drag = FALSE;

	// 設置字體
	memset(&g_lf, 0, sizeof(LOGFONT));
	g_lf.lfQuality = CLEARTYPE_QUALITY;
	g_lf.lfHeight  = g_Width/5;
	g_lf.lfWeight  = g_Width/10;
	g_FontL = CreateFontIndirect(&g_lf);

	g_lf.lfHeight = g_Width/16;
	g_lf.lfWeight = g_Width/16;
	g_FontS = CreateFontIndirect(&g_lf);

	// 獲取屏幕圖像
	g_ScrDC  = GetDC(NULL);
	g_BkgBmp = CreateCompatibleBitmap(g_ScrDC, g_Width, g_Height);
	g_BkgDC  = CreateCompatibleDC(g_ScrDC);
	SelectObject(g_BkgDC, g_BkgBmp);
	BitBlt(g_BkgDC, 0, 0, g_Width, g_Height, g_ScrDC, 0, 0, SRCCOPY);

	if (g_Profile.isLoadImage)
	{
		switch (g_Profile.Status)
		{
		case 0:
			g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szScreenOff));
			break;

		case 1:
			g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szShutDown));
			break;

		case 2:
			g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szReboot));
			break;

		default:
			break;
		}
	}
	else
	{
		g_BlkBmp = CreateCompatibleBitmap(g_ScrDC, g_Width, g_Height);
	}

	// 窗口全屏化
	ShowWindow(hWnd, SW_SHOW);

	RECT rc;
	GetWindowRect(hWnd, &rc);
	SHFullScreen(hWnd, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON);
	HWND hWndCB = ::SHFindMenuBar(hWnd);
	ShowWindow(hWndCB, SW_HIDE);

	MoveWindow(hWnd, 
		rc.left, 
		rc.top - g_Width / 240 * 26, 
		rc.right, 
		rc.bottom + g_Width / 240 * 26, 
		TRUE);

    return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    static SHACTIVATEINFO s_sai;
	
    switch (message) 
    {
        case WM_CREATE:
            // 初始化外壳程序激活信息结构
            memset(&s_sai, 0, sizeof (s_sai));
            s_sai.cbSize = sizeof (s_sai);
            break;

        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            
            // TODO: 在此添加任意绘图代码...
			DrawUI(hdc, g_Profile.Status, g_Pos);
            
            EndPaint(hWnd, &ps);
            break;

		case WM_ERASEBKGND:
			return 0;
			break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

		case WM_QUIT:
			ReleaseDC(NULL, g_ScrDC);
			DeleteDC(g_BkgDC);
			DeleteObject(g_BkgBmp);
			if (g_Profile.isLoadImage)
			{
				DeleteObject(g_BlkBmp);
			}
			DeleteObject(g_FontL);
			DeleteObject(g_FontS);

			break;

        case WM_ACTIVATE:
            // 向外壳程序通知我们的激活消息
            SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE);
            break;

        case WM_SETTINGCHANGE:
            SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai);
            break;

		case WM_LBUTTONDOWN:
			if (HIWORD(lParam) < g_Pos)
			{
				g_Drag = TRUE;

				if (g_Spt.x == 0)
				{
					g_Spt.x = LOWORD(lParam);
					g_Spt.y = HIWORD(lParam);
				}
			}

			if (g_TimerID != 0)
			{
				KillTimer(NULL, g_TimerID);
				g_TimerID = 0;
			}
			break;

		case WM_MOUSEMOVE:
			if (g_Drag)
			{
				g_Ept.x = LOWORD(lParam);
				g_Ept.y = HIWORD(lParam);

				g_Pos = g_Ept.y - g_Spt.y + g_Height/2;

				if (g_Pos > g_Height)
				{
					g_Pos = g_Height;
				}
				else if (g_Pos < 0)
				{
					g_Pos = 0;
				}

				InvalidateRect(hWnd, NULL, FALSE);
				UpdateWindow(hWnd);
			}

			break;

		case WM_LBUTTONUP:
			if (g_Drag)
			{
				g_Ept.x = LOWORD(lParam);
				g_Ept.y = HIWORD(lParam);

				g_Pos = g_Ept.y - g_Spt.y + g_Height/2;

				if (g_Pos > g_Height)
				{
					g_Pos = g_Height;
				}
				else if (g_Pos < 0)
				{
					g_Pos = 0;
				}

				POINT Dist;
				Dist.x = g_Ept.x - g_Spt.x;
				Dist.y = g_Ept.y - g_Spt.y;

				if (Dist.x < 0)
				{
					Dist.x = -Dist.x;
				}
				if (Dist.y < 0)
				{
					Dist.y = -Dist.y;
				}

				if (Dist.x < 16 && Dist.y < 16)
				{
					g_Profile.Status += 1;
					if (g_Profile.Status > 2)
					{
						g_Profile.Status = 0;
					}

					DeleteObject(g_BlkBmp);
					switch (g_Profile.Status)
					{
					case 0:
						g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szScreenOff));
						break;

					case 1:
						g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szShutDown));
						break;

					case 2:
						g_BlkBmp = SHLoadImageFile(W2T(g_Profile.szReboot));
						break;

					default:
						break;
					}
				}
				g_TimerID = SetTimer(NULL, 0, TimeInterval, TimerProc);
				g_Drag = FALSE;

				InvalidateRect(hWnd, NULL, FALSE);
				UpdateWindow(hWnd);
			}
			break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

void ShutDownWM()
{
	typedef int(*lpAPIFun)(BOOL);
	lpAPIFun HTCUtilDeviceOff;

	HINSTANCE hDll = LoadLibrary(_T("HTCUtil.dll"));

	if (hDll != NULL)
	{
		HTCUtilDeviceOff = (lpAPIFun)GetProcAddress(hDll, _T("HTCUtilDeviceOff"));

		if (HTCUtilDeviceOff != NULL)
		{
			HTCUtilDeviceOff(TRUE);
		}
		else
		{
			PostQuitMessage(0);
		}
	}
	else
	{
		PostQuitMessage(0);
	}

	FreeLibrary(hDll);
}

void FillSolidRect(HDC hDC, RECT rect, COLORREF clr)
{
	SetBkColor(hDC, clr);
	ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
}

void DrawUI(HDC hDC, int type, int Distance)
{
	// 創建內存畫布,並將屏幕背景貼到內存畫布上
	HDC MemDC = CreateCompatibleDC(NULL);
	HBITMAP MemBmp = CreateCompatibleBitmap(g_ScrDC, g_Width, g_Height);
	SelectObject(MemDC, MemBmp);
	BitBlt(MemDC, 0, 0 , g_Width, g_Height, g_BkgDC, 0 , 0, SRCCOPY);

	// 滑塊貼圖相關操作
	HDC blkDC = CreateCompatibleDC(NULL);	// 創建滑塊內存DC
	SelectObject(blkDC, g_BlkBmp);
	TCHAR strInfo[] = _T("向下滑动以关机");	// 初始化說明文字

	RECT rc;
	rc.left = 0;
	rc.right = g_Width;
	rc.top = 0;
	rc.bottom = g_Height;

	switch (type)
	{
	case 0:			// 關屏
		if (!g_Profile.isLoadImage)
		{
			FillSolidRect(blkDC, rc, g_Profile.clrScreenOff);
		}
		wsprintf(strInfo, _T("向下滑动以关屏"));
		break;

	case 1:			// 關機
		if (!g_Profile.isLoadImage)
		{
			FillSolidRect(blkDC, rc, g_Profile.clrShutDown);
		}
		wsprintf(strInfo, _T("向下滑动以关机"));
		break;

	case 2:			// 重啟
		if (!g_Profile.isLoadImage)
		{
			FillSolidRect(blkDC, rc, g_Profile.clrReboot);
		}
		wsprintf(strInfo, _T("向下滑动以重启"));
		break;

	default:
		break;
	}

	BitBlt(MemDC, 0, 0, g_Width, Distance, blkDC, 0, g_Height - Distance, SRCCOPY);

	// ------------------------------------------文字部份
	SetBkMode(MemDC, TRANSPARENT);
	SetTextColor(MemDC, RGB(255, 255, 255));
	SelectObject(MemDC, g_FontL);

	rc.left = g_Width/3;
	rc.top = Distance - g_Height/2;
	rc.bottom = Distance - g_Height/4;

	// 時間貼圖
	TCHAR str[8];
	LPSYSTEMTIME lpSystemTime = new SYSTEMTIME;
	GetLocalTime(lpSystemTime);
	wsprintf(str, _T("%02d:%02d"), lpSystemTime->wHour, lpSystemTime->wMinute);
	DrawText(MemDC, str, -1, &rc, DT_CENTER | DT_VCENTER);

	// 文字貼圖
	rc.left = 0;
	rc.top = Distance - g_Height/16;
	rc.bottom = Distance;
	SelectObject(MemDC, g_FontS);
	DrawText(MemDC, strInfo, -1, &rc, DT_CENTER | DT_VCENTER);

	// 完成貼圖
	BitBlt(hDC, 0, 0, g_Width, g_Height, MemDC, 0, 0, SRCCOPY);

	// 清理
	DeleteDC(MemDC);
	DeleteDC(blkDC);
	DeleteObject(MemBmp);

	if (Distance >= g_Height)
	{
		switch (type)
		{
		case 0:			// 關屏
			ReleaseDC(NULL, g_ScrDC);
			DeleteDC(g_BkgDC);
			DeleteObject(g_BkgBmp);
			if (g_Profile.isLoadImage)
			{
				DeleteObject(g_BlkBmp);
			}
			DeleteObject(g_FontL);
			DeleteObject(g_FontS);

			SetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
			exit(0);

			break;

		case 1:			// 關機
			ShutDownWM();
			break;

		case 2:			// 重啟
			KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
			break;

		default:
			break;
		}
	}
	else if (Distance <= g_Height/4)
	{
		PostQuitMessage(0);
	}
}

void CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
	if (g_Pos == g_Height/2)
	{
		InvalidateRect(g_hWnd, NULL, FALSE);
		UpdateWindow(g_hWnd);
		g_Spt.x = 0;
		KillTimer(NULL, g_TimerID);
	}
	else
	{
		g_Pos = ((g_Pos - g_Height/2)*7)/8 + g_Height/2;

		InvalidateRect(g_hWnd, NULL, FALSE);
		UpdateWindow(g_hWnd);
	}
}

由於用到了HTCUtil,因此關機只能用於HTC機型,其他機型只能實現休眠。

轉載請注明http://www.cnblogs.com/ZzzZzz/原創。

原文地址:https://www.cnblogs.com/ZzzZzz/p/2668409.html