【问题标题】:How do I run a C program as a thread from a C# System Tray Application?如何从 C# 系统托盘应用程序将 C 程序作为线程运行?
【发布时间】:2014-12-19 01:53:41
【问题描述】:

我有一个 C 控制台应用程序,它曾经在 WindowsCMD 终端的前台运行,并接受用户击键输入。但是现在需要将其移到后台,并且不需要用户输入。

我已经创建了一个系统托盘,它通过右键退出和右键单击正确实现。并有一个执行该功能的终端程序。

我希望能够创建一个线程来调用我现有程序中不需要终端的函数,而不是再次重写程序。

只是为了强调一点,控制台交互方面已从代码中删除,应用程序对按键的响应等也已删除。希望这能稍微澄清一下。

问题:这可能吗?我将如何实现这一点?

(我通常不是使用更多嵌入式 C 的 PC 程序员,所以 .NET 对我来说很陌生。非常感谢任何帮助)

【问题讨论】:

  • 一个 C 程序 太模糊了。我猜你的意思是用C编写的控制台应用程序,在这种情况下答案是,控制台应用程序不能作为托盘应用程序运行而无需修改;它至少必须有一个窗口句柄和一个消息循环才能接收控制台应用程序没有的通知。
  • 托盘应用程序可以启动进程
  • 卢克,您的 C 程序是否期望任何按键、用户输入之王?
  • 我认为为了做到这一点,你的C程序中的函数必须使用_declspec(dllexport)之类的东西导出
  • 是的,最好的方法几乎可以肯定是将您的 C 程序重新构建为导出一个或多个函数的 DLL。我相当确定您可以从 C# 调用任意 DLL,尽管我不熟悉该方法。

标签: c# c windows multithreading system-tray


【解决方案1】:

我不确定这是否是您要问的,但如果您要问是否可以从 C# 应用程序调用 C 程序中的函数,那么您可以。只要您有 C 程序的源代码。为了使 C 中的函数可用于 C# 程序,必须将它们导出。我给你举个例子:

MyAddDll.h

#include <iostream>

extern "C"
{
    __declspec(dllexport) int Add(int a, int b);
}

这里重要的是你的函数被包裹在一个extern "C" 块中。基本上,这告诉编译器不要破坏函数的名称。另一个重要的部分是__declspec(dllexport)。这告诉编译器您要导出此函数,以便可以从另一个程序(如您的 C# 程序)调用它。

MyAddDll.cpp

#include <iostream>
#include "MyAddDll.h"

extern "C"
{
    __declspec(dllexport) int Add(int a, int b)
    {
        return (a + b);
    }
}

同样,您的代码被包装在 extern "C" 块中,您需要将 __declspec(dllexport) 添加到函数中。现在您可以将其编译为 DLL 文件或 EXE 文件。现在从 C# 调用它,它非常简单:

MyProgram.cs

class Program
{
    [DllImport("c:\\PathToMyDllOrExeFile\\MyAddDll.dll")]
    public static extern int Add(int val1, int val2);

    static void Main(string[] args)
    {
        int val1 = 12;
        int val2 = 4;
        Console.WriteLine("{0} + {1} = {2}", val1, val2, Add(val1, val2));
    }
}

就是这样!

一个“陷阱”是确保您的 C 程序和您的 C# 程序都编译为 32 位或 64 位。您不能将 C 程序编译为 64 位,而将 C# 程序编译为 32 位。它们必须使用相同的位长。

【讨论】:

  • 您好,谢谢,非常有帮助。如果我有多个 C 文件,它们是否都需要包装在 DLL 中,或者如果我将 main 包装为 DLL,它可以调用其他 C 文件吗?
  • @Luke - 任何包含您希望能够在 C# 中调用的函数的 C 文件都需要包装
  • 谢谢。这应该有助于实施更改。干杯
  • @Luke - 另一件事。我假设您的 C 程序是使用 Microsoft 的 Visual Studio 编译的。如果这不正确,请告诉我,我会更新我的答案。 __declspec(dllexport) 只存在于微软的编译器中。对于任何其他编译器,我们都必须创建一个 export.def 文件。
  • 我正在使用 Microsoft Visual Studio 的最新免费版本。
【解决方案2】:

如前所述,您可以使用 C# 应用程序托盘中的 Process.Start

    // Uses the ProcessStartInfo class to start new processes, 
    // both in a minimized mode. 
    void OpenWithStartInfo()
    {
        ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
        startInfo.WindowStyle = ProcessWindowStyle.Minimized;

        Process.Start(startInfo);

        startInfo.Arguments = "www.northwindtraders.com";

        Process.Start(startInfo);
    }

http://msdn.microsoft.com/en-us/library/53ezey2s(v=vs.110).aspx

您可以尝试在隐藏状态下启动它:http://msdn.microsoft.com/en-us/library/system.diagnostics.processwindowstyle(v=vs.110).aspx

一些程序员告诉你要小心。如果预期有任何输入,那么您的进程可能会停止。确保没有任何东西真正停止你的程序。

您也可以尝试使用Process.Start 启动cmd 命令,但我会说这太多了。这将在没有您的 C# 托盘应用程序控制的情况下启动另一个进程:

 Process.Start("start /min cmd /c mycommand");

【讨论】:

  • 我不是 100% 确定他想调用他的可执行文件。我在想他可能想要调用编译到他的可执行文件中的一个或多个特定函数。
  • @rodrigogq 我认为解决我的问题的更好方法是创建一个调用 DLL 函数的线程。尽管您的回答我可能可以用于稍微不同的应用程序,但我也需要自动化。干杯
【解决方案3】:

您可以通过 System.Diagnostics.Process 从 .NET 代码启动您的 C 程序。它将在单独的进程中运行。

您也可以从 .NET 代码中终止进程

【讨论】:

  • 问题是关于一个系统托盘应用程序,它与通过Process启动的控制台应用程序不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 2011-05-22
  • 1970-01-01
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多