鱼C论坛

 找回密码
 立即注册
查看: 1219|回复: 4

获取一个窗口的截图

[复制链接]
发表于 2024-5-12 22:46:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我想要通过窗口句柄获取一个窗口的截图,这个窗口是一个外部程序的,只知道进程号,然后回显到当前正在运行的程序窗口上。
这些代码是我从https://learn.microsoft.com/en-us/windows/win32/gdi/capturing-an-image复制下来的,在147行GetDC(NULL)获取桌面窗口句柄,这样可以成功显示。
但是当我把GetDC()参数换成上面这种通过进程ID获取的窗口句柄时,显示都是黑屏的。我不知道是什么原因,求大佬解答
  1. BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
  2. {
  3.         EnumWindowsArg* pArg = (EnumWindowsArg*)lParam;
  4.         DWORD  dwProcessID = 0;
  5.         // 通过窗口句柄取得进程ID
  6.         ::GetWindowThreadProcessId(hwnd, &dwProcessID);
  7.         if (dwProcessID == pArg->dwProcessID)
  8.         {
  9.                 pArg->hwndWindow = hwnd;
  10.                 // 找到了返回FALSE
  11.                 return FALSE;
  12.         }
  13.         // 没找到,继续找,返回TRUE
  14.         return TRUE;
  15. }

  16. ///< 通过进程ID获取窗口句柄
  17. HWND GetWindowHwndByPID(DWORD dwProcessID)
  18. {
  19.         HWND hwndRet = NULL;
  20.         EnumWindowsArg ewa;
  21.         ewa.dwProcessID = dwProcessID;
  22.         ewa.hwndWindow = NULL;
  23.         EnumWindows(EnumWindowsProc, (LPARAM)&ewa);
  24.         if (ewa.hwndWindow)
  25.         {
  26.                 hwndRet = ewa.hwndWindow;
  27.         }
  28.         return hwndRet;
  29. }
复制代码


  1. // GDI_CapturingAnImage.cpp : Defines the entry point for the application.
  2. //

  3. #include "framework.h"
  4. #include "GDI_CapturingAnImage.h"
  5. #include "GetHWND.h"

  6. #define MAX_LOADSTRING 100

  7. // Global Variables:
  8. HINSTANCE hInst;                                // current instance
  9. WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
  10. WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

  11. // Forward declarations of functions included in this code module:
  12. ATOM                MyRegisterClass(HINSTANCE hInstance);
  13. BOOL                InitInstance(HINSTANCE, int);
  14. LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
  15. INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

  16. int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
  17.   _In_opt_ HINSTANCE hPrevInstance,
  18.   _In_ LPWSTR    lpCmdLine,
  19.   _In_ int       nCmdShow)
  20. {
  21.   UNREFERENCED_PARAMETER(hPrevInstance);
  22.   UNREFERENCED_PARAMETER(lpCmdLine);

  23.   // TODO: Place code here.

  24.   // Initialize global strings
  25.   LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  26.   LoadStringW(hInstance, IDC_GDICAPTURINGANIMAGE, szWindowClass, MAX_LOADSTRING);
  27.   MyRegisterClass(hInstance);

  28.   // Perform application initialization:
  29.   if (!InitInstance(hInstance, nCmdShow))
  30.   {
  31.     return FALSE;
  32.   }

  33.   HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDICAPTURINGANIMAGE));

  34.   MSG msg;

  35.   // Main message loop:
  36.   while (GetMessage(&msg, nullptr, 0, 0))
  37.   {
  38.     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  39.     {
  40.       TranslateMessage(&msg);
  41.       DispatchMessage(&msg);
  42.     }
  43.   }

  44.   return (int)msg.wParam;
  45. }

  46. //
  47. //  FUNCTION: MyRegisterClass()
  48. //
  49. //  PURPOSE: Registers the window class.
  50. //
  51. ATOM MyRegisterClass(HINSTANCE hInstance)
  52. {
  53.   WNDCLASSEXW wcex;

  54.   wcex.cbSize = sizeof(WNDCLASSEX);

  55.   wcex.style = CS_HREDRAW | CS_VREDRAW;
  56.   wcex.lpfnWndProc = WndProc;
  57.   wcex.cbClsExtra = 0;
  58.   wcex.cbWndExtra = 0;
  59.   wcex.hInstance = hInstance;
  60.   wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDICAPTURINGANIMAGE));
  61.   wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
  62.   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  63.   wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_GDICAPTURINGANIMAGE);
  64.   wcex.lpszClassName = szWindowClass;
  65.   wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

  66.   return RegisterClassExW(&wcex);
  67. }

  68. //
  69. //   FUNCTION: InitInstance(HINSTANCE, int)
  70. //
  71. //   PURPOSE: Saves instance handle and creates main window
  72. //
  73. //   COMMENTS:
  74. //
  75. //        In this function, we save the instance handle in a global variable and
  76. //        create and display the main program window.
  77. //
  78. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  79. {
  80.   hInst = hInstance; // Store instance handle in our global variable

  81.   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  82.     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

  83.   if (!hWnd)
  84.   {
  85.     return FALSE;
  86.   }

  87.   ShowWindow(hWnd, nCmdShow);
  88.   UpdateWindow(hWnd);

  89.   return TRUE;
  90. }

  91. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  92. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  93. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  94. // PARTICULAR PURPOSE.
  95. //
  96. // Copyright (c) Microsoft Corporation. All rights reserved

  97. //
  98. //   FUNCTION: CaptureAnImage(HWND hWnd)
  99. //
  100. //   PURPOSE: Captures a screenshot into a window ,and then saves it in a .bmp file.
  101. //
  102. //   COMMENTS:
  103. //
  104. //      Note: This function attempts to create a file called captureqwsx.bmp
  105. //        

  106. int CaptureAnImage(HWND hWnd)
  107. {
  108.   HDC hdcScreen;
  109.   HDC hdcWindow;
  110.   HDC hdcMemDC = NULL;
  111.   HBITMAP hbmScreen = NULL;
  112.   BITMAP bmpScreen;
  113.   DWORD dwBytesWritten = 0;
  114.   DWORD dwSizeofDIB = 0;
  115.   HANDLE hFile = NULL;
  116.   char* lpbitmap = NULL;
  117.   HANDLE hDIB = NULL;
  118.   DWORD dwBmpSize = 0;

  119.   // Retrieve the handle to a display device context for the client
  120.   // area of the window.
  121.   // HWND nhdcScreen = GetWindowHwndByPID(27380);
  122.   hdcScreen = GetDC(NULL); // source

  123.   hdcWindow = GetDC(hWnd);  // destination

  124.   // Create a compatible DC, which is used in a BitBlt from the window DC.
  125.   hdcMemDC = CreateCompatibleDC(hdcWindow);

  126.   if (!hdcMemDC)
  127.   {
  128.     MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK);
  129.     goto done;
  130.   }

  131.   // Get the client area for size calculation.
  132.   RECT rcClient;
  133.   GetClientRect(hWnd, &rcClient);

  134.   // This is the best stretch mode.
  135.   SetStretchBltMode(hdcWindow, HALFTONE);

  136.   // The source DC is the entire screen, and the destination DC is the current window (HWND).
  137.   if (!StretchBlt(hdcWindow,
  138.     0, 0,
  139.     rcClient.right, rcClient.bottom,
  140.     hdcScreen,
  141.     0, 0,
  142.     GetSystemMetrics(SM_CXSCREEN),
  143.     GetSystemMetrics(SM_CYSCREEN),
  144.     SRCCOPY))
  145.   {
  146.     MessageBox(hWnd, L"StretchBlt has failed", L"Failed", MB_OK);
  147.     goto done;
  148.   }

  149.   // Create a compatible bitmap from the Window DC.
  150.   hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);

  151.   if (!hbmScreen)
  152.   {
  153.     MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK);
  154.     goto done;
  155.   }

  156.   // Select the compatible bitmap into the compatible memory DC.
  157.   SelectObject(hdcMemDC, hbmScreen);

  158.   // Bit block transfer into our compatible memory DC.
  159.   if (!BitBlt(hdcMemDC,
  160.     0, 0,
  161.     rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
  162.     hdcWindow,
  163.     0, 0,
  164.     SRCCOPY))
  165.   {
  166.     MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
  167.     goto done;
  168.   }

  169.   // Get the BITMAP from the HBITMAP.
  170.   GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);

  171.   BITMAPFILEHEADER   bmfHeader;
  172.   BITMAPINFOHEADER   bi;

  173.   bi.biSize = sizeof(BITMAPINFOHEADER);
  174.   bi.biWidth = bmpScreen.bmWidth;
  175.   bi.biHeight = bmpScreen.bmHeight;
  176.   bi.biPlanes = 1;
  177.   bi.biBitCount = 32;
  178.   bi.biCompression = BI_RGB;
  179.   bi.biSizeImage = 0;
  180.   bi.biXPelsPerMeter = 0;
  181.   bi.biYPelsPerMeter = 0;
  182.   bi.biClrUsed = 0;
  183.   bi.biClrImportant = 0;

  184.   dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

  185.   // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
  186.   // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
  187.   // have greater overhead than HeapAlloc.
  188.   hDIB = GlobalAlloc(GHND, dwBmpSize);
  189.   lpbitmap = (char*)GlobalLock(hDIB);

  190.   // Gets the "bits" from the bitmap, and copies them into a buffer
  191.   // that's pointed to by lpbitmap.
  192.   GetDIBits(hdcWindow, hbmScreen, 0,
  193.     (UINT)bmpScreen.bmHeight,
  194.     lpbitmap,
  195.     (BITMAPINFO*)&bi, DIB_RGB_COLORS);

  196.   // A file is created, this is where we will save the screen capture.
  197.   hFile = CreateFile(L"captureqwsx.bmp",
  198.     GENERIC_WRITE,
  199.     0,
  200.     NULL,
  201.     CREATE_ALWAYS,
  202.     FILE_ATTRIBUTE_NORMAL, NULL);

  203.   // Add the size of the headers to the size of the bitmap to get the total file size.
  204.   dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

  205.   // Offset to where the actual bitmap bits start.
  206.   bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

  207.   // Size of the file.
  208.   bmfHeader.bfSize = dwSizeofDIB;

  209.   // bfType must always be BM for Bitmaps.
  210.   bmfHeader.bfType = 0x4D42; // BM.

  211.   WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
  212.   WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
  213.   WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);

  214.   // Unlock and Free the DIB from the heap.
  215.   GlobalUnlock(hDIB);
  216.   GlobalFree(hDIB);

  217.   // Close the handle for the file that was created.
  218.   CloseHandle(hFile);

  219.   // Clean up.
  220. done:
  221.   DeleteObject(hbmScreen);
  222.   DeleteObject(hdcMemDC);
  223.   ReleaseDC(NULL, hdcScreen);
  224.   ReleaseDC(hWnd, hdcWindow);

  225.   return 0;
  226. }

  227. //
  228. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  229. //
  230. //  PURPOSE: Processes messages for the main window.
  231. //
  232. //  WM_COMMAND  - process the application menu
  233. //  WM_PAINT    - Paint the main window
  234. //  WM_DESTROY  - post a quit message and return
  235. //
  236. //
  237. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  238. {
  239.   switch (message)
  240.   {
  241.   case WM_COMMAND:
  242.   {
  243.     int wmId = LOWORD(wParam);
  244.     // Parse the menu selections:
  245.     switch (wmId)
  246.     {
  247.     case IDM_ABOUT:
  248.       DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
  249.       break;
  250.     case IDM_EXIT:
  251.       DestroyWindow(hWnd);
  252.       break;
  253.     default:
  254.       return DefWindowProc(hWnd, message, wParam, lParam);
  255.     }
  256.   }
  257.   break;
  258.   case WM_PAINT:
  259.   {
  260.     PAINTSTRUCT ps;
  261.     HDC hdc = BeginPaint(hWnd, &ps);
  262.     CaptureAnImage(hWnd);
  263.     EndPaint(hWnd, &ps);
  264.   }
  265.   break;
  266.   case WM_DESTROY:
  267.     PostQuitMessage(0);
  268.     break;
  269.   default:
  270.     return DefWindowProc(hWnd, message, wParam, lParam);
  271.   }
  272.   return 0;
  273. }

  274. // Message handler for about box.
  275. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  276. {
  277.   UNREFERENCED_PARAMETER(lParam);
  278.   switch (message)
  279.   {
  280.   case WM_INITDIALOG:
  281.     return (INT_PTR)TRUE;

  282.   case WM_COMMAND:
  283.     if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  284.     {
  285.       EndDialog(hDlg, LOWORD(wParam));
  286.       return (INT_PTR)TRUE;
  287.     }
  288.     break;
  289.   }
  290.   return (INT_PTR)FALSE;
  291. }
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-26 04:14

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表