第一个windows窗口程序

创建一个窗口程序的空项目,或者
创建一个控制台空项目,调整下面的选项:
image.png

  1. #include <Windows.h>
  2. int WINAPI WinMain(
  3. HINSTANCE hInstance, //实例句柄
  4. HINSTANCE hPreInstance, //没有用了
  5. LPSTR szCmd, //命令行参数
  6. int nShow //命令行参数
  7. )
  8. {
  9. MessageBox(0, L"你好", L"友情提示", 0);
  10. return 0;
  11. }

在windows下编程,有两个问题需要提前了解:

数字转字符串

  1. 在windows下,没有比较好用的输出数字的函数,我通常都需要自己转换:

  1. int WINAPI WinMain(
  2. HINSTANCE hInstance, //实例句柄
  3. HINSTANCE hPreInstance, //没有用了
  4. LPSTR szCmd, //命令行参数
  5. int nShow //命令行参数
  6. )
  7. {
  8. //想要将nNum的值,用MessageBox显示出来。
  9. //数字转字符串
  10. int nNum = 100;
  11. char buf[100] = {};
  12. sprintf_s(buf, "%d", nNum);
  13. MessageBoxA(0, buf, "友情提示", 0);
  14. return 0;
  15. }

下来自己去试一试字符串转成数字。
sscanf

字符串转成数字

A版和W版

  1. 所有的字符串相关的API函数,都分成两个版本:A版和W版
  1. int WINAPI WinMain(
  2. HINSTANCE hInstance, //实例句柄
  3. HINSTANCE hPreInstance, //没有用了
  4. LPSTR szCmd, //命令行参数
  5. int nShow //命令行参数
  6. )
  7. {
  8. //想要将nNum的值,用MessageBox显示出来。
  9. //数字转字符串
  10. int nNum = 100;
  11. char buf[100] = {};
  12. wchar_t buf2[100] = {};
  13. sprintf_s(buf, "%d", nNum);
  14. swprintf_s(buf2, L"%d", nNum);
  15. MessageBoxA(0, buf, "友情提示", 0);
  16. MessageBoxW(0, buf2, L"友情提示", 0);
  17. return 0;
  18. }

T版

一般我们都使用T版函数

  1. #include <Windows.h>
  2. #include <stdio.h>
  3. #include <tchar.h>
  4. int WINAPI WinMain(
  5. HINSTANCE hInstance, //实例句柄
  6. HINSTANCE hPreInstance, //没有用了
  7. LPSTR szCmd, //命令行参数
  8. int nShow //命令行参数
  9. )
  10. {
  11. //想要将nNum的值,用MessageBox显示出来。
  12. //数字转字符串
  13. int nNum = 100;
  14. char buf[100] = {};
  15. wchar_t buf2[100] = {};
  16. sprintf_s(buf, "%d", nNum);
  17. swprintf_s(buf2, L"%d", nNum);
  18. MessageBoxA(0, buf, "友情提示", 0);
  19. MessageBoxW(0, buf2, L"友情提示", 0);
  20. //t版函数
  21. TCHAR buf3[100] = { _T("helloworld") };
  22. _stprintf_s(buf3, _T("%d"), nNum);
  23. MessageBox(0, buf3, _T("友情提示"), 0);
  24. return 0;
  25. }

asc和unicode之间的转换。

  1. // 宽字符转换为多字符(Unicode --> ASCII)
  2. #define WCHAR_TO_CHAR(lpW_Char, lpChar) \
  3. WideCharToMultiByte(CP_ACP, NULL, lpW_Char, -1,
  4. lpChar, _countof(lpChar), NULL, FALSE);
  5. // 多字符转换为宽字符(ASCII --> Unicode)
  6. #define CHAR_TO_WCHAR(lpChar, lpW_Char) \
  7. MultiByteToWideChar(CP_ACP, NULL, lpChar, -1,
  8. lpW_Char, _countof(lpW_Char));

在windows下输出调试信息:

  1. bool _trace(const TCHAR *format, ...) //变参函数
  2. {
  3. TCHAR buffer[1000];
  4. va_list argptr;
  5. va_start(argptr, format);
  6. //将格式化信息写入指定的缓冲区
  7. wvsprintf(buffer, format, argptr);
  8. va_end(argptr);
  9. //将缓冲区信息输出
  10. OutputDebugString(buffer);
  11. return true;
  12. }
  13. int WINAPI WinMain(
  14. HINSTANCE hInstance, //实例句柄
  15. HINSTANCE hPreInstance, //没有用了
  16. LPSTR szCmd, //命令行参数
  17. int nShow //命令行参数
  18. )
  19. {
  20. int nNum = 100;
  21. _trace(_T("这个数字为%d"), nNum);
  22. return 0;
  23. }

image.png
我们也可以自己封装带格式控制符的Messagebox

  1. bool _MyMessageBox(const TCHAR *format, ...) //变参函数
  2. {
  3. TCHAR buffer[1000];
  4. va_list argptr;
  5. va_start(argptr, format);
  6. //将格式化信息写入指定的缓冲区
  7. wvsprintf(buffer, format, argptr);
  8. va_end(argptr);
  9. //将缓冲区信息输出
  10. MessageBox(0,buffer,_T("提示"),0);
  11. return true;
  12. }
  13. int WINAPI WinMain(
  14. HINSTANCE hInstance, //实例句柄
  15. HINSTANCE hPreInstance, //没有用了
  16. LPSTR szCmd, //命令行参数
  17. int nShow //命令行参数
  18. )
  19. {
  20. int nNum = 100;
  21. _MyMessageBox(_T("这个数字为%d"), nNum);
  22. return 0;
  23. }

关于windows程序的错误码:

  1. int WINAPI WinMain(
  2. HINSTANCE hInstance, //实例句柄
  3. HINSTANCE hPreInstance, //没有用了
  4. LPSTR szCmd, //命令行参数
  5. int nShow //命令行参数
  6. )
  7. {
  8. HANDLE h = GetStdHandle(100);
  9. int nError = GetLastError();//这个函数能够获取到最近一次调用的API的错误码
  10. _MyMessageBox(_T("错误码为:%d"), nError);
  11. return 0;
  12. }

image.png
在调试的时候,快速监视到错误码的方法:
注意是:err,hr
英文逗号逗号逗号
image.png
制作一个能够解析错误码的工具,能够提供出错的具体位置:

  1. #define CHAR_TO_WCHAR(lpChar, lpW_Char) \
  2. MultiByteToWideChar(CP_ACP, NULL, lpChar, -1, \
  3. lpW_Char, _countof(lpW_Char));
  4. void MyGetErrorInfo(
  5. LPCTSTR lpErrInfo,
  6. UINT unErrCode,
  7. TCHAR* tFile,
  8. UINT unLine) // unLine=__LINE__
  9. {
  10. LPTSTR lpMsgBuf = nullptr;
  11. WCHAR szMessage[128] = { 0 };
  12. WCHAR szCaption[128] = { 0 };
  13. //这个函数能够将错误码解析为错误信息
  14. FormatMessage(0x1300, NULL, unErrCode,
  15. 0x400, (LPTSTR)&lpMsgBuf, 64, NULL);
  16. swprintf_s(szMessage, 128,
  17. L"Error_0x%08X:%s", unErrCode, lpMsgBuf);
  18. swprintf_s(szCaption, 128,
  19. L"%s:%s:(Error Line:%05d)", lpErrInfo, tFile, unLine);
  20. MessageBox(NULL, szCaption, szMessage , MB_OK);
  21. }
  22. int WINAPI WinMain(
  23. HINSTANCE hInstance, //实例句柄
  24. HINSTANCE hPreInstance, //没有用了
  25. LPSTR szCmd, //命令行参数
  26. int nShow //命令行参数
  27. )
  28. {
  29. HANDLE h = GetStdHandle(100);
  30. //1 获得错误码
  31. int nError = GetLastError();
  32. //2 得到出错的文件路径
  33. wchar_t buf[100] = {};
  34. CHAR_TO_WCHAR(__FILE__, buf);
  35. //3 输出错误信息
  36. MyGetErrorInfo(_T("十五派友情提示您:"), nError, buf,__LINE__-1);
  37. return 0;
  38. }

第一个窗口程序:

  1. #include <Windows.h>
  2. #include <tchar.h>
  3. //int WinMain(
  4. // HINSTANCE hInstance,
  5. // HINSTANCE hPreInstance,
  6. // LPSTR szCmd,
  7. // int nShow
  8. //);
  9. //int wWinMain(
  10. // HINSTANCE hInstance,
  11. // HINSTANCE hPreInstance,
  12. // LPWSTR szCmd,
  13. // int nShow
  14. //);
  15. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
  16. int WINAPI _tWinMain(
  17. HINSTANCE hInstance,
  18. HINSTANCE hPreInstance,
  19. LPTSTR szCmd,
  20. int nShow
  21. )
  22. {
  23. //1 设计窗口类
  24. //UINT style;
  25. //WNDPROC lpfnWndProc;
  26. //int cbClsExtra;
  27. //int cbWndExtra;
  28. //HINSTANCE hInstance;
  29. //HICON hIcon;
  30. //HCURSOR hCursor;
  31. //HBRUSH hbrBackground;
  32. //LPCWSTR lpszMenuName;
  33. //LPCWSTR lpszClassName;
  34. WNDCLASS wc;
  35. wc.style = CS_VREDRAW | CS_HREDRAW;//类风格
  36. wc.lpfnWndProc = WndProc;//回调函数的地址(重要)
  37. wc.cbClsExtra = 0;
  38. wc.cbWndExtra = 0;
  39. wc.hInstance = hInstance;//实例句柄,代表此程序
  40. wc.hIcon = 0; //类图标
  41. wc.hCursor = 0; //类光标
  42. wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  43. wc.lpszMenuName = 0;
  44. wc.lpszClassName = L"15PB";
  45. //2 注册窗口类
  46. RegisterClass(&wc);
  47. //3 创建窗口
  48. HWND hWnd = CreateWindow(
  49. L"15PB", //类名
  50. L"第一个窗口", //窗口名
  51. WS_OVERLAPPEDWINDOW,//重叠窗口风格
  52. 100, 100, 400, 600, //位置和大小
  53. NULL, //父窗口句柄
  54. NULL, //菜单句柄
  55. hInstance, //实例句柄
  56. NULL //附加信息
  57. );
  58. //4 更新显示窗口
  59. ShowWindow(hWnd, SW_SHOW);
  60. UpdateWindow(hWnd);
  61. //5 实现消息循环
  62. MSG msg = {};
  63. // 5.1 获取消息
  64. //GetMessage得到WM_QUIT消息的时候,会返回False
  65. while (GetMessage(&msg, 0, 0, 0))
  66. {
  67. // 5.2 转换消息 将WM_KEYDOWN转换WM_CHAR
  68. TranslateMessage(&msg);
  69. // 5.3 派发消息
  70. DispatchMessage(&msg);
  71. }
  72. return 0;
  73. }
  74. LRESULT CALLBACK WndProc(
  75. HWND hWnd,
  76. UINT uMessage,
  77. WPARAM wParam,
  78. LPARAM lParam
  79. )
  80. {
  81. switch (uMessage)
  82. {
  83. case WM_CLOSE:
  84. PostQuitMessage(0);//会发出一个WM_QUIT消息
  85. break;
  86. default:
  87. break;
  88. }
  89. return DefWindowProc(hWnd, uMessage, wParam, lParam);
  90. }

常见的消息处理:

WM_CLOSE 窗口关闭的消息
WM_DESTORY 窗口销毁的消息
WM_KEYDOWN 键盘按下的消息
WM_CHAR 字符按键消息
image.png
WM_LBUTTONDOWN 鼠标左键单击消息

WM_MOVING 窗口移动消息
WM_SIZE 窗口大小改变的消息
需要用到的一个函数:GetClientRect 获取窗口的大小

  1. LRESULT CALLBACK WndProc(
  2. HWND hWnd,
  3. UINT uMessage,
  4. WPARAM wParam,
  5. LPARAM lParam
  6. )
  7. {
  8. switch (uMessage)
  9. {
  10. case WM_CREATE://一般进行一些初始化的操作
  11. break;
  12. case WM_DESTROY:
  13. _trace(L"接到了wm_destory消息\n");
  14. PostQuitMessage(0);//会发出一个WM_QUIT消息
  15. break;
  16. case WM_CLOSE:
  17. _trace(L"接到了wm_close消息\n");
  18. break;
  19. case WM_KEYDOWN:
  20. _trace(L"接到了wm_keydown消息\n");
  21. _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
  22. break;
  23. case WM_CHAR://可见字符
  24. _trace(L"接到了wm_char消息\n");
  25. _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
  26. break;
  27. case WM_LBUTTONDOWN://鼠标左键单击
  28. {
  29. _trace(L"接到了wm_lbuttondown消息\n");
  30. int x = LOWORD(lParam);
  31. int y = HIWORD(lParam);
  32. _trace(L"鼠标左键点击了x:%d,y:%d\n",x,y);
  33. }
  34. case WM_SIZE://窗口大小发生改变了
  35. {
  36. _trace(L"接到了wm_size消息\n");
  37. RECT rc = {};
  38. GetClientRect(hWnd,&rc);
  39. _trace(L"鼠标左键点击了l:%d,r:%d,t:%d,b:%d\n",
  40. rc.left, rc.right,rc.top, rc.bottom);
  41. }
  42. break;
  43. default:
  44. break;
  45. }
  46. return DefWindowProc(hWnd, uMessage, wParam, lParam);
  47. }

关于PostMessage,SendMessage,自定义消息

  1. #define WM_MYMESSAGE WM_USER+2
  2. LRESULT CALLBACK WndProc(
  3. HWND hWnd,
  4. UINT uMessage,
  5. WPARAM wParam,
  6. LPARAM lParam
  7. )
  8. {
  9. switch (uMessage)
  10. {
  11. case WM_CREATE://一般进行一些初始化的操作
  12. break;
  13. case WM_DESTROY:
  14. _trace(L"接到了wm_destory消息\n");
  15. PostQuitMessage(0);//会发出一个WM_QUIT消息
  16. break;
  17. case WM_CLOSE:
  18. _trace(L"接到了wm_close消息\n");
  19. break;
  20. case WM_KEYDOWN:
  21. _trace(L"接到了wm_keydown消息\n");
  22. _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
  23. break;
  24. case WM_CHAR://可见字符
  25. _trace(L"接到了wm_char消息\n");
  26. _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
  27. break;
  28. case WM_LBUTTONDOWN://鼠标左键单击
  29. {
  30. _trace(L"接到了wm_lbuttondown消息\n");
  31. int x = LOWORD(lParam);
  32. int y = HIWORD(lParam);
  33. _trace(L"鼠标左键点击了x:%d,y:%d\n",x,y);
  34. }
  35. case WM_SIZE://窗口大小发生改变了
  36. {
  37. _trace(L"接到了wm_size消息\n");
  38. RECT rc = {};
  39. GetClientRect(hWnd,&rc);
  40. _trace(L"鼠标左键点击了l:%d,r:%d,t:%d,b:%d\n",
  41. rc.left, rc.right,rc.top, rc.bottom);
  42. }
  43. break;
  44. case WM_MYMESSAGE:
  45. {
  46. _trace(L"接到了wm_mymessage消息\n");
  47. _trace(L"lParam:%d,wParam:%d\n", lParam, wParam);
  48. MessageBox(0, 0, 0, 0);
  49. }
  50. break;
  51. default:
  52. break;
  53. }
  54. return DefWindowProc(hWnd, uMessage, wParam, lParam);
  55. }
  1. #define WM_MYMESSAGE WM_USER+2
  2. int main()
  3. {
  4. //FindWindow
  5. PostMessage(
  6. (HWND)0x00360E7C,
  7. WM_MYMESSAGE,
  8. 68, 55
  9. );
  10. }