当前位置:C++技术网 > 资讯 > 打造自己的屏幕截图软件(QQ截图功能实现),我照着做了,但是出现了问题

打造自己的屏幕截图软件(QQ截图功能实现),我照着做了,但是出现了问题

更新时间:2018-11-10 10:35:20浏览次数:1+次

// Win32Project2.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Win32Project2.h"

#define MAX_LOADSTRING 100

// 全局变量: 
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
HDC g_srcMemDc; // - 源桌面截图 
HDC g_grayMemDc; // - 灰度桌面截图 
int screenW; // - 电脑屏幕的宽 
int screenH; // - 电脑屏幕的高 
RECT rect = { 0 }; // - 画图的矩形区域 
bool isSelect = false; // - 是否已经选中区域 
bool isDown = false; // - 是否已经按下左键
// 此代码模块中包含的函数的前向声明: 
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

  // TODO:  在此放置代码。
MSG msg;
HACCEL hAccelTable;

// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_POPUP,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

ShowWindow(hWnd, SW_MAXIMIZE);

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

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT2));

// 主消息循环: 
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
//  函数:  MyRegisterClass()
//
//  目的:  注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT2));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
//   函数:  InitInstance(HINSTANCE, int)
//
//   目的:  保存实例句柄并创建主窗口
//
//   注释: 
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

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

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

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数:  WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    处理主窗口的消息。
//
//  WM_COMMAND - 处理应用程序菜单
//  WM_PAINT - 绘制主窗口
//  WM_DESTROY - 发送退出消息并返回
//
//

void CovertToGrayBitmap(HBITMAP hSourceBmp, HDC sourceDc)
{
HBITMAP retBmp = hSourceBmp;
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(sourceDc, retBmp, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);

BYTE* bits = new BYTE[bmpInfo.bmiHeader.biSizeImage];
GetBitmapBits(retBmp, bmpInfo.bmiHeader.biSizeImage, bits);

int bytePerPixel = 4;//默认32位 
if (bmpInfo.bmiHeader.biBitCount == 24)
{
bytePerPixel = 3;
}
for (DWORD i = 0; i<bmpInfo.bmiHeader.biSizeImage; i += bytePerPixel)
{
BYTE r = *(bits + i);
BYTE g = *(bits + i + 1);
BYTE b = *(bits + i + 2);
*(bits + i) = *(bits + i + 1) = *(bits + i + 2) = (r + b + g) / 3;
}
SetBitmapBits(hSourceBmp, bmpInfo.bmiHeader.biSizeImage, bits);
delete[] bits;
}

void ScreenCapture()
{
HDC disDc = CreateDC(L"DISPLAY", 0, 0, 0); // - 创建一个DC,与桌面相关的 
screenW = GetDeviceCaps(disDc, HORZRES); // - 水平分辨率 
screenH = GetDeviceCaps(disDc, VERTRES); // - 垂直分辨率 

//获取桌面截图 
g_srcMemDc = CreateCompatibleDC(disDc); // - 创建一个兼容DC(内存DC),与桌面DC相关的 
HBITMAP hbitMap = CreateCompatibleBitmap(disDc, screenW, screenH); // - 模拟一张画布,其中没有数据 
SelectObject(g_srcMemDc, hbitMap); // - 将画布选入内存DC,其中还是没有数据 
//将桌面画到画布上,将屏幕的dc中的画图,拷贝至内存DC中 
BitBlt(g_srcMemDc, 0, 0, screenW, screenH, disDc, 0, 0, SRCCOPY); // - 整个桌面被画到memDc上 

//获取屏幕的灰度图片 
g_grayMemDc = CreateCompatibleDC(disDc); // - 创建一个兼容DC,存放灰度图片 
HBITMAP grayMap = CreateCompatibleBitmap(disDc, screenW, screenH); // - 模拟一张画布,其中没有数据 
SelectObject(g_grayMemDc, grayMap); // - 将画图选入内存DC,其中还是没有数据的 
BitBlt(g_grayMemDc, 0, 0, screenW, screenH, disDc, 0, 0, SRCCOPY); // - 将屏幕的dc中的画图,拷贝至内存DC中 
CovertToGrayBitmap(grayMap, g_grayMemDc); // - 将彩色图片转换为灰度图片 

DeleteObject(hbitMap);
DeleteObject(grayMap);
DeleteObject(disDc);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择: 
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT: // - 屏幕绘制消息,画线条,画图片 
{
  PAINTSTRUCT ps;
  HDC hdc = BeginPaint(hWnd, &ps); // - 代表当前窗口 

  //将灰度图像和变亮部分画到memDc中(兼容DC) 
  HDC memDc = CreateCompatibleDC(hdc);
  HBITMAP bmp = CreateCompatibleBitmap(hdc, screenW, screenH);
  SelectObject(memDc, bmp);
  BitBlt(memDc, 0, 0, screenW, screenH, g_grayMemDc, 0, 0, SRCCOPY);
  SelectObject(memDc, hBrush);
  SelectObject(memDc, hPen);

  if (isDown || isSelect)
  {
  BitBlt(memDc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, g_srcMemDc, rect.left, rect.top, SRCCOPY);// - 选中的区域变亮,将变亮的部分画到memDc 
  Rectangle(memDc, rect.left, rect.top, rect.right, rect.bottom);// - 画矩形 
  }
  //最后将灰度和变亮的部分一起画到桌面 
  BitBlt(hdc, 0, 0, screenW, screenH, memDc, 0, 0, SRCCOPY);
  DeleteObject(bmp);
  DeleteObject(memDc);
  EndPaint(hWnd, &ps);
}
break;
case WM_MOUSEMOVE:
{
if (isDown && !isSelect)
{
POINT pt;
GetCursorPos(&pt);
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, false);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
ScreenCapture();
break;
case WM_LBUTTONDBLCLK: // - 双击复制 
{
  POINT pt;
  GetCursorPos(&pt);
  if (PtInRect(&rect, pt))
  {
  if (isSelect) // - 选中区域了才去拷贝 
  {
  CopyBitmapToClipBoard(); // - 拷贝选中区域到粘贴板 
  }
  }
  InvalidateRgn(hWnd, 0, false);
  ShowWindow(hWnd, SW_MINIMIZE);
  isDown = false;
  isSelect = false;
}
break;
case WM_LBUTTONDOWN:
{
  if (!isSelect) // - 如果没有选中才能按左键 
  {
  POINT pt;
  GetCursorPos(&pt); // - 得到当前光标位置 
  rect.left = pt.x;
  rect.top = pt.y;
  rect.right = pt.x;
  rect.bottom = pt.y;
  InvalidateRgn(hWnd, 0, false);
  isDown = true;
  }
}
break;
case WM_LBUTTONUP:
{
if (isDown == TRUE &&!isSelect) // - 鼠标按下了才计算矩形大小 
{
POINT pt;
GetCursorPos(&pt); // - 得到当前光标位置 
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, false);
isSelect = true; // - 弹起的时候,表示区域已经选中 
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

 1>------ 已启动生成:  项目: Win32Project2, 配置: Debug Win32 ------
1>  stdafx.cpp
1>  Win32Project2.cpp
1>c:\users\think\documents\visual studio 2013\projects\win32project2\win32project2\win32project2.cpp(223): error C2065: “hBrush”: 未声明的标识符
1>c:\users\think\documents\visual studio 2013\projects\win32project2\win32project2\win32project2.cpp(224): error C2065: “hPen”: 未声明的标识符
1>c:\users\think\documents\visual studio 2013\projects\win32project2\win32project2\win32project2.cpp(264): error C3861: “CopyBitmapToClipBoard”:  找不到标识符

========== 生成:  成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

我照着打造自己的屏幕截图软件(QQ截图功能实现)出现了问题


C++技术网会员解答:

    感谢您对C++技术网的支持。

    未声明的标识符,意思是找不到这些标志符的定义。代码只是直接用了这些标志符。至于这些标志符未定义,不是问题,而是写代码是应该就先定义好的。对于变量,可以自己在使用前定义一下。而对于函数,则需要查找对应的头文件,并包含到代码中。函数的头文件,请使用MSDN来查询函数,并找到对应的头文件。

    别人分享的代码,可能只是给了核心的代码,一些细节丢失,都是很正常的,需要你自己去根据错误提示来补全代码,而作者分享的目的也应该是能够补全代码的人。如果基本的代码无法完成补全修复错误,可能你现在就无法读懂代码。

    此程序代码是Win32程序代码,如果不熟悉Windows编程,推荐书籍《Windows程序设计》,再配合阅读C++技术网win32教程《Windows零基础入门教程》。