gpt4 book ai didi

c++ - 程序在 TCL exec 中可以正常工作

转载 作者:行者123 更新时间:2023-11-28 03:00:57 32 4
gpt4 key购买 nike

我编写/借用了以下 C++ 程序,它根据窗口名称截取窗口的屏幕截图。

当我通过 Windows 命令提示符运行该程序时,它可以正常工作。但是,当我使用 exec 命令调用 TCL 脚本中的程序时,wish86 应用程序崩溃了。

为什么程序可以通过命令行运行,而不能使用 exec 命令?

示例:screenshot.exe calc.bmp “计算器”

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "gdiplus.lib")

using namespace Gdiplus;

// From http://msdn.microsoft.com/en-us/library/ms533843%28VS.85%29.aspx
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for(UINT j = 0; j < num; ++j) {

if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) {
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}

free(pImageCodecInfo);
return -1; // Failure
}

int wmain(int argc, wchar_t** argv)
{

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

HDC desktopdc;
HDC mydc;
HBITMAP mybmp;

desktopdc = GetDC(NULL);

if(desktopdc == NULL) {
return -1;
}

// If three arguments were passed, capture the specified window
if(argc == 3) {

RECT rc;

// Convert wchar_t[] to char[]
char title[512] = {0};

wcstombs(title, argv[2], wcslen(argv[2]));

HWND hwnd = FindWindow(NULL, title); //the window can't be min

if(hwnd == NULL) {
return -1;
}

GetWindowRect(hwnd, &rc);
mydc = CreateCompatibleDC(desktopdc);

mybmp = CreateCompatibleBitmap(desktopdc, rc.right - rc.left, rc.bottom - rc.top);
SelectObject(mydc,mybmp);

//Print to memory hdc
PrintWindow(hwnd, mydc, PW_CLIENTONLY);

} else {

// Capture the entire screen
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);

mydc = CreateCompatibleDC(desktopdc);

mybmp = CreateCompatibleBitmap(desktopdc, width, height);
HBITMAP oldbmp = (HBITMAP)SelectObject(mydc, mybmp);
BitBlt(mydc,0,0,width,height,desktopdc,0,0, SRCCOPY|CAPTUREBLT);
SelectObject(mydc, oldbmp);
}

const wchar_t* filename = (argc > 1) ? argv[1] : L"screenshot.png";
Bitmap* b = Bitmap::FromHBITMAP(mybmp, NULL);
CLSID encoderClsid;
Status stat = GenericError;
if (b && GetEncoderClsid(L"image/png", &encoderClsid) != -1) {
stat = b->Save(filename, &encoderClsid, NULL);
}

if (b)
delete b;

// cleanup
GdiplusShutdown(gdiplusToken);
ReleaseDC(NULL, desktopdc);
DeleteObject(mybmp);
DeleteDC(mydc);
DeleteDC(desktopdc);
return stat == Ok;
}

最佳答案

正如您在评论中提到的那样,真正的问题是当您尝试对调用屏幕截图程序的 Tcl 进程拥有的 GUI 窗口进行屏幕截图时代码挂起(使用 exec ).这是因为 Windows 希望进程为它的消息泵提供服务——Tcl 将其映射到事件循环——但是消息处理已经停止,因为 Tcl 正忙于阻塞等待子进程完成。 (这就是 exec 的工作方式以及它一直以来的工作方式。)这会阻塞死锁中的所有内容,听起来解锁处理得不是很优雅。

由于您的程序不读取任何输入或产生任何输出(好吧,它会同时执行这两项操作,但通过参数和“知名”文件),您需要一种在后台运行程序的方法能够找出它何时完成。这意味着我们不想使用exec;只有两种操作模式:阻塞等待,或完全断开异步(如果最后一个参数是 &)。前者是问题,后者没有给我们需要的信息。

相反,我们需要一个管道以便我们可以在后台截屏同时仍在处理事件,并且我们需要设置一个fileevent以便我们找出当事情完成时(因为这是一种事件,在幕后)。

set thepipeline [open |[list screenshot.exe $filename $windowname] r]
fileevent $thepipeline readable [list doneScreenshot $thepipeline $filename]
proc doneScreenshot {pipe filename} {
# Pipelines become readable when either:
# 1. there's some data to read, or
# 2. the pipe gets closed.
# It's option 2 that happens here.
close $pipe
puts "screenshot now available in $filename"
}

因为基于 Tk 的 Tcl 程序无论如何都会运行一个事件循环,我们不会使用 vwait 来创建一个。 (编写异步代码有时会有点费脑筋;考虑“回调”而不是“程序流”。除非您使用的是 Tcl 8.6,否则我们可以使用协程来解决问题。)

旁注:您可能不想将 $filename 传递给 screenshot.exe,而是传递给 [file nativename [file normalize $filename] ],但这不是你在这里遇到的问题。而且您不需要在 $windowname 周围手动添加引号; Tcl 运行时会在必要时执行此操作(假设您正在为屏幕截图程序使用 MSVC 运行时,而不是自己进行奇怪的处理)。

关于c++ - 程序在 TCL exec 中可以正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20863905/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com