/*------------------------------------
014 編程達人win32 API每日一練
第14個例子WM_DESTROY.C:回調函數---處理WM_DESTROY消息
WM_DESTROY消息
PostQuitMessage函數
注意:關閉窗口后,程序退出。
(c) www.bcdaren.com 編程達人
-----------------------------------------*/
#include <windows.h>
/***************回調函數******************/
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回調函數
/************程序入口 *********************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
……(略)
return msg.wParam;//msg.wParam 來自一條表示退出的消息,返回這個值給系統
}
/**************回調函數——消息處理過程*********/
//窗口回調函數
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC; //設備環境——繪圖的地方
PAINTSTRUCT ps; //繪圖結構體變量
RECT rect; //繪圖區范圍
switch (message)
{
case WM_CREATE: //創建窗口消息
//return 0;
break; //也可以
case WM_PAINT://繪圖函數,在窗口上繪圖!
hDC=BeginPaint(hwnd, &ps);
//獲得客戶區大小
GetClientRect(hwnd, &rect);
//繪制字符串
TextOut(hDC, 200, 200, TEXT("愛達人!"), lstrlen(TEXT("愛達人!")));
//繪制橢圓圖形
Ellipse(hDC, 250, 250, 1200, 500);
//繪制格式化文本,客戶區中間垂直居中對齊
DrawText(hDC, TEXT("我的第一個窗口程序!"), -1, &rect,DT_CENTER |
DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY://處理退出消息
//繪制橢圓圖形
//Ellipse(hDC, 250, 250, 1200, 500);//測試
PostQuitMessage(0);//此消息直接進入消息隊列的頭部!默認情況下,
//DefWindowProc函數調用DestroyWindow函數來銷毀窗口。
break;
//default: //可以放在最后
//return DefWindowProc(hwnd, message, wParam, lParam);
}
//return 0;
//調用默認窗口過程以為應用程序未處理的任何窗口消息提供默認處理
return DefWindowProc(hwnd, message, wParam, lParam);
}
/**************注意*******************
/*
WM_DESTROY消息:窗口銷毀后(調用DestroyWindow()后),消息隊列添加WM_DESTROY消息。
流程:用戶通過點擊關閉程序按鈕后,消息隊列增加一條消息WM_CLOSE,然后程序從消息隊列中取走WM_CLOSE,WM_CLOSE消息的默認處理方式為調用DestroyWindow()向窗口發送一個WM_DESTROY消息,消息隊列增加WM_DESTROY,主程序消息循環再次取出后交給Windows系統,Windows系統調用窗口過程處理WM_DESTROY消息,處理方式為調用ostQuitMessage(),在消息隊列中添加WM_QUIT標記,消息循環獲取WM_QUIT后退出消息循環,程序退出。
如果窗口過程不處理WM_CLOSE消息,默認情況下,默認窗口過程DefWindowProc函數同樣是調用DestroyWindow函數。
********************************************
PostQuitMessage函數:向系統指示線程已請求終止(退出)。通常用于響應WM_DESTROY消息。
void PostQuitMessage(
int nExitCode //指定的退出碼,是一個整數值。這個退出碼通常用來表示程序執行的結果或狀態。此值用作WM_QUIT消息的wParam參數。
);
備注
PostQuitMessage函數添加一個WM_QUIT退出標記到線程的消息隊列并立即返回;這個函數只是向系統表明這個線程在將來的某個時候請求退出。
當線程從它的消息隊列中檢索WM_QUIT標記時,它應該退出它的消息循環并將控制權返回給系統。返回到系統的退出值必須是WM_QUIT消息的wParam參數。
(有些書上將WM_QUIT視為一個消息,插入到消息隊列頭,然后立即退出,消息隊列中剩余的消息不會被處理,雖然比較形象,但是不太嚴謹,WM_QUIT其實是一個退出標記。)。
*/
注意
1.本例在關閉窗口后,終于可以正常退出程序了。原因就在于窗口過程WndProc處理了WM_DESTROY消息,向窗口消息隊列添加一個WM_QUIT退出標記。消息循環GetMessage函數獲取WM_QUIT后返回值為0,退出消息循環,進而退出進程。
2.動手實驗:在WM_DESTROY消息處理模塊添加一個繪制橢圓的函數:
Ellipse(hDC, 250, 250, 1200, 500);
編譯器編譯后提示:error C4700: 使用了未初始化的局部變量“hDC”。
錯誤原因:窗口過程中設置的hDC為局部變量,在WM_PAINT消息模塊中使用,但是在WM_DETROY模塊無法識別,說明局部變量在窗口過程中不可以跨消息模塊使用,作用域僅限一個消息模塊內。記得水面以下的冰山部分并不是由我們實現的,Windows程序是消息驅動的程序。
解決方案:將變量定義為全局區的靜態變量static HDC hDC;如果一個變量需要跨消息模塊使用,請將其定義為static變量。但是在這里并不建議將hDC定義為static變量,因為hDC會持續占用大塊內存空間,隨用隨取就可以了。
在Ellipse函數處下斷點,當關閉窗口后,執行Ellipse函數調用并不會顯示窗口。原因很簡單,因為窗口已經不存在了。
/*----------------------------------------
015 編程達人win32 API每日一練
第15個例子WM_CLOSE.C:回調函數---處理WM_CLOSE消息
WM_CLOSE消息
DestroyWindow函數
注意:關閉窗口后,程序退出。
(c) www.bcdaren.com 編程達人
----------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回調函數
/**************程序入口 **********
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
static TCHAR szAppName[]=TEXT("HelloWin"); // 窗口類名
……(略)
return msg.wParam;//msg.wParam 來自一條表示退出的消息,返回這個值給系統
}
/************回調函數——消息處理過程************/
//窗口回調函數
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC; //設備環境——繪圖的地方
PAINTSTRUCT ps; //繪圖結構體變量
RECT rect; //繪圖區范圍
switch (message)
{
case WM_CREATE: //創建窗口消息
return 0;
case WM_PAINT://繪圖函數,在窗口上畫畫兒!
hDC=BeginPaint(hwnd, &ps);
//獲得客戶區大小
GetClientRect(hwnd, &rect);
//繪制字符串
TextOut(hDC, 200, 200, TEXT("愛達人!"), lstrlen(TEXT("愛達人!")));
//繪制橢圓圖形
Ellipse(hDC, 250, 250, 1200, 500);
//繪制格式化文本,客戶區中間垂直居中對齊
DrawText(hDC, TEXT("我的第一個窗口程序!"), -1, &rect,DT_CENTER |
DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &ps);
return 0;
case WM_CLOSE:
/*
1、一般是響應WM_CLOSE:調用DestroyWindow(),DestroyWindow()又發送WM_DESTROY消息;響應WM_DESTROY時,PostQuitMessage()函數發送WM_QUIT標記到消息隊列,GetMessage()發現WM_QUIT時,退出程序
2、一個窗口或者應用程序應該被關閉時發出WM_CLOSE消息,當接收到WM_CLOSE消息時,
如果你愿意,可以通過MessageBox向用戶提出是否真的要退出。
3、用戶選擇退出或不退出。*/
if (IDYES==MessageBox(hwnd,TEXT("是否真的要退
出!),TEXT("OK?"),MB_YESNO))
{
DestroyWindow(hwnd);
break;
}
else
break;//不退出,并且什么都沒做。
case WM_DESTROY://處理退出消息
PostQuitMessage(0);//此消息直接進入消息隊列的頭部!
break;
default: //可以放在最后
return DefWindowProc(hwnd, message, wParam, lParam); //調用默認窗口過程以為應用程序未處理的任何窗口消息提供默認處理
}
return 0;
//return DefWindowProc(hwnd, message, wParam, lParam); //調用默認窗口過程以為應用程序未處理的任何窗口消息提供默認處理
}
/***************注意***********
WM_CLOSE消息:作為窗口或應用程序應終止的信號發送。
#define WM_CLOSE 0x0010
返回值類型:LRESULT
如果應用程序處理此消息,則應返回零。
備注
應用程序可以在銷毀窗口之前提示用戶進行確認,方法是處理WM_CLOSE消息并僅在用戶確認選擇后才調用DestroyWindow函數。
默認情況下,DefWindowProc函數調用DestroyWindow函數來銷毀窗口。
***********************************
DestroyWindow函數:銷毀指定的窗口。該函數將WM_DESTROY和WM_NCDESTROY消息發送到窗口以將其停用并從中移出鍵盤焦點。
該函數還破壞窗口的菜單,刷新線程消息隊列,破壞計時器,刪除剪貼板所有權,并中斷剪貼板查看器鏈(如果窗口位于查看器鏈的頂部)。
如果指定的窗口是父窗口或所有者窗口,則DestroyWindow在銷毀父窗口或所有者窗口時會自動銷毀關聯的子窗口或所有者窗口。該函數首先銷毀子窗口或所有者窗口,然后銷毀父窗口或所有者窗口。DestroyWindow還會破壞由CreateDialog函數創建的無模式對話框。
BOOL DestroyWindow(
HWND hWnd //銷毀窗口的句柄
);
返回值類型:布爾
如果函數成功,則返回值為非零。
如果函數失敗,則返回值為零。要獲取擴展的錯誤信息,請調用GetLastError。
*/
點擊“關閉”系統菜單后,彈出對話框窗口,如圖2-6所示:
圖2-6 WM_CLOSE消息
注意
讀者可能會有疑問,當用戶點擊系統菜單“關閉”窗口時,是如何產生并獲取WM_CLOSE消息的呢?答案是Windows操作系統獲取“關閉”系統菜單消息后,再發送一個WM_CLOSE消息。這個問題,我們將在下一節消息機制中詳細講解。
/*-----------------------------
016 編程達人win32 API每日一練
第16個例子WM_SIZE.C:窗口過程---處理WM_SIZE消息
WM_SIZE消息---調整客戶區大小
InvalidateRect函數
注意:關閉窗口后,程序退出。
(c) www.bcdaren.com 編程達人
-------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回調函數
/************程序入口 *************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
static TCHAR szAppName[]=TEXT("HelloWin"); // 窗口類名
……(略)
return msg.wParam;//msg.wParam 來自一條表示退出的消息,返回這個值給系統
}
/*********回調函數——消息處理過程***********/
//窗口過程回調函數
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC; //設備環境——繪圖的地方
PAINTSTRUCT ps; //繪圖結構體變量
RECT rect; //繪圖區范圍
static int cxClient,cyClient;//客戶區的寬度和高度,定義為靜態局部變量
switch (message)
{
case WM_CREATE: //創建窗口消息
//return 0;
break; //也可以
case WM_SIZE://更改窗口客戶區大小的消息
GetClientRect(hwnd, &rect);//等價于lParam參數的作用
InvalidateRect(hwnd, &rect, TRUE);//TRUE重繪窗口客戶區背景
cxClient=LOWORD(lParam);//客戶區的新寬度
cyClient=HIWORD(lParam);//客戶區的新高度
break;
case WM_PAINT://繪圖函數,在窗口上畫畫兒!
hDC=BeginPaint(hwnd, &ps);
//獲得客戶區大小
GetClientRect(hwnd, &rect);
//繪制字符串---跟隨客戶區尺寸的變化而變化
//TextOut(hDC, 200, 200, TEXT("愛達人!"), lstrlen(TEXT("愛達人!
")));//對比測試
TextOut(hDC, cxClient / 5, cyClient / 5, TEXT("愛達人!"),
lstrlen(TEXT("愛達人!")));
//繪制橢圓圖形---跟隨客戶區尺寸的變化而變化
//Ellipse(hDC, 250, 250, 1200, 500);//對比測試
Ellipse(hDC, cxClient / 4 , cyClient / 4 , cxClient / 4 * 3,
cyClient / 4 * 3);
//繪制格式化文本,客戶區中間垂直居中對齊
DrawText(hDC, TEXT("我的第一個窗口程序!"), -1, &rect,DT_CENTER |
DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &ps);
break;
case WM_CLOSE:
if (IDYES==MessageBox(hwnd,TEXT("是否真的要退出!
"),TEXT("OK?"),MB_YESNO))
{
DestroyWindow(hwnd);
break;
}
else
break;//不退出,并且什么都沒做。
case WM_DESTROY://處理退出消息
PostQuitMessage(0);//此消息直接進入消息隊列的頭部!
break;
default: //可以放在最后
return DefWindowProc(hwnd, message, wParam, lParam);//調用默認窗口過程
}
return 0;
//return DefWindowProc(hwnd, message, wParam, lParam); //調用默認窗口過程
}
/*******************注意***************
WM_SIZE消息:當主窗口的客戶區部分大小改變時,我們的應用程序將接收到 WM_SIZE 消息。
lParam 的高字部分是客戶區的高,低字部分是客戶區的寬。
wParam請求的調整大小類型。此參數可以是下列值之一。
SIZE_MAXHIDE:當某個其他窗口最大化時,消息將發送到所有彈出窗口。
SIZE_MAXIMIZED:窗口已最大化。
SIZE_MAXSHOW:當某些其他窗口恢復到原來的大小時,消息將發送到所有彈出窗口。
SIZE_MINIMIZED:窗口已最小化。
SIZE_RESTORED:窗口已調整大小,但SIZE_MINIMIZED或SIZE_MAXIMIZED值均不適用。
說明:
lParam和GetClientRect的功能一樣,有時候WM_SIZE的效率要比使用GetClientRect高.
可以在程序中使用WM_SIZE來保存客戶區的大小方便以后使用.
*******************************************
InvalidateRect函數:向指定的窗體更新區域添加一個矩形,然后窗口客戶區域的這一部分將被重新繪制。
BOOL InvalidateRect(
HWND hWnd, //新區域已更改的窗口的句柄。如果此參數為NULL,
//則系統將使所有窗口(不僅是此應用程序的窗口)無效并重新繪制
//所有窗口,并在函數返回之前發送WM_ERASEBKGND和WM_NCPAINT消
//息。不建議將此參數設置為NULL。
const RECT *lpRect,//指向RECT結構的指針,該結構包含要添加到更新區域的矩形的客
//戶坐標。如果此參數為NULL,則整個工作區將添加到更新區域。
BOOL bErase //指定在處理更新區域時是否要擦除更新區域內的背景。
//如果此參數為TRUE,則在調用BeginPaint函數時將擦除背景。
//如果此參數為FALSE,則背景保持不變。
);
*/ 運行結果:
圖2-7 WM_SIZEE消息
注意
1.讀者是否還記得,當我們執行ShowWindow函數時會向消息隊列發送一個WM_SIZE消息。WM_SIZE消息用于向窗口發送尺寸改變的消息。當窗口的大小發生變化時,系統會生成并發送WM_SIZE消息給窗口,使程序能夠對窗口尺寸的改變做出響應。WM_SIZE消息的lParam 參數的高字部分是客戶區的高,低字部分是客戶區的寬。wParam參數為請求的調整大小類型。每個Windows消息都有附屬的wParam參數和lParam 參數。不同消息的wParam參數和lParam 參數的含義是不同的。我們將在2.4節中詳細講解。
2.細心的讀者會發現,本例中的窗口是可以通過鼠標拖動改變窗口的大小,同時窗口客戶區繪制的圖形和文本也隨之而改變相應的位置。請注意處理WM_PAINT消息時的GDI繪圖函數,繪制圖形和文本的坐標位置是和窗口客戶區等比例的。首先定義static變量cxClient,cyClient,接著在處理WM_SIZE消息時通過lParam參數獲取窗口客戶區的高和寬。當然也可以通過GetClientRect函數獲取窗口客戶區的寬和高,使用其中一個方法就可以了。
3.請讀者對比測試一下,如果將繪制文本和橢圓的坐標和區域設置為固定值,顯示效果如何。
Windows開始菜單是Windows系統中圖形用戶界面的基本組成部分,它包含了Windows系統的大部分主要內容。我們可以通過敲擊鍵盤上的Windows徽標或點擊桌面左下角的Windows圖標打開Windows開始菜單。但有時我們會遇到問題,Win10開始菜單點擊無效打不開怎么辦?我們該如何解決這一問題?
Win10開始菜單呼不出來點擊無反應,一般都是因為Windows資源管理器所導致的,此時只需重啟Windows資源管理器即可。還有一些少見的原因導致Win10開始菜單打不開,例如:系統文件損壞或缺失、User Manager服務被禁用或開始菜單本身的問題。
那我們該如何解決Win10開始菜單點擊無反應這一問題?針對以上的這些原因,本文提供了相應的4種解決方法,您可以按照以下提供的方法進行解決。
一般Win10開始菜單點擊無效都是因為Windows資源管理器所引起的,我們只需重新啟動Windows資源管理器即可解決開始菜單點擊沒反應這一問題。
1. 按鍵盤上的“Ctrl + Shift + Esc”鍵,打開任務管理器。
2. 在“進程”選項卡中,找到“Windows資源管理器”,并單擊右下角的“重新啟動”按鈕。
等待重啟完成后,您可以再次點擊Win10開始菜單查看問題是否解決,若沒有您可以繼續嘗試以下的方法。
User Manager服務是用于管理Windows用戶程序的,若將其禁用,可能會導致某些程序無法正常的啟動。若Win10開始菜單點擊無效,可以查看User Manager服務是否被禁用,若被禁用可以將其啟動。
1. 按“Windows + R”鍵,打開運行框并輸入“services.msc”,再單擊“確定”。
2. 進入服務窗口中,找到“User Manager”,并右鍵單擊它選擇“屬性”。
3. 在彈出的User Manager屬性窗口,將“啟動類型”設置為“自動”,再單擊“確定”。
若是Win10開始菜單本身的問題,我們可以使用PowerShell重新安裝開始菜單。具體操作步驟如下:
1. 按“Windows + X”鍵,然后單擊“Windows PowerShell(管理員)”,再單擊“是”。
2. 在彈出的窗口中,輸入以下命令并按下回車鍵。
命令:“Get-AppxPackage -AllUsers| Foreach {Add-AppxPackage -DisableDevelopmentMode -Register “$($_.InstallLocation)\AppXManifest.xml”}”
說明:該命令會將Win10內置的默認應用進行重新安裝。如果有錯誤提示,不必理會,等待執行完成后,再重啟電腦即可。
若以上的方法都嘗試了,Win10開始菜單還是打不開,那有可能是系統文件損壞了。您可以嘗試修復系統文件,以解決Win10開始菜單點擊無效這一問題。您可以按照以下步驟進行操作:
1. 按“Windows + X”鍵,然后單擊“Windows PowerShell(管理員)”,再單擊“是”。
2. 然后,依次輸入以下命令,并在每個命令輸入完成按回車鍵。
Dism /Online /Cleanup-Image /ScanHealth (掃描全部系統文件并與官方系統文件對比)
Dism /Online /Cleanup-Image /CheckHealth
DISM /Online /Cleanup-image /RestoreHealth (將與官方系統源文件不同的進行還原)
3. 執行完成后重新啟動電腦,再次進入PowerShell并輸入“sfc /scannow”并按回車鍵。該命令會掃描系統文件的完整性,并對有問題的文件進行修復。
若以上的4種方法,都嘗試了Win10開始菜單還是打不開,您可以先對系統中重要的數據進行文件備份,再重新安裝系統,再將原系統中的數據還原到新系統。
以上就是有關“Win10開始菜單點擊無效打不開怎么辦?”問題的4種解決方法!一般重啟Windows資源管理器即可解決大部分Win10開始菜單點擊無反應的問題。若重啟Windows資源管理器無法解決問題,您可以依次嘗試本文提供的其他方法。