【问题标题】:What is the easiest way to send text from a child GUI process to a console parent?将文本从子 GUI 进程发送到控制台父进程的最简单方法是什么?
【发布时间】:2013-03-03 19:56:08
【问题描述】:

我使用 C++ 编写了两个进程。一种是我的控制台应用程序使用CreateProcess API 调用的GUI 进程。我需要将文本从 GUI 应用(子)传递到控制台应用(父)。文本的数量可以是任意的——从几行到 KB 的文本。

最简单的方法是什么?

附言。我可以访问这两个进程的源代码。

【问题讨论】:

  • pipes 怎么样?
  • 哎呀。我一直在寻找简单的东西......但是谢谢,我也想到了。
  • 另外,如果我没记错的话,你可以告诉CreateProcess 使用特定的文件句柄来用于新进程的stdin/stdout。您可以创建一个anonymous pipe 并将写句柄设置为新进程'stdout,然后新进程只需写入stdout(如std::cout << something)并且父进程可以读取它。使用 WIN32 文件句柄并不难。
  • 为什么不能直接向窗口发送用户定义的消息?
  • @JoachimPileborg:这是个好主意!问题是如何从 GUI 应用程序获得这样的输出匿名管道?

标签: c++ windows winapi console-application


【解决方案1】:

控制台应用程序可以创建一个 WinAPI 窗口(不可见),以便它可以接收消息(取自 Delphi 中的 AllocateHWND 函数的想法)。

另一种解决方案是使用命名管道。

另一种解决方案是通过 TCP/IP 在本地发送数据。

如果这些字符串只是调试字符串,请考虑使用 WinAPI 中的 OutputDebugString 函数,并使用像 SysInternals'DbgView 这样的程序来捕获它们。

【讨论】:

  • 这也是个好主意。虽然,不,这不是用于调试目的。
【解决方案2】:

如果 GUI 应用程序是真正的图形化应用程序,您就不会真正使用标准输出流(即std::cout)。这可以重复用于输出到您的控制台应用程序。

首先你需要使用CreatePipe创建一个匿名管道:

HANDLE hPipeRead;
HANDLE hPipeWrite;

CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0);

现在您必须处理可以用作普通文件句柄的句柄;一个用于读取,另一个用于写入。写入句柄应设置为您创建的新进程的标准输出:

STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdOutput = hPipeWrite;  // Standard output of the new process
                                      // is set to the write end of the pipe

CreateProcess(
    lpApplicationName,
    lpCommandLine,
    NULL,
    NULL,
    FALSE,
    0,
    NULL,
    NULL,
    &startupInfo,  // Use our startup information
    &processInfo);

现在每当子进程需要写入父进程时,它只需要使用标准输出:

std::cout << "In child process, are you getting this parent?";

父级使用ReadFile从管道的读取端读取:

char buffer[256];
DWORD bytesRead = 0;

ReadFile(hPipeRead, buffer, sizeof(buffer), &bytesRead, NULL);

注意:我有一段时间没有做过WIN32编程,所以可能有些细节有误。但希望足以让您入门。


Inter Process Communications (IPC)当然还有很多其他方式,包括(但不限于)socket、文件、共享内存等。

【讨论】:

  • 非常感谢您提供代码示例。我会试试看。我唯一的问题是管道尺寸。当您创建它时,您将其大小指定为 0。这在理论上是否意味着它可以包含尽可能多的数据?还是有一些默认限制?
  • @ahmd0 来自CreatePipe 的链接手册页:“如果此参数为零,则系统使用默认缓冲区大小。”我不知道默认缓冲区大小到底是多少,但除非你开始发送兆字节的数据,否则应该没有问题。
  • 谢谢。我看到了文档。 unless you start to send megabytes of data there should be no problem -- 这正是问题在以后发生的方式。
  • @ahmd0 对于这么多的数据,一个文件可能会更好,然后使用管道发送文件名。但请记住,套接字也有以千字节计的缓冲区,只要接收方能够足够快地处理数据,您仍然可以毫无问题地发送几千兆字节的数据。
【解决方案3】:

简单的方法可能是让子应用程序实际上是一个控制台应用程序,即使它也创建窗口。

在这种情况下,您可以让您的父母使用_popen 生成孩子,而孩子只需将输出写入其正常的stdout/std::cout_popen 返回 FILE *,因此父级可以读取子级的输出,就像它通常读取文件一样(好吧,通常对于 C 来说)。

【讨论】:

  • 感谢您的建议。不幸的是,GUI 应用程序中涉及的代码太多,无法对其进行更改。实现上面建议的管道服务器/客户端方法会更容易。
  • 无法通过某种基于线程的 WM_COPYDATA 消息发送该文本,是吗?
  • @ahmd0:将 GUI 应用程序转换为控制台应用程序相当简单:将启动函数从 WinMain 重命名为 main。它们采用不同的参数,但无论如何您通常都会忽略它们。您可以执行 WM_COPYDATA(使用 PostThreadMessage),但这有点难看。另一种可能性是让 GUI 应用程序编写调试消息 (OutputDebugString) 以供父级拦截(父级将充当调试器)。
  • 哦 - 我刚刚回答的基本想法相同 - 被你关于让孩子成为控制台应用程序的谈话抛出。无论如何,GUI 应用程序都不能在 Windows 下写入其标准输出吗?
  • @TonyD:他们可以写信,但它不会去任何地方——他们写的东西会被丢弃。
【解决方案4】:

可以使用各种方法,其中一些已在上面给出。哪一个最简单取决于您的任务。
我还可以向您推荐在 IPC 中广泛使用的文件映射技术,例如。 dll 是使用文件映射实现的。
它允许多个进程同时共享相同的资源,访问是随机的而不是必然的。
以下是主要实现步骤:

1. 进程 A 创建一个文件;
2. 进程 A 为该文件创建一个命名系统对象 mappedfile(mappedfile 分配内存);
3. 进程 A 创建一个系统对象 viewOfMapped 文件(这允许将进程 A 的某些区域映射到由 mappedFile 分配的主内存中的页面);
4 . 进程B创建命名系统对象mappedfile(名称应与进程A使用的名称相似),viewOfMapped文件;
5.通过viewOfMapped进程返回的指针可以共享相同的记忆。 示例:
流程 A:

/* 1. file creation */
    hFile = CreateFile(0, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,  CREATE_ALWAYS,  FILE_ATTRIBUTE_NORMAL,  
    NULL); 

/* 2. Create file mapping */
    wchar_t lpName[] = L"fileMappingObject0";
    HANDLE hfileMappingObject;
    hfileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, lpName);

/* 3. Create MappedFileViewOfFile */
    void* p = (MapViewOfFile(hfileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, 0));

流程 B:

/* 2. Create file mapping */
        wchar_t lpName[] = L"fileMappingObject0";
        HANDLE hfileMappingObject;
        hfileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, lpName);

    /* 3. Create MappedFileViewOfFile */
        void* p = (MapViewOfFile(hfileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, 0));

这个方法比较简单,也很强大。

【讨论】:

  • 感谢代码示例。我自己喜欢文件映射技术,除了它有两个警告。首先,映射内存的大小是有限的并且仅限于页面大小。因此需要编写某种编组机制来管理传输。其次,如果进程以不同的提升级别运行,则需要首先从提升的进程设置安全描述符,这可能会产生令人讨厌的竞争条件。除此之外,它可能是最快的 IPC。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2014-10-08
  • 2011-08-14
相关资源
最近更新 更多