技术标签: C++ c++ Linux win32 linux
在解决方案中添加一个控制台程序–》空项目
添加源代码
添加代码并编译执行
测试:成功打印
在解决方案中添加一个项目
测试:制作窗口成功
在解决方案中添加一个新项目 -》静态库程序
创建完后设置为启动项目
运行测试:无法运行
有入口 --> 可执行 --> 程序的最终文件可以进内存
没有入口 --> 无法执行
在解决方案中添加一个新项目 -》动态库程序
测试:动态库不能独立运行,需要依赖其他进程
三种应用程序的对比
CL.EXE 和 LINK.EXE 可执行程序 在安装的路径下的 VC下bin
(kernel32.dll, user32.dll, gdi32.dll 三个动态库的路径) 在 C:\Windows\System32 下
(几个重要的头文件所在的路径) C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include
窗口程序入口函数
句柄:
是一个用来找到内存的东西,但绝对不是指针
提示框
测试代码:hello.cpp
#include <windows.h>
int WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow)
{
int ret = MessageBox(NULL, "HELLO WORLD", "INFORMATION", MB_ABORTRETRYIGNORE | MB_ICONERROR);
if (ret == IDABORT) {
}
else if (ret == IDRETRY) {
}
else {
}
return 0;
}
完整的编译链接的过程:
CL.EXE
.c/.cpp -----------> .obj|
| LINK.EXE
|---------------------------> .exe
RC.EXE |
.rc -------------> .res|
脚本文件:hello.rc 图片名称为small.ico
100 ICON small.ico
操作步骤:
cl.exe -c hello.c -->Hello.c
rc.exe Hello.rc --> Hello.res
link.exe Hello.obj Hello.res user32.lib --> Hello.exe
编写窗口程序的步骤:
参考代码:
#include <windows.h>
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
//回调函数
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
//注册窗口类(系统内核中写入数据)
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "Main";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
//内存中创建窗口
HWND hWnd = CreateWindowEx(0,"Main","windows",WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,hIns,NULL);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
//消息循环
MSG nMsg = {
0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);//将消息交给窗口处理函数(自己定义的那个函数)
}
return 0;
}
ASC - 7位代表一个字符 128个字符
ASCII - 美国国家信息标准交换码(扩展ASC码) 8位代码一个字符,256个字符
MBCS - 多字节字符编码
DBCS - 单双字节混合编码(没有统一标准) 例 A 01 我 0203 是 0405 程 0607 序 0809 源0A0B
UNICODE -万国码
utf-8 : unix 系统
utf-16: 所有字符统统按照两个字节来编码
参考代码:
//#define UNICODE
#include <windows.h>
#include <stdio.h>
#define WIDECHAR
void T_char() {
const TCHAR* pszText = __TEXT("hello");
//wchar_t * pszText = L"hello";
#ifdef UNICODE
wprintf(L"%s\n",pszText);
#else
printf("单:%s\n",pszText);
#endif
/*
#ifdef WIDECHAR
wchar_t* pszText = L"hello";
wprintf(L"%s\n", pszText);
#else
const char* pszText = "hello";
printf("单:%s\n", pszText);
#endif
*/
}
void C_char() {
const char* pszText = "hello char";
printf("%s\n", pszText);
}
void W_char() {
const wchar_t* pszText = L"hello wcahr"; //宽字节字符串
int nlen = wcslen(pszText);
wprintf(L"%s %d\n", pszText, nlen);
}
void PrintUnicode() {
const wchar_t* pszText = L"反倒是房价快速拉升国家";
//wprintf(L"%s\n", pszText); //对汉字打印支持不完善
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hOut, pszText, wcslen(pszText), NULL, NULL);
}
int main(void) {
//T_char();
//C_char();
//W_char();
PrintUnicode();
return 0;
}
项目属性 :
Unicode字符集(IDE开发工具,增加UNICODE宏的定义)
多字节字符集(IDE开发工具,不增加UNICODE宏的定义)
<winnt.h> 中的代码
#ifdef UNICODE
typedef wchar_t TCHAR;
#define __TEXT(quote) L##quote
#else
typedef char TCHAR;
#define __TEXT(quote) quote
#endif
涉及字符集的集中类型:
TCHAR char/wchar_t
LPSTR char*
LPCSTR const char*
LPWSTR wchar_t*
LPCWSTR const wchar_t*
LPTSTR TCHAR* (char*/wchar_t*)
LPCTSTR const TCHAR*
打印字符到控制台
BOOL WINAPI WriteConsole(
HANDLE hConsoleOutput, // 标准输出句柄
const VOID *lpBuffer, // 准备输出内容的buffer
DWORD nNumberOfCharsToWrite, // 准备输出字符串的长度
LPDWORD lpNumberOfCharsWritten,// 返回实际输出字符串的长度
LPVOID lpReserved // 备用参数 NULL
);
三个标准句柄:
标准输入句柄、标准输出句柄、标准错误句柄
HANDLE WINAPI GetStdHandle(
DWORD nStdHandle
);
nStdHandle的取值:
STD_INPUT_HANDLE
STD_OUTPUT_HANDLE
STD_ERROR_HANDLE
参考代码:BUTTON
#include <windows.h>
HINSTANCE g_hIns = 0; //接收当前程序实例句柄
void SysReg() {
//不需要注册,系统已经注册
HWND hWnd = CreateWindowEx(0, "BUTTON", "0K", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, g_hIns,NULL);
ShowWindow(hWnd, SW_SHOW);
}
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
SysReg();
return 0;
}
CreateWindowEx (推荐使用)
参考代码:
#include <windows.h>
HINSTANCE g_hInstance = 0;
void SysReg()
{
// 系统窗口类由系统注册,应用程序可以直接使用
// 创建窗口
HWND hWnd = CreateWindow("BUTTON","OK",WS_OVERLAPPEDWINDOW,
100,100,700,500,NULL,NULL,g_hInstance,NULL);
// 显示窗口
ShowWindow(hWnd,SW_SHOW);
// 消息循环
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
void AppReg()
{
WNDCLASS wcs = {
0};
wcs.cbClsExtra = 0;
wcs.cbWndExtra = 0;
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcs.hCursor = NULL;
wcs.hIcon = NULL;
wcs.hInstance = g_hInstance; /**************/
wcs.lpfnWndProc = DefWindowProc;
wcs.lpszClassName = "Main"; /**************/
wcs.lpszMenuName = NULL;
wcs.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
RegisterClass(&wcs);
CreateWindow("Main","Window",WS_OVERLAPPEDWINDOW,
100,100,700,500,NULL,NULL,g_hInstance,NULL);
}
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
SysReg();
return 0;
}
参考代码1:主窗口关闭后进程也关闭
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hIns = 0; //保存当前程序实例句柄
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch(msgID) {
case WM_DESTROY:
PostQuitMessage(0); //能够是GetMessage函数返回0
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//注册窗口类
void Register(LPSTR lpClassName, WNDPROC wndproc) {
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = g_hIns;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpClassName;
wc.lpszClassName = "Main";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) {
HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, 100, 100, 700, 500, NULL, NULL, g_hIns, NULL);
return hWnd;
}
//显示窗口
void Display(HWND hWnd){
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); //刷新窗口
}
//消息循环
void Message() {
MSG nMsg = {
0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
g_hIns = hIns;
Register("Main", WndProc);
HWND hWnd = CreateMain("Main", "window");
Display(hWnd);
Message();
return 0;
}
参考代码2:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hIns = 0; //保存当前程序实例句柄
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch(msgID) {
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//注册窗口类
void Register(LPSTR lpClassName, WNDPROC wndproc) {
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = g_hIns;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpClassName;
wc.lpszClassName = "Main";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) {
HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, 100, 100, 700, 500, NULL, NULL, g_hIns, NULL);
return hWnd;
}
//创建子窗口
HWND CreateChild(LPSTR lpClassName, LPSTR lpWndName, HWND hParent) {
HWND hChild = CreateWindowEx(0, lpClassName, lpWndName, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, hParent, NULL, g_hIns, NULL);
return hChild;
}
//显示窗口
void Display(HWND hWnd){
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); //刷新窗口
}
//消息循环
void Message() {
MSG nMsg = {
0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
g_hIns = hIns;
Register("Main", WndProc);
HWND hWnd = CreateMain("Main", "window");
Display(hWnd);
Register("Child",DefWindowProc);
HWND hChild1 = CreateChild("Child", "c1", hWnd);
HWND hChild2 = CreateChild("Child", "c2", hWnd);
MoveWindow(hChild1, 300, 100, 200, 200, FALSE);
MoveWindow(hChild2, 300, 100, 200, 200, FALSE);
Message();
return 0;
}
参考代码: winMsg.cpp
// 定义自定义消息
#define WM_MYMESSAGE WM_USER + 1001
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
HANDLE g_hOutput = 0; // 接收标准输出句柄
HWND g_hEdit = 0;
/*void OnCreate(HWND hWnd,LPARAM lParam)
{
CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
char* pszText = (char*)pcs->lpCreateParams;
MessageBox(hWnd,pszText,"Infor",MB_OK);
}*/
void OnCreate(HWND hWnd)
{
g_hEdit = CreateWindowEx(0,"EDIT","",WS_CHILD|WS_VISIBLE|WS_BORDER,
0,0,200,200,hWnd,NULL,g_hInstance,NULL);
// 自定义消息的发送位置任意
// 既可以使用SendMessage,也可以使用PostMessage
// SendMessage(hWnd,WM_MYMESSAGE,100,200);
PostMessage(hWnd,WM_MYMESSAGE,100,200);
}
void OnMyMessage(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char szText[256] = {
0};
sprintf(szText,"自定义消息被处理 - wParam:%d,lParam:%d\n",
wParam,lParam);
MessageBox(hWnd,szText,"Infor",MB_OK);
}
void OnSize(HWND hWnd,LPARAM lParam)
{
int nWidth = LOWORD(lParam);
int nHeight = HIWORD(lParam);
char szText[256] = {
0};
sprintf(szText,"WM_SIZE--宽:%d,高:%d\n",nWidth,nHeight);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
MoveWindow(g_hEdit,0,0,nWidth,nHeight,TRUE);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID){
case WM_MYMESSAGE:
OnMyMessage(hWnd,wParam,lParam);
break;
case WM_SIZE:
OnSize(hWnd,lParam);
break;
case WM_CREATE:
// OnCreate(hWnd,lParam);
OnCreate(hWnd);
break;
case WM_SYSCOMMAND:
// return 0;
// MessageBox(hWnd,"WM_SYSCOMMAND","Infor",MB_OK);
if(wParam==SC_CLOSE){
int nRet = MessageBox(hWnd,"是否退出?","提示",MB_YESNO);
if(nRet==IDYES){
// 什么也不写
}else{
return 0;
}
}
break;
case WM_DESTROY:
// PostQuitMessage(0); // GetMessage返回0?
// SendMessage(hWnd,WM_QUIT,0,0);
PostMessage(hWnd,WM_QUIT,0,0);
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
char* pszText = "Data";
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,pszText);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
/* while(1){
if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE))
{
// 有消息
if(GetMessage(&nMsg,NULL,0,0))
{ // 不是WM_QUIT
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}else{ // WM_QUIT
return;
}
}
else{
// 没有消息 做空闲处理
WriteConsole(g_hOutput,"OnIdle",6,NULL,NULL);
}
}*/
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
AllocConsole(); // 增加一个DOS窗口
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
HANDLE g_hOutput = 0; //保存标准输出句柄
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
参考代码:
//消息循环
void Message() {
MSG nMsg = {
0 };
/*
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
*/
while (1) {
if( PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE)){
//有消息
if (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
else {
return;
}
}
else {
//空闲处理
WriteConsole(g_hOutput, "OnIdld", 6, NULL, NULL);
}
}
}
参考代码:
void OnMyMessage(HWND hWnd, WPARAM wParam, LPARAM lParam) {
char szText[256] = {
0 };
sprintf(szText, "自定义消息被处理:wParam=%d,1Param=%d", wParam, lParam);
MessageBox(hWnd, szText, "Infor", MB_OK);
}
参考代码:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
HANDLE g_hOutput = 0;
int g_xPos = 100,g_yPos = 100;
void OnKeyDown(HWND hWnd,WPARAM wParam)
{
switch(wParam)
{
case 0X25:
g_xPos-=5;
break;
case 0X26:
g_yPos-=5;
break;
case 0X27:
g_xPos+=5;
break;
case 0X28:
g_yPos+=5;
break;
}
InvalidateRect(hWnd,NULL,TRUE);
char szText[256] = {
0};
sprintf(szText,"WM_KEYDOWN : %08X\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnKeyUp(HWND hWnd,WPARAM wParam)
{
char szText[256] = {
0};
sprintf(szText,"WM_KEYUP : %08X\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
TextOut(hdc,g_xPos,g_yPos,"Hello",5);
EndPaint(hWnd,&ps);
}
void OnChar(HWND hWnd,WPARAM wParam)
{
char szText[256] = {
0};
sprintf(szText,"WM_CHAR: %08X\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_CHAR:
OnChar(hWnd,wParam);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_KEYUP:
OnKeyUp(hWnd,wParam);
break;
case WM_KEYDOWN:
OnKeyDown(hWnd,wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码:
void OnKeyDown(HWND hWnd,WPARAM wParam)
{
switch(wParam)
{
case 0X25:
g_xPos-=5;
break;
case 0X26:
g_yPos-=5;
break;
case 0X27:
g_xPos+=5;
break;
case 0X28:
g_yPos+=5;
break;
}
InvalidateRect(hWnd,NULL,TRUE);
char szText[256] = {
0};
sprintf(szText,"WM_KEYDOWN : %08X\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_CHAR:
OnChar(hWnd,wParam);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_KEYUP:
OnKeyUp(hWnd,wParam);
break;
case WM_KEYDOWN:
OnKeyDown(hWnd,wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
练习:使用键盘的方向键控制字符串在窗口客户区移动。(15分钟)
// 假设按下 A
TranslateMessage(&nMsg)
{
if(nMsg.message != WM_KEYDOWN )
return ...;
(是WM_KEYDOWN)
根据nMsg.wParam(按键的虚拟键值),可以获取按下的按键
if(不是可见字符键)
return ...;
if(是可见字符键){
判断CapsLock键的状态
if(打开)
PostMessage(nMsg.hwnd,WM_CHAR,0X41,...);// A:0X41
else
PostMessage(nMsg.hWnd,WM_CHAR,0X61,...);// a:0X61
}
return ...;
}
练习:实现鼠标移动时字符串的跟随
WM_PAINT
WM_MOUSEMOVE
InvalidateRect()函数
// 定时器处理函数
VOID CALLBACK TimerProc(
__in HWND hwnd, // 窗口句柄
__in UINT uMsg, // 消息ID (只能是WM_TIMER)
__in UINT_PTR idEvent, // 定时器ID
__in DWORD dwTime // 当前计算机的系统时间
);
参考代码:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
HANDLE g_hOutput = 0;
int g_xPos = 0,g_yPos = 0;
void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char szText[256] = {
0};
sprintf(szText,"WM_LBUTTONDOWN-- 按键状态:%08X,鼠标坐标(%d,%d)\n",
wParam,LOWORD(lParam),HIWORD(lParam));
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char szText[256] = {
0};
sprintf(szText,"WM_LBUTTONUP-- 按键状态:%08X,鼠标坐标(%d,%d)\n",
wParam,LOWORD(lParam),HIWORD(lParam));
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
TextOut(hdc,g_xPos,g_yPos,"Hello",5);
EndPaint(hWnd,&ps);
}
void OnMouseMove(HWND hWnd,LPARAM lParam)
{
g_xPos = LOWORD(lParam);
g_yPos = HIWORD(lParam);
InvalidateRect(hWnd,NULL,FALSE);
}
void OnLButtonDblClk(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char szText[256] = {
0};
sprintf(szText,"WM_LBUTTONDBLCLK -- 按键状态:%08X,鼠标坐标(%d,%d)\n",
wParam,LOWORD(lParam),HIWORD(lParam));
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnMouseWheel(HWND hWnd,WPARAM wParam)
{
short nDelta = HIWORD(wParam);
char szText[256] = {
0};
sprintf(szText,"WM_MOUSEWHEEL: %d\n",nDelta);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_MOUSEWHEEL:
OnMouseWheel(hWnd,wParam);
break;
case WM_LBUTTONDBLCLK:
OnLButtonDblClk(hWnd,wParam,lParam);
break;
case WM_MOUSEMOVE:
// OnMouseMove(hWnd,lParam);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_LBUTTONUP:
OnLButtonUp(hWnd,wParam,lParam);
break;
case WM_LBUTTONDOWN:
OnLButtonDown(hWnd,wParam,lParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
HANDLE g_hOutput = 0;
void OnTimer(HWND hWnd,WPARAM wParam)
{
char szText[256] = {
0};
switch(wParam){
case 1001:
sprintf(szText,"窗口处理函数处理了定时器:%d\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
break;
case 1002:
sprintf(szText,"窗口处理函数处理了定时器:%d\n",wParam);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
break;
}
}
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
char szText[256] = {
0};
switch(idEvent){
case 1001:
sprintf(szText,"定时器处理函数处理了定时器:%d\n",idEvent);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
break;
case 1002:
sprintf(szText,"定时器处理函数处理了定时器:%d\n",idEvent);
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
break;
}
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_LBUTTONDOWN:
KillTimer(hWnd,1001);
KillTimer(hWnd,1002);
break;
case WM_TIMER:
OnTimer(hWnd,wParam);
break;
case WM_CREATE:
SetTimer(hWnd,1001,1000,NULL);
SetTimer(hWnd,1002,2000,TimerProc);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
创建 WinRes项目 添加资源文件—>添加菜单资源
选中WinRes.rc ,添加资源
添加加菜单资源
**编辑第一个菜单下拉选项 – 新建 id_new
编辑第二个菜单选项 退出 id_exit
菜单项分三种:
被点击后唯一功能就是 弹出下拉菜单(Popup风格)
被点击后能够发出消息
为分隔线(Separator)
新建和退出直接做一条分割线
参考代码:WinRes.cpp
#include <windows.h>
#include "resource.h"
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
HICON hIcon = LoadIcon(g_hInstance,(LPCSTR)IDI_ICON1);
DrawIcon(hdc,200,200,hIcon);
EndPaint(hWnd,&ps);
}
void OnCommand(HWND hWnd,WPARAM wParam)
{
switch(LOWORD(wParam))
{
case ID_NEW:
if(HIWORD(wParam)){
MessageBox(hWnd,"Ctrl+N被点击","Infor",MB_OK);
}else
MessageBox(hWnd,"新建菜单项被点击","Infor",MB_OK);
break;
case ID_EXIT:
PostQuitMessage(0);
break;
case ID_SET:
MessageBox(hWnd,"Ctrl+S被点击","Infor",MB_OK);
break;
}
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_COMMAND:
OnCommand(hWnd,wParam);
break;
case WM_SETCURSOR:
if(LOWORD(lParam)==HTCLIENT){
POINT pt = {
0};
GetCursorPos(&pt); // 屏幕坐标系下的光标坐标
ScreenToClient(hWnd,&pt); // 屏幕坐标系-->客户区坐标系
RECT rcClient = {
0};
GetClientRect(hWnd,&rcClient); // 客户区坐标系下的客户区大小
if(pt.x<rcClient.right/2)
{
HCURSOR hCur = LoadCursor(g_hInstance,(LPCSTR)IDC_CURSOR2);
SetCursor(hCur);
}else{
HCURSOR hCur = LoadCursor(g_hInstance,(LPCSTR)IDC_CURSOR1);
SetCursor(hCur);
}
return 0;
}
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = LoadCursor(g_hInstance,(LPCSTR)IDC_CURSOR1);// 光标 NULL--系统默认
wcs.hIcon = LoadIcon(g_hInstance,(LPCSTR)IDI_ICON1);// 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = (LPCSTR)IDR_MENU1;// 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
HACCEL hAccel = LoadAccelerators(g_hInstance,(LPCSTR)IDR_ACCELERATOR1);
while(GetMessage(&nMsg,NULL,0,0))
{
if(!TranslateAccelerator(nMsg.hwnd,hAccel,&nMsg))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
char szTitle[256] = {
0};
LoadString(g_hInstance,IDS_TITLE,szTitle,256);
HWND hWnd = CreateMain("Main",szTitle);
Display(hWnd);
Message();
return 0;
}
添加图标
参考代码:
#include <windows.h>
#include <stdio.h>
#include "resource.h"
HANDLE g_hOutput = 0;
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
HMENU g_hFile = 0;
BOOL flag = FALSE; // 标志勾选状态
void OnCommand(HWND hWnd,WPARAM wParam)
{
switch(LOWORD(wParam)) // 被点击菜单项的ID
{
case ID_POPUP_COPY:
MessageBox(hWnd,"窗口处理函数处理了复制菜单项被点击",
"Infor",MB_OK);
break;
case ID_NEW:
// MessageBox(hWnd,"新建菜单项被点击","Infor",MB_OK);
if(!flag)
CheckMenuItem(g_hFile,ID_NEW,MF_BYCOMMAND | MF_UNCHECKED);
else
CheckMenuItem(g_hFile,0,MF_BYPOSITION | MF_CHECKED);
flag = !flag;
break;
case ID_EXIT:
PostQuitMessage(0);
break;
case ID_ABOUT:
MessageBox(hWnd,"关于菜单项被点击","Infor",MB_OK);
break;
}
}
void OnInitMenuPopup(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char szText[256] = {
0};
sprintf(szText,"即将显示的菜单的句柄:%d,"
"被点击菜单项索引:%d,即将显示的菜单是否是窗口菜单:%d\n",
wParam,LOWORD(lParam),HIWORD(lParam));
WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
void OnRButtonUp(HWND hWnd,LPARAM lParam)
{
// 加载菜单
HMENU hMenu = LoadMenu(g_hInstance,(LPCSTR)IDR_MENU2);
// 获取指定菜单项下的子菜单
HMENU hPopup = GetSubMenu(hMenu,0);
POINT pt = {
0};
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
ClientToScreen(hWnd,&pt); // 客户区坐标系-->屏幕坐标系
// 显示右键菜单
TrackPopupMenu(hPopup,TPM_CENTERALIGN | TPM_VCENTERALIGN,
pt.x,pt.y,0,hWnd,NULL);
}
void OnContextMenu(HWND hWnd,LPARAM lParam)
{
// 加载菜单
HMENU hMenu = LoadMenu(g_hInstance,(LPCSTR)IDR_MENU2);
// 获取指定菜单项下的子菜单
HMENU hPopup = GetSubMenu(hMenu,0);
POINT pt = {
0};
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
// ClientToScreen(hWnd,&pt); // 客户区坐标系-->屏幕坐标系
// 显示右键菜单
BOOL nRet = TrackPopupMenu(hPopup,
TPM_CENTERALIGN | TPM_VCENTERALIGN | TPM_RETURNCMD,
pt.x,pt.y,0,hWnd,NULL);
switch(nRet)
{
case ID_POPUP_COPY:
MessageBox(hWnd,"没有发出WM_COMMAND消息,处理了复制菜单项被点击",
"Infor",MB_OK);
break;
}
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_CONTEXTMENU:
OnContextMenu(hWnd,lParam);
break;
case WM_RBUTTONUP:
// OnRButtonUp(hWnd,lParam);
break;
case WM_INITMENUPOPUP:
OnInitMenuPopup(hWnd,wParam,lParam);
break;
case WM_COMMAND:
OnCommand(hWnd,wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL;//(LPCSTR)IDR_MENU1;// 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HMENU hMenu = LoadMenu(g_hInstance,(LPCSTR)IDR_MENU1);
g_hFile = GetSubMenu(hMenu,0);
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,hMenu,
g_hInstance,NULL);
// SetMenu(hWnd,hMenu);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
测试按 Crtl +M和crtl +P
// 假设按下 Ctrl + N
TranslateAccelerator(hWnd,hAccel,&nMsg)
{
if(nMsg.message != WM_KEYDOWN &&
nMsg.message != WM_SYSKEYDOWN)
{
return 0; // 没有键盘按键被按下,不可能是加速键
}
根据 nMsg.wParam(虚拟键值),可以获知哪些按键被按下(Ctrl+N)
根据加速键句柄,到加速键表中查找是否有匹配的加速键
if(不是)
return 0; // 不是加速键
else
{
SendMessage(hWnd,WM_COMMAND,ID_NEW///1,0);
return 1;
}
}
参考代码:
#include <windows.h>
#include <stdio.h>
#include "../WinRes/resource.h"
HINSTANCE g_hIns = 0; //保存当前程序实例句柄
void OnCommand(HWND hWnd, WPARAM wParam) {
switch (LOWORD(wParam)) //被点击菜单项的ID
{
case ID_NEW:
MessageBox(hWnd, "新建菜单项被点击", "Infor", MB_OK);
break;
}
}
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch (msgID) {
case WM_COMMAND:
OnCommand(hWnd, wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); //能够是GetMessage函数返回0
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//注册窗口类
void Register(LPSTR lpClassName, WNDPROC wndproc) {
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = g_hIns;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpClassName;
wc.lpszClassName = "Main";
wc.lpszMenuName = (CHAR *)IDR_MENU1;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) {
HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, 100, 100, 700, 500, NULL, NULL, g_hIns, NULL);
return hWnd;
}
//显示窗口
void Display(HWND hWnd) {
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); //刷新窗口
}
//消息循环
void Message() {
MSG nMsg = {
0 };
HACCEL hAccel = LoadAccelerators(g_hIns, (CHAR*)RT_ACCELERATOR);
while (GetMessage(&nMsg, NULL, 0, 0)) {
if (! TranslateAccelerator(nMsg.hwnd, hAccel, &nMsg)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
}
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
g_hIns = hIns;
Register("Main", WndProc);
HWND hWnd = CreateMain("Main", "window");
Display(hWnd);
Message();
return 0;
}
获取绘图对象的信息
int GetObject(
__in HGDIOBJ hgdiobj, // 绘图对象的句柄
__in int cbBuffer, // 缓冲区大小
__out LPVOID lpvObject // 缓冲区首地址
);
参考代码:
#include <windows.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
void DrawPixel(HDC hdc)
{
// SetPixel(hdc,100,100,RGB(255,0,0));
for(int i=0;i<256;i++){
for(int j=0;j<256;j++){
SetPixel(hdc,100+i,100+j,RGB(255,i,j));
}
}
}
void DrawLine(HDC hdc)
{
MoveToEx(hdc,100,100,NULL);
LineTo(hdc,300,300);
LineTo(hdc,100,300);
LineTo(hdc,100,100);
}
void DrawRect(HDC hdc)
{
Rectangle(hdc,100,100,300,300);
RoundRect(hdc,300,100,600,300,50,50);
}
void DrawEll(HDC hdc)
{
Ellipse(hdc,100,100,300,300);
Ellipse(hdc,300,100,600,300);
}
void DrawArc(HDC hdc)
{
// Rectangle(hdc,100,100,300,300);
Arc(hdc,100,100,300,300,200,50,50,200);
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
// 1. 创建画笔
HPEN hPen = CreatePen(PS_SOLID,5,RGB(150,220,220));
// 2. 将画笔应用到DC中
HGDIOBJ hOldPen = SelectObject(hdc,hPen);
// 创建画刷
// HBRUSH hBrush = CreateSolidBrush(RGB(200,220,220));
// HBRUSH hBrush = CreateHatchBrush(HS_DIAGCROSS,RGB(180,220,220));
HGDIOBJ hBrush = GetStockObject(NULL_BRUSH);
// 将画刷应用到DC中
HGDIOBJ hOldBrush = SelectObject(hdc,hBrush);
// 3. 绘图
// DrawPixel(hdc); // 设置一个点的颜色值
// DrawLine(hdc); // 绘制直线
DrawRect(hdc); // 绘制矩形
// DrawEll(hdc); // 绘制椭圆
// DrawArc(hdc); // 绘制弧线
// 将画刷从DC中取出
SelectObject(hdc,hOldBrush);
// 释放画刷
// DeleteObject(hBrush);
// 4. 从DC中取出画笔
SelectObject(hdc,hOldPen);
// 5. 释放画笔
DeleteObject(hPen);
EndPaint(hWnd,&ps);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = CreateSolidBrush(RGB(200,220,220));// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
// 1. 创建画笔
HPEN hPen = CreatePen(PS_SOLID,5,RGB(150,220,220));
// 2. 将画笔应用到DC中
HGDIOBJ hOldPen = SelectObject(hdc,hPen);
// 创建画刷
// HBRUSH hBrush = CreateSolidBrush(RGB(200,220,220));
// HBRUSH hBrush = CreateHatchBrush(HS_DIAGCROSS,RGB(180,220,220));
HGDIOBJ hBrush = GetStockObject(NULL_BRUSH);
// 将画刷应用到DC中
HGDIOBJ hOldBrush = SelectObject(hdc,hBrush);
// 3. 绘图
// DrawPixel(hdc); // 设置一个点的颜色值
// DrawLine(hdc); // 绘制直线
DrawRect(hdc); // 绘制矩形
// DrawEll(hdc); // 绘制椭圆
// DrawArc(hdc); // 绘制弧线
// 将画刷从DC中取出
SelectObject(hdc,hOldBrush);
// 释放画刷
// DeleteObject(hBrush);
// 4. 从DC中取出画笔
SelectObject(hdc,hOldPen);
// 5. 释放画笔
DeleteObject(hPen);
EndPaint(hWnd,&ps);
}
参考代码:
#include <windows.h>
#include "resource.h"
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
void DrawBmp(HDC hdc)
{
// 1. 添加位图资源(不需要写代码)
// 2. 加载位图
HBITMAP hBmp = LoadBitmap(g_hInstance,(LPCSTR)IDB_BITMAP2);
// 3. 创建一个和当前DC相匹配的内存DC
// 同时在内存中构建一个虚拟区域,内存DC对应这块虚拟区域
/*
创建一个内存DC的内核结构,同时申请一块内存,内存DC维护这块内存
申请的内存空间和当前DC维护的显存空间大小相同
当前DC维护的显存空间大小由窗口大小决定
*/
HDC hMemDC = CreateCompatibleDC(hdc);
// 4. 将位图数据放入内存DC中,内存DC立即在虚拟区域绘制位图的图像
/*
将位图的数据存入内存DC维护的那块内存中
*/
HGDIOBJ hOldBmp = SelectObject(hMemDC,hBmp);
// 5. 成像(绘制位图)
/*
将内存DC维护的内存中的数据,以拷贝内存的方式一次性放入当前DC维护的显存中
*/
BITMAP bmpInfo = {
0};
GetObject(hBmp,sizeof(bmpInfo),&bmpInfo);
BitBlt(hdc,50,50,bmpInfo.bmWidth,bmpInfo.bmHeight,hMemDC,0,0,NOTSRCCOPY);
StretchBlt(hdc,300,50,bmpInfo.bmWidth*2,bmpInfo.bmHeight*2,
hMemDC,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,SRCCOPY);
// 6. 从内存DC中取出位图
SelectObject(hMemDC,hOldBmp);
// 7. 释放位图
DeleteObject(hBmp);
// 8. 释放内存DC
DeleteDC(hMemDC);
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
// 绘制位图
DrawBmp(hdc);
EndPaint(hWnd,&ps);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码:WinText.cpp
#include <windows.h>
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps = {
0};
HDC hdc = BeginPaint(hWnd,&ps);
// 设置文字颜色
SetTextColor(hdc,RGB(255,0,0));
// 设置文字背景颜色
// SetBkColor(hdc,RGB(250,165,165));
// 设置文字背景模式
SetBkMode(hdc,TRANSPARENT);
// 创建字体
HFONT hFont = CreateFont(30,0,100,0,FW_THIN,0,1,0,
GB2312_CHARSET,0,0,0,0,"LiSu");
// 将字体应用到DC中
HGDIOBJ hOldFont = SelectObject(hdc,hFont);
char szText[] = "达内科技";
// 绘制字符串
TextOut(hdc,100,100,szText,strlen(szText));
RECT rc = {
0};
rc.left = 100;
rc.top = 200;
rc.right = 400;
rc.bottom = 400;
// Rectangle(hdc,100,150,200,200);
DrawText(hdc,szText,strlen(szText),&rc,
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
// 从DC中取出字体
SelectObject(hdc,hOldFont);
// 释放字体
DeleteObject(hFont);
EndPaint(hWnd,&ps);
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = CreateSolidBrush(RGB(220,200,220));// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = NULL; // 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码1:WinNDlg
#include <windows.h>
#include "resource.h"
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
// 对话框处理函数
INT CALLBACK DlgProc(HWND hWndDlg,UINT msgID,WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_DESTROY:
MessageBox(hWndDlg,"对话框窗口即将被销毁","提示",MB_OK);
break;
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE)
DestroyWindow(hWndDlg);
// EndDialog(hWndDlg,1001);
break;
}
return FALSE;
}
void OnCommand(HWND hWnd,WPARAM wParam)
{
switch(LOWORD(wParam))
{
case ID_MODELESS:
HWND hWndDlg = CreateDialog(g_hInstance,(LPCSTR)IDD_DIALOG1,hWnd,DlgProc);
ShowWindow(hWndDlg,SW_SHOW);
break;
}
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_COMMAND:
OnCommand(hWnd,wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = (LPCSTR)IDR_MENU1;// 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码2:WinMDlg.cpp
#include <windows.h>
#include "resource.h"
HINSTANCE g_hInstance = 0;// 当前程序实例句柄
// 对话框处理函数
INT CALLBACK DlgProc(HWND hWndDlg,UINT msgID,WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_INITDIALOG:
MessageBox(hWndDlg,"WM_INITDIALOG","Infor",MB_OK);
break;
/* case WM_CREATE:
MessageBox(hWndDlg,"WM_CREATE","Infor",MB_OK);
break;*/
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE)
EndDialog(hWndDlg,1001);
// DestroyWindow(hWndDlg);
break;
}
return FALSE; // 将消息交给真正的对话框窗口处理函数的后续代码处理
}
void OnCommand(HWND hWnd,WPARAM wParam)
{
switch(LOWORD(wParam))// 菜单项ID
{
case ID_MODAL:
int nRet = DialogBox(g_hInstance,(LPCSTR)IDD_DIALOG1,hWnd,DlgProc);
if(nRet==1001)
{
MessageBox(hWnd,"successful!","Infor",MB_OK);
}
break;
}
}
// 2. 窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
WPARAM wParam,LPARAM lParam)
{
switch(msgID)
{
case WM_COMMAND:
OnCommand(hWnd,wParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // GetMessage返回0?
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
// 3. 注册窗口类
void Register(LPCSTR lpClassName,WNDPROC wndProc)
{
WNDCLASS wcs ={
0};
wcs.cbClsExtra = 0; // 窗口类附加数据缓冲区
wcs.cbWndExtra = 0; // 窗口附加数据缓冲区
wcs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);// 背景色
wcs.hCursor = NULL; // 光标 NULL--系统默认
wcs.hIcon = NULL; // 图标 NULL--系统默认
wcs.hInstance = g_hInstance; // 当前程序实例句柄
wcs.lpfnWndProc = wndProc; // 窗口处理函数
wcs.lpszClassName = lpClassName;// 窗口类名称
wcs.lpszMenuName = (LPCSTR)IDR_MENU1;// 菜单 NULL-没有菜单
wcs.style = CS_HREDRAW | CS_VREDRAW;// 一般风格
RegisterClass(&wcs);// 将以上赋值写入操作系统
}
// 4. 创建窗口
HWND CreateMain(LPCSTR lpClassName,LPCSTR lpWindowName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWindowName,
WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,
g_hInstance,NULL);
return hWnd;
}
// 5. 显示窗口
void Display(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
// 6. 消息循环
void Message()
{
MSG nMsg = {
0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
// 1. WinMain函数
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
LPSTR lpCmdLine,int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hWnd = CreateMain("Main","Window");
Display(hWnd);
Message();
return 0;
}
参考代码:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hIns = 0; //保存当前程序实例句柄
void OnCreate(HWND hWnd) {
CreateWindowEx(0, "BUTTON", "OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON|BS_NOTIFY, 50, 50, 100, 40, hWnd, (HMENU)1001, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "GroupButton", WS_CHILD | WS_VISIBLE |BS_GROUPBOX, 30, 30, 300, 400, hWnd, (HMENU)1002, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "CheckBox", WS_CHILD | WS_VISIBLE |BS_CHECKBOX, 50, 180, 200, 200, hWnd, (HMENU)1003, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "CheckBox", WS_CHILD | WS_VISIBLE |BS_AUTOCHECKBOX, 50, 220, 200, 30, hWnd, (HMENU)1004, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "霸天虎", WS_CHILD | WS_VISIBLE |BS_AUTOCHECKBOX|WS_GROUP , 50, 180, 200, 20, hWnd, (HMENU)1005, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "汽车人", WS_CHILD | WS_VISIBLE |BS_AUTOCHECKBOX, 50, 180, 210, 20, hWnd, (HMENU)1006, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "喜洋洋", WS_CHILD | WS_VISIBLE |BS_AUTOCHECKBOX |WS_GROUP, 50, 180, 240, 20, hWnd, (HMENU)1007, g_hIns, NULL);
CreateWindowEx(0, "BUTTON", "灰太狼", WS_CHILD | WS_VISIBLE |BS_AUTOCHECKBOX, 50, 180, 270, 20, hWnd, (HMENU)1008, g_hIns, NULL);
}
void OnCommand(HWND hWnd, WPARAM wParam) {
switch (LOWORD(wParam))
{
case 1003:
if (HIWORD(wParam) == BN_CLICKED) {
HWND hCheck = GetDlgItem(hWnd, 1003); //通过控件ID获取控件句柄
LRESULT nState = SendMessage(hCheck, BM_GETCHECK, 0, 0);
if (nState == BST_CHECKED)
SendMessage(hCheck, BM_SETCHECK, BST_UNCHECKED, 0);
else
SendMessage(hCheck, BM_SETCHECK, BST_CHECKED, 0);
}
break;
case 1001:
if (HIWORD(wParam) == BN_CLICKED) {
MessageBox(hWnd, "单击了按钮", "Infor", MB_OK);
}
else if (HIWORD(wParam) == BN_CLICKED) {
MessageBox(hWnd, "双击了按钮", "Infor", MB_OK);
}
break;
}
}
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch (msgID) {
case WM_COMMAND:
OnCommand(hWnd, wParam);
break;
case WM_CREATE:
OnCreate(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); //能够是GetMessage函数返回0
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//注册窗口类
void Register(LPSTR lpClassName, WNDPROC wndproc) {
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = g_hIns;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpClassName;
wc.lpszClassName = "Main";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) {
HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, 100, 100, 700, 500, NULL, NULL, g_hIns, NULL);
return hWnd;
}
//显示窗口
void Display(HWND hWnd) {
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); //刷新窗口
}
//消息循环
void Message() {
MSG nMsg = {
0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
g_hIns = hIns;
Register("Main", WndProc);
HWND hWnd = CreateMain("Main", "window");
Display(hWnd);
Message();
return 0;
}
参考代码:
#include <windows.h>
#include <stdio.h>
HINSTANCE g_hIns = 0; //保存当前程序实例句柄
void OnCreate(HWND hWnd) {
CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "hello",
WS_CHILD | WS_VISIBLE|WS_BORDER|ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOHSCROLL|WS_HSCROLL|WS_VSCROLL,
0, 0, 200, 200, hWnd, (HMENU)1001, g_hIns, NULL); //WS_EX_CLIENTEDGE阴影边框 ES_PASSWORD --只适合单行编辑框和ES_MULTILINE冲突
}
void OnCommand(HWND hWnd, WPARAM wParam) {
switch (LOWORD(wParam)) //菜单项ID 或控件ID
{
case 1001:
if (HIWORD(wParam) == EN_CHANGE) {
MessageBox(hWnd, "内容被修改", "Infor", MB_OK);
}
break;
case ID_GET: {
HWND hEdit = GetDlgCtrlID(hWnd, 1001);
CHAR szText[256] = {
0 };
SendMessage(hEdit, WM_GETTEXT, 256, (LPARAM)szText);
MessageBox(hWnd, szText, "Infor", MB_OK);
}
break;
case ID_SET:
{
HWND hEdit = GetDlgItem(hWnd, 1001);
CHAR szText[] = "asdfdasrewafdsaf";
SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)szText);
}
break;
}
}
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch (msgID) {
case WM_COMMAND:
OnCommand(hWnd, wParam);
break;
case WM_CREATE:
OnCreate(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); //能够是GetMessage函数返回0
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam); //给各种消息做默认处理
}
//注册窗口类
void Register(LPSTR lpClassName, WNDPROC wndproc) {
WNDCLASS wc = {
0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = g_hIns;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpClassName;
wc.lpszClassName = "Main";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); //将以上所有赋值全部写入操作系统内核
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) {
HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, 100, 100, 700, 500, NULL, NULL, g_hIns, NULL);
return hWnd;
}
//显示窗口
void Display(HWND hWnd) {
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); //刷新窗口
}
//消息循环
void Message() {
MSG nMsg = {
0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); //将消息交给窗口处理函数(自定义)
}
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
g_hIns = hIns;
Register("Main", WndProc);
HWND hWnd = CreateMain("Main", "window");
Display(hWnd);
Message();
return 0;
}
静态库:
动态库:
静态库和动态库的区别?
在现有的解决方案下生成静态库
第二 选择桌面向导
选择静态库.LIB 空项目
添加点 C 文件
写入代码
生成:
添加一个可执行控制台程序
设置为启动程序
添加一个点c的文件
查看静态库文件并调用
查看clib.lib 所在的路径
写入代码:
#include <stdio.h>
//C编译器在函数调用前,不需要前向声明
//2.告诉链接器去哪儿抓取加减法函数的源代码
#pragma comment(lib,"../debug/clib.lib")
int main(void) {
int sum = clib_add(5, 3);
int sub = clib_sub(5, 3);
printf("%d,%d\n",sum,sub);
getchar();
return 0;
}
测试
添加cpp文件
写入代码:
int cpplib_add(int a, int b) {
return a + b;
}
int cpplib_sub(int a, int b) {
return a - b;
}
生成静态库
创建控制台程序
设置为启动项
添加源文件写入代码 usecpplib.cpp
//1.前向声明(头文件)
//2.链接器使用
//3.功能代码
#include <stdio.h>
int cpplib_add(int , int );
int cpplib_sub(int , int );
//告诉链接器从哪儿抓取加减法的源代码
#pragma comment(lib,"../debug/cpplib.lib")
//功能代码
int main(void) {
int sum = cpplib_add(5, 3);
int sub = cpplib_sub(5, 3);
printf("%d,%d\n",sum,sub);
getchar();
return 0;
}
测试:
写入代码:
//1.前向声明(头文件)
//2.链接器使用
//3.功能代码
#include <stdio.h>
int cpplib_add(int , int );
int cpplib_sub(int , int );
//c库函数的声明
int clib_add(int, int);
int clib_sub(int, int);
//告诉链接器从哪儿抓取加减法的源代码
#pragma comment(lib,"../debug/cpplib.lib")
#pragma comment(lib,"../debug/clib.lib") //链接C库
//功能代码
int main(void) {
int sum = cpplib_add(5, 3);
int sub = cpplib_sub(5, 3);
printf("%d,%d\n",sum,sub);
sum = clib_add(5, 3);
sub = clib_sub(5, 3);
printf("%d,%d\n",sum,sub);
getchar();
return 0;
}
测试: 报错
C++程序在编译时对函数有换名操作
**解决办法:**前面加extern “C”
修改代码为:
//1.前向声明(头文件)
//2.链接器使用
//3.功能代码
#include <stdio.h>
int cpplib_add(int , int );
int cpplib_sub(int , int );
//c库函数的声明
extern "C" int clib_add(int, int);
extern "C" int clib_sub(int, int);
//告诉链接器从哪儿抓取加减法的源代码
#pragma comment(lib,"../debug/cpplib.lib")
#pragma comment(lib,"../debug/clib.lib") //链接C库
//功能代码
int main(void) {
int sum = cpplib_add(5, 3);
int sub = cpplib_sub(5, 3);
printf("%d,%d\n",sum,sub);
sum = clib_add(5, 3);
sub = clib_sub(5, 3);
printf("%d,%d\n",sum,sub);
getchar();
return 0;
}
测试: 成功执行
写入代码:
生成动态库
设置dumpbin.exe 程序导出
C:\Program Files(x86)\Microsoft Visual Studio 19.0\VC\bin
使用该程序查看dll 的导出函数的。
如果运行不成功,提示缺少.dll 文件,解决步骤如下:
1> 切换到C:\Program Files(x86)\Microsoft Visual Studio 19.0\VC 目录,执行批处理文件vcvarsall.bat,双击即可。
2> 设置path 环境变量,增加如下路径 ;C:\Program Files(x86)\Microsoft Visual Studio 19.0\Common7\IDE\
需要在导出函数中前面添加 _declspec(dllexport)
注意:
当生成动态库时,如果有导出函数,生成dll文件的同时生成配套的lib 文件。
该lib 文件与原来的静态库的lib 文件是不同的。原来的静态库lib文件中存储的是函数的源代码。
而与dll 配套的lib文件存储的是函数的偏移地址。源代码在dll文件中。
新建调用项目
设置为启动项,并添加代码测试
写入代码:
//1.头文件包含,前向声明
#include <stdio.h>
//2.告诉链接器去哪儿抓取加减法函数的地址
#pragma comment(lib,"../debug/cdll.lib")
//3.功能代码
int main(void) {
int sum = cdll_add(5, 3);
int sub = cdll_sub(5, 3);
printf("%d,%d\n",sum,sub);
getchar();
return 0;
}
测试成功
与对静态库调用在代码的编写上时类似的,但是本质上是不同的!
这种调用方式(隐式调用),需要的文件:usecdll.exe +cdll.lib(函数的偏移地址) +cdll.dll (函数的源代码)
添加文件并写入代码生成:
_declspec(dllexport) int cppdll_add(int a, int b) {
return a + b;
}
_declspec(dllexport) int cppdll_sub(int a, int b) {
return a + b;
}
_declspec(dllexport) int cppdll_mul(int a, int b) {
return a * b;
}
创建项目
添加cpp文件
写入代码:
//前向声明
#include <stdio.h>
int cppdll_add(int, int);
int cppdll_sub(int, int);
//链接信息,告诉链接器从哪儿抓取函数的地址
#pragma comment(lib,"../debug/cppdll.lib")
//功能代码
int main(void) {
int sum = cppdll_add(5, 3);
int sub = cppdll_sub(5, 3);
printf("sum=%d,sub=%d\n",sum,sub);
getchar();
return 0;
}
官方推荐写法:
//前向声明
#include <stdio.h>
//增加导入声明(官方文档推荐)
_declspec(dllimport) int cppdll_add(int, int);
_declspec(dllimport) int cppdll_sub(int, int);
//链接信息,告诉链接器从哪儿抓取函数的地址
#pragma comment(lib,"../debug/cppdll.lib")
//功能代码
int main(void) {
int sum = cppdll_add(5, 3);
int sub = cppdll_sub(5, 3);
printf("sum=%d,sub=%d\n", sum, sub);
getchar();
return 0;
}
测试:
生成C动态库
使用之前代码,添加调用C库函数
//前向声明
#include <stdio.h>
//增加导入声明(官方文档推荐)
_declspec(dllimport) int cppdll_add(int, int);
_declspec(dllimport) int cppdll_sub(int, int);
//调用C库函数,需要增加extern “C ”
extern "C" int cdll_add(int, int);
extern "C" int cdll_sub(int, int);
//链接信息,告诉链接器从哪儿抓取函数的地址
#pragma comment(lib,"../debug/cppdll.lib")
#pragma comment(lib,"../debug/cdll.lib")
//功能代码
int main(void) {
int sum = cppdll_add(5, 3);
int sub = cppdll_sub(5, 3);
printf("sum=%d,sub=%d\n", sum, sub);
sum = cdll_add(5, 3);
sub = cdll_sub(5, 3);
printf("sum=%d,sub=%d\n", sum, sub);
getchar();
return 0;
}
测试:
声明导出添加 _declspec(dllexport) 导出的是函数换名后的对应的相对地址
模块定义文件导出 在库程序中添加.def文件
导出的可以是不做换名的函数对应的相对地址,也可以是换名的函数对应的相对地址
隐式链接
程序执行前,操作系统负责加载动态库(读取.exe文件head部分依赖的动态库的名字)
操作系统根据函数的编号到dll的head部分查找对应的相对地址进而获取函数的绝对地址
程序结束时,操作系统负责卸载已经加载的动态库
显式链接
程序员调用LoadLibrary函数,负责使动态库执行(加载动态库)
程序员调用GetProcAddress函数,获取函数的绝对地址
程序员调用FreeLibrary函数,卸载动态库
参考代码:
//包含头文件
#include <stdio.h>
#include <Windows.h>
//2.显示链接时。不需要配套的lib文件
//功能代码
//1.定义函数指针类型
typedef int(*Func)(int, int);
int main() {
//加载dll
HMODULE hDll = LoadLibrary("cppdll.dll");
//获取函数的绝对地址
Func add = (Func)GetProcAddress(hDll,"?cppdll_add@@[email protected]");
//调用函数
int sum = add(5, 3);
printf("sum=%d\n",sum);
//卸载dll
FreeLibrary(hDll);
getchar();
}
为了解决 函数名称麻烦,使用导出方式2 :在库程序中添加.def文件
添加代码:并重新生成
LIBRARY cppdll
EXPORTS
cppdll_add @1
cppdll_sub @2
重新编写代码:
//包含头文件
#include <stdio.h>
#include <Windows.h>
//2.显示链接时。不需要配套的lib文件
//功能代码
//1.定义函数指针类型
typedef int(*Func)(int, int);
int main() {
//加载dll
HMODULE hDll = LoadLibrary("cppdll.dll");
//获取函数的绝对地址
//Func add =(Func)GetProcAddress(hDll,"?cppdll_add@@[email protected]");
//加法
Func add =(Func)GetProcAddress(hDll,"cppdll_add");
//调用函数
int sum = add(5, 3);
printf("sum=%d\n",sum);
//减法
Func sub = (Func)GetProcAddress(hDll,"cppdll_sub");
int sub2 = sub(5, 3);
printf("sub=%d\n",sub2);
Func mul = (Func)GetProcAddress(hDll,"?cppdll_mul@@[email protected]");
int mul2 = mul(5, 3);
printf("sub=%d\n",mul2);
//卸载dll
FreeLibrary(hDll);
getchar();
}
测试:
创建项目
添加头文件
写入代码:math.h
#pragma once
//或者使用ifndef。。。endif
//math.h在创建类库时(导出类),和调用类库时(导入类)都需要
#ifndef DLL_EXT_CLASS
#define EXT_CLASS _declspec(dllexport) //创建dll
#else
#define EXT_CLASS _declspec(dllimport) //调用dll
#endif // !
class EXT_CLASS CMath {
public:
int add(int a, int b);
int sub(int a, int b);
};
添加源文件
写入代码:math.cpp
#define DLL_EXT_CLASS
#include "math.h"
int CMath::add(int a, int b) {
return a + b;
}
int CMath::sub(int a, int b) {
return a - b;
}
生成:
创建项目并设置为启动项
添加源文件
写入代码:
#include <stdio.h>
#include "../classdll/math.h"
#pragma comment(lib,"../debug/classdll.lib");
int main(void) {
CMath math;
printf("sum=%d\n",math.add(5,3));
printf("sub=%d\n",math.sub(5,3));
return 0;
}
测试:
#include <Windows.h>
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle, // 句柄
__in DWORD dwMilliseconds // 等候时间 INFINITE
);
参考代码: math.cpp
#define DLL_EXT_CLASS
#include "math.h"
#include <Windows.h>
//dll的入口函数
BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL, "进程加载时的初始化", "提示", MB_OK);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
MessageBox(NULL, "进程卸载时清理工作", "提示", MB_OK);
break;
}
return TRUE;
}
int CMath::add(int a, int b) {
return a + b;
}
int CMath::sub(int a, int b) {
return a - b;
}
测试:
解决办法:
方法1: 项目-》属性-》更改字符集为多字节字符集
方法2:字符串串前面加大写 L
DWORD WINAPI ThreadProc(
LPVOID lpParameter //创建线程时,传递给线程的参数
);
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//安全属性 (一般NULL)
SIZE_T dwStackSize, //线程栈的大小 (一般0)
LPTHREAD_START_ROUTINE lpStartAddress, //线程处理函数的函数地址
LPVOID lpParameter, //传递给线程处理函数的参数
DWORD dwCreationFlags, //线程的创建方式,
LPDWORD lpThreadId //创建成功,返回线程的ID
);
//创建成功,返回线程句柄
dwCreationFlags
取值:
0 - 创建之后线程立刻执行
CREATE_SUSPENDED - 创建之后线程处于挂起状态
结束指定线程
BOOL TerminateThread(
HANDLE hThread, // handle to thread
DWORD dwExitCode // exit code
);
结束函数所在的线程
VOID ExitThread(
DWORD dwExitCode // exit code for this thread
);
CloseHandle
挂起
DWORD SuspendThread(
HANDLE hThread // handle to thread
);
DWORD ResumeThread(
HANDLE hThread // handle to thread
);
获取当前线程的ID
GetCurrentThreadId
获取当前线程的句柄
GetCurrentThread
打开指定ID的线程,获取其句柄
HANDLE OpenThread(
DWORD dwDesiredAccess, // access right
BOOL bInheritHandle, // handle inheritance option
DWORD dwThreadId // thread identifier
);
#include <stdio.h>
#include <Windows.h>
//线程函数1
DWORD WINAPI ThreadProc(LPVOID lpParameter /*创建线程时,传递给线程的参数 */) {
//DWORD id = GetCurrentThreadId();
//printf("%d\n", id);
while (true)
{
for (int i = 0; i < 20; i++) {
printf("*");
}
printf("\n");
Sleep(1000);
}
return 0;
}
//线程函数2
DWORD WINAPI ThreadProc2(LPVOID lpParameter /*创建线程时,传递给线程的参数 */) {
while (true)
{
for (int i = 0; i < 20; i++) {
printf("-");
}
printf("\n");
Sleep(1000);
}
return 0;
}
int main(void) {
//1. 创建子线程
DWORD nID = 0;
HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &nID);
//printf("nID=%d", nID);
DWORD nID2 = 0;
HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL,CREATE_SUSPENDED, &nID2); //CREATE_SUSPENDED 挂起
getchar();
//切换线程状态:子线程1的状态由执行-> 挂起:子线程2的状态由挂起->执行
SuspendThread(hThread);
ResumeThread(hThread2);
getchar();
//不再使用线程句柄时,需要关闭句柄,否则有句柄泄露
CloseHandle(hThread);
CloseHandle(hThread2);
return 0;
}
WaitForSingleObject - 等候单个句柄有信号
DWORD WaitForSingleObject(
HANDLE hHandle, //等候对象的句柄
DWORD dwMilliseconds //等候时间
);
其中:
dwMilliseconds 等候时间 毫秒为单位
INFINITE 表示无限期等候
WaitForMultipleObjects - 等候多个句柄有信号
DWORD WaitForMultipleObjects(
DWORD nCount, //句柄数量
CONST HANDLE *lpHandles, //句柄BUFF的地址
BOOL bWaitAll, //等候方式
DWORD dwMilliseconds // 等候时间 INFINITE
);
其中:
bWaitAll - 等候方式
TRUE - 表示所有句柄都有信号,才结束等候
FASLE- 表示句柄中只要有1个有信号,就结束等候。
多线程的问题
线程A -> 线程B -> 线程A 。。。。。
当线程A执行printf输出时,如果线程A的执行时间结束,系统会将线程A的相关信息(栈、寄存器)压栈保护,同时将线程B相关信息恢复,然后执行线程B,线程B继续输出字符。由于线程A正输出字符,线程B会继续输出,画面字符会产生混乱。
原子锁
临界区(段)
互斥
事件
信号量
可等候定时器
相关问题
多个线程对同一个数据进行原子操作,会产生结果丢失
比如执行++运算时, 当线程A执行g_nValue++时,如果线程切换时间 正好是在线程A将值保存到g_nValue之前, 线程B继续执行g_nValue++,那么当线程A再次被切换回来之后,会将原来线程A保存的值保存到g_nValue上,线程B进行的加法操作被覆盖。
原子锁-对单条指令的操作。
API
InterlockedIncrement
InterlockedDecrement
InterlockedCompareExchange
InterlockedExchange
原子锁的实现:
直接对数据所在的内存操作,并且在任何一个瞬间只能有一个线程访问。
参考代码:WinInterlock.cpp
#include <stdio.h>
#include <Windows.h>
//1.定义一个全局变量
long gValue = 0;
//2.添加两个子线程函数
DWORD WINAPI ThreadProc(LPVOID pParam) {
for (int i = 0; i < 1e8; i++) {
//gValue++;
InterlockedIncrement(&gValue); //原子锁
}
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID pParam) {
for (int i = 0; i < 1e8; i++) {
//gValue++;
InterlockedIncrement(&gValue); //原子锁
}
return 0;
}
int main(void) {
//1. 创建两个子线程
DWORD nID;
HANDLE hThread[2] = {
0 };
hThread[0] = CreateThread(NULL, 0, ThreadProc, NULL, 0, &nID);
hThread[1] = CreateThread(NULL, 0, ThreadProc, NULL, 0, &nID);
//等待两个子线程完成计算后,再打印结果
//线程句柄何时有信号何时无信号呢?线程正在执行时无信号,线程执行完成,有信号。
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
//打印计算结果;
printf("%d\n", gValue);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
getchar();
return 0;
}
相关的问题
多线程下代码或资源的共享使用。
互斥的使用
创建互斥
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性
BOOL bInitialOwner, //初始的拥有者 TRUE/FALSE
LPCTSTR lpName //命名
);
//创建成功返回互斥句柄
bInitialOwner - 初始的拥有者
TRUE - 调用CreateMutex的线程拥有互斥
FALSE - 创建的时没有线程拥有互斥
WaitForXXX
互斥的等候遵循谁先等候谁先获取
BOOL ReleaseMutex(
HANDLE hMutex // handle to mutex
);
关闭互斥句柄
CloseHandle
参考代码:WinMutex.cpp
#include <stdio.h>
#include <Windows.h>
//全局逇互斥句柄
HANDLE hMutex = NULL;
//子线程函数1
DWORD WINAPI PrintProc(LPVOID pParam) {
while (true)
{
//哪些线程先等待,就会先得到互斥。互斥变成无信号
WaitForSingleObject(hMutex, INFINITE);
//通过之后,被线程1拥有,互斥变成无信号
for (int i = 0; i < 20; i++) {
printf("*");
}
printf("\n");
//释放互斥,互斥不被任何线程拥有,变成有信号
ReleaseMutex(hMutex);
Sleep(1000);
}
return 0;
}
//子线程函数2
DWORD WINAPI PrintProc2(LPVOID pParam) {
while (true)
{
//等待互斥有信号
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < 20; i++) {
printf("-");
}
printf("\n");
ReleaseMutex(hMutex);
Sleep(1000);
}
return 0;
}
int main(void) {
//创建互斥,FALSE意味着主线程不拥有互斥。目前是有信号。
//当互斥不被任何线程拥有时,有信号:被线程拥有时,无信号。
hMutex = CreateMutex(NULL, FALSE, "myMutex");
//1. 创建线程
DWORD nID, nID2;
HANDLE hThread, hThread2;
hThread = CreateThread(NULL, 0, PrintProc, NULL, 0, &nID);
hThread2 = CreateThread(NULL, 0, PrintProc2, NULL, 0, &nID2);
getchar();
//2.关闭线程句柄
CloseHandle(hThread);
CloseHandle(hThread2);
CloseHandle(hMutex);
return 0;
}
相关问题
程序之间的通知的问题。
事件的使用
创建事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
BOOL bManualReset, //事件重置(复位)方式 TRUE手动,FALSE自动
BOOL bInitialState, //事件初始状态,TRUE有信号
LPCTSTR lpName //事件命名
);
//创建成功返回 事件句柄
等候事件
WaitForSingleObject/ WaitForMultipleObjects
触发事件
将事件设置成有信号状态 – 触发事件
BOOL SetEvent(
HANDLE hEvent // handle to event
);
将事件设置成无信号状态-- 复位事件
BOOL ResetEvent(
HANDLE hEvent // handle to event
);
关闭事件
CloseHandle
注意:
小心事件的死锁。
参考代码:WinEvent.cpp
#include <stdio.h>
#include <Windows.h>
//1.全局事件句柄
HANDLE hEvent = NULL;
//两个线程函数,一个线程用于打印,另一个线程用于控制打印时间间隔
DWORD WINAPI PrintProc(LPVOID pParam) {
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
//有信后,通过后, 自动重置,表示事件自动变成无信号
printf("**************\n");
}
return 0;
}
DWORD WINAPI CtrlProc(LPVOID pParam) {
while (true)
{
Sleep(1000);
SetEvent(hEvent);
}
return 0;
}
int main(void) {
//FALSE:自动重置;FALSE:初始无信号
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
DWORD nID;
HANDLE hThread = CreateThread(NULL, 0, PrintProc, NULL, 0, &nID);
HANDLE hThread2 =CreateThread(NULL, 0, CtrlProc, NULL, 0, &nID);
getchar();
CloseHandle(hThread);
CloseHandle(hThread2);
return 0;
}
相关的问题
类似于事件,解决通知的相关问题。但是可以提供一个计数器,可以设置次数。
信号量的使用
创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全属性
LONG lInitialCount, //初始化信号量数量 3
LONG lMaximumCount, //信号量的最大值 10
LPCTSTR lpName //命名
);
//创建成功返回信号量句柄
等候信号量
WaitFor…
每等候通过一次,信号量的信号减1,直到为0阻塞
给信号量指定计数值
BOOL ReleaseSemaphore(
HANDLE hSemaphore, //信号量句柄
LONG lReleaseCount, //释放数量
LPLONG lpPreviousCount // 释放前原来信号量的数量
// 可以为NULL
);
关闭句柄
CloseHandle
参考代码:WinSema.cpp
#include <stdio.h>
#include <Windows.h>
HANDLE hSema = NULL;
DWORD WINAPI PrintProc(LPVOID pParam) {
while (true)
{
WaitForSingleObject(hSema, INFINITE);
printf("*************\n");
Sleep(1000);
}
return 0;
}
int main(void) {
hSema = CreateSemaphore(NULL, 3, 10, NULL);
DWORD nID;
HANDLE hThread = CreateThread(NULL, 0, PrintProc, NULL, 0, &nID);
getchar();
//释放5个信号
ReleaseSemaphore(hSema,5,NULL);
CloseHandle(hSema);
CloseHandle(hThread);
return 0;
}
文章来源:[url]http://blog.sina.com.cn/s/blog_5421dfd20100ffn8.html[/url]3.2 SGA系统全局区--System global area(SGA) 是一组共享的内存结构,它里面存储了oracle数据库实例(instance)的数据和控制文件信息。如果有多个用户同时连接到数据库,他们会共享这一区域,因此SGA也称之为Shar...
Token 是什么通俗的讲,token 是用户的一种凭证,需拿正确的用户名/密码向 Keystone 申请才能得到。如果用户每次都采用用户名/密码访问 OpenStack API,容易泄露用户信息,带来安全隐患。所以 OpenStack 要求用户访问其 API 前,必须先获取 token,然后用 token 作为用户凭据访问 OpenStack API。 四种 Token 的由来D
一个完善的多任务操作系统,必须具有完备的同步和通信机制。任务的同步和事件1 任务间的同步直接制约关系:源于任务之间的合作间接制约关系:源于对资源的共享多任务合作过程中,处理的问题:各任务间应该具有一种互斥关系,即对于某个共享资源,如果一个任务正在使用,则其他任务只能等待,等待该任务释放该资源后,等待的任务才能使用。相关的任务在执行中要有先后次序,一个任务要等其伙伴发来通
在研究OCC与Webassembly结合使用,编译的时候遇到以下问题:原来是最新版本的emcc导致的,版本回退到3.1.10就可以了。
JPA是什么?JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。想了解更多请自行百度百科。JPAJPA的...
本文章的内容是根据书籍《从零开始学架构》整理的资料,供作者以及读者查阅。1. 架构的定义软件架构指软件系统的顶层架构。详细阐述如下:a. “系统由一群关联个体组成”,个体分别是:系统、子系统、模块、组件等。架构需要明确系统包含哪些“个体”。b. 系统中的个体需要“按照某种规则”运作,架构需要明确个体运作和协作的规则。2. 架构设计的目的2.1. 软件架构的历史背景(...
CentOS使用Nginx反向代理Tomcat部署Java Web项目今天我舍友问我:CSDN是什么意思?床上等你吗?文章目录CentOS使用Nginx反向代理Tomcat部署Java Web项目一、安装Tomcat9.01.配置Java环境2.安装Tomcat二、安装Nginx1. 编译工具及库文件2.安装PCRE3.安装Nginx4.编辑Nginx配置文件三.小结一、安装Tomcat9.01.配置Java环境先卸载系统自带的恶心人的openjdk,方法的话比较暴力,使用rpm找到所有
Python微信检测你的颜值高低需要准备的工具功能实现原因代码Face.pyWechatRobot.py使用教程1丶运行WechatRobot.py文件2丶添加好友或群组开启功能运行结果需要准备的工具Python 2.7itchat模块功能实现原因当初有段...
1,Windows 10微软福利啊,免费升级windows 10,赶紧升级下自己的电脑。 微软的升级是有期限的,是7月底。还有 1个多月的时间。 https://www.microsoft.com/zh-cn/windows/windows-10-upgrade 下载一个 exe直接进行安装就好。2,安装过程 下载到了c盘的隐藏文件夹。 3个多G。 不知道拷贝到别的电脑上面能不能使
1 importandroid.app.Service;2 importandroid.content.Context;3 importandroid.content.Intent;4 importandroid.media.AudioManager;5 importandroid.os.Handler;6 importandroid.os.IBinder;7 importandroid.os.M...
一、JNI基本数据类型字符对应"()V" "(II)V" "(Ljava/lang/String;Ljava/lang/String;)V" ()中的字符表示参数,后面的则代表返回值"()V"就代表 void func()"(II)V" 表示 void func(int,int)上述是单字符的表示,下面来看下数组的表示方法数组是以"["开始用两个字符表示 ...
展开全部可以同时开,但是没有必要。单频无e68a84e8a2ad62616964757a686964616f31333366303065线路由器一般工作在2.4GHz频段,这个频段是免费的公共频段,其它的电子产品,如空调、微波炉、无线鼠标、无线音箱、蓝牙、无绳电话等同样在使用这个频段,这就很容易造成设备间的无线信号干扰,从而导致无线网络不稳定。由于双频无线路由器有2.4GHz和5GHz两个频段可选...