如何集成开源C程序而不是通过系统调用调用其可执行文件?

发布于 2024-10-09 03:31:34 字数 302 浏览 0 评论 0原文

我有一个可执行文件(fossil scm),我的程序通过 ::CreateProcess windows 调用从外部调用它。然后捕获 stdout 和 stderr。由于化石的源代码是可用的,我更愿意用它创建一个静态库并直接发出调用。目前,与化石的通信是通过命令行参数完成的,而返回的通信是通过进程返回代码、stdout 和 stderr 完成的。 Fossil 通过 printf 和 fprintf 调用写入 stdout/err。

在最小化化石来源改变的情况下解决这个问题的最佳方法是什么?是否有可靠且跨平台的方法来拦截 stdout/err 并将其发送到内存缓冲区?

I have an executable (fossil scm) that is being invoked by my program externally through ::CreateProcess windows call. The stdout and stderr are then captured. Since the source code for fossil is available, I would prefer to create a static library out of it and issue calls directly. Currently, communication to fossil is done through the command line parameters, and the communication back is through the process return code, stdout and stderr. Fossil writes to stdout/err through printf and fprintf calls.

What is the best way to solve this with minimum alteration of fossil source? Is there a reliable and cross-platform way to intercept stdout/err and send it into a memory buffer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

平生欢 2024-10-16 03:31:34

你说你想要

拦截stdout/err并将其发送到
内存缓冲区

这表明您不想为 SCM 程序引入 API,而是希望在不更改现有代码的情况下继续解析文本输出。如果是这样,那么我认为没有必要改变你当前的方法。与当前方法相比,使用内存缓冲区和静态链接到底能获得什么?

You say that you want to

intercept stdout/err and send it into
a memory buffer

This would indicate that you don't want to introduce an API for the SCM program and instead wish to carry on parsing the textual output without changing your existing code. If that is so then I see no point in changing from your current approach. What exactly is to be gained by using a memory buffer and static linking over the current approach?

巡山小妖精 2024-10-16 03:31:34

您可以按照如下步骤执行此操作:

  • 将化石的 main 函数重命名为其他名称,以便您可以调用它
  • 在调用化石的 main 之前,将 stdout/stderr 重定向到您选择的文件:

freopen("filename.out" , "w", stdout);

  • 形成一个参数数组,调用fossil_main,从文件中读取输出。
  • 您需要恢复标准输出流状态;没有跨平台机制,但您可以使用一些伪句柄(即 Windows 上的 CONOUT$)。

但是,请注意,这是脆弱的:

  • 可能有一些全局变量应该在 main() 开始时被初始化为零,但对于第二次调用 main() 则不是这样,
  • 化石可能会更改某些进程/线程状态(区域设置、当前目录等),您将无法可靠地恢复它。一个特别糟糕的情况是调用 exit(n)。
  • 进程终止时不会进行通常的清理 - 期望文件句柄保持打开状态(这样,如果在没有共享的情况下打开它们,您将无法再次打开它们)、内存泄漏等。
  • 显然,现在崩溃/挂起在化石中会更难处理(有时你可以解决这个问题)

通常,你可以这样做,但除非你有充分的理由(即性能)并且你准备好面对后果并自己修复错误,否则不要这样做。

You can do it in steps like these:

  • Rename the fossil's main function to something else so that you can call it
  • Before calling fossil's main, redirect stdout/stderr to the file of your choice with:

freopen("filename.out", "w", stdout);

  • Form an argument array, call fossil_main, read the output from the files.
  • You'll need to restore stdout stream state; there is no cross-platform mechanism for that, but you can use some pseudo-handles (i.e. CONOUT$ on Windows).

However, please note that this is fragile:

  • There may be global variables that are supposed to be zero-initialized at the beginning of main(), which will not be true for the second call to main()
  • fossil may change some process/thread state (locale, current directory, etc.), you won't be able to reliably restore it. An especially bad case of this is calling exit(n).
  • There will be no usual cleanup on process termination - expect file handles that are left open (so that you would not be able to open them again, if they're opened without sharing), memory leaks, etc.
  • Obviously, now crashes/hangs in fossil will be harder to handle (you can sometimes work around that)

Generally, you can do this, but don't unless you have a good reason to (i.e. performance) and you're ready to face the consequences and fix bugs yourself.

寂寞陪衬 2024-10-16 03:31:34

将化石转变为共享库,然后从您的自定义程序中使用它。

Turn fossil into a shared library, and then use that from your custom program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文