如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?

Posted

技术标签:

【中文标题】如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?【英文标题】:How to call C# function from C++ background task (Windows Universal app)? 【发布时间】:2014-07-23 12:16:48 【问题描述】:

我正在将我的应用(使用自定义动态磁贴)重写为通用应用。以前,我使用 3rd 方库来渲染这些自定义动态磁贴。不再支持这个库,所以我必须找到一种新的方法来做到这一点。似乎XamlRenderingBackgroundTask 是目前唯一的前进方向,但这是在 C++ 中。我的应用程序的其余部分在 C# 中。

我的后台任务应该从公共 API 获取数据(例如天气),并使用这些信息来呈现动态磁贴。我已经编写了获取数据的类(我也在主应用程序中使用它们),但这些是用 C# 编写的。

现在,使用 Windows 运行时组件应该可以“混合”不同的语言(对吗?)。但是我该如何实现呢? (缺少具体样品)。

简而言之:如何从我的 C++ 后台任务调用 C# 函数(将返回数据)

我创建了一个非常示例 - 我想从我的 C++ 后台任务中运行 RunTheFunction 和 RunAnotherFunction。

public class ***ExampleClass()

    public string Name  get; set; 
    public string Value  get; set; 


public class ***ExampleClass2()

    public string UpperString  get; set; 



public async Task<***ExampleClass> RunTheFunction(int ParameterValue)

    ***ExampleClass overflowClass = new ***ExampleClass();
    overflowClass.Name = "Stack Overflow";
    overflowClass.Value = 1 + ParameterValue;

    // DO SOME COOL ADVANCED HTTP STUFF
    return overflowClass;


public async Task<***ExampleClass> RunAnotherFunction(string ExampleString)

    ***ExampleClass2 overflowClass2 = new ***ExampleClass2();
    overflowClass2.UpperString = ExampleString.ToUpper();

    return overflowClass2;

在正常的 C# 后台任务中,我会这样做:

***ExampleClass SFClass = await ***example.RunTheFunction(10);
***ExampleClass2 SFClass = await ***example.RunAnotherFunction("***");
///// render SFClass.Value + SFClass.Name as a PNG
///// set tile title to SFClass.UpperString

如何在 C++ 中做到这一点?

【问题讨论】:

有什么理由不能用 C# 编写后台任务并从中调用 XamlRenderingBackgroundTask 吗? 由于内存问题,不建议这样做。这里有一个示例:social.msdn.microsoft.com/Forums/en-US/… 但它没有成功。代码生成了一个损坏的图像。 但这是否意味着您的整个问题“由于内存问题不推荐”? 我说的是生成图块。这就是占用内存的原因。如果后台任务在 C++ 中(并进行渲染),那么我想我会没事的。 【参考方案1】:

您可以查看Visual C++ Compiler November 2013 CTP,一些漂亮的示例可以执行以下操作: __await FileIO::WriteTextAsync(file, file->Name);

它看起来还不是很好,而且很可能会在未来的版本中出现标准的发展、新的和更好的(至少是标准的)方法。

【讨论】:

我已经安装了,你能举个例子说明如何使用上面提到的代码吗?我对如何使用它感到困惑:(【参考方案2】:

您可以尝试为此使用 COM(虽然我不确定它是否合适):

C#端:

using System;
using System.Runtime.InteropServices;

namespace CSharp

    [Guid("62D276EB-FABE-4c0e-BF59-7D0799DEC029")]
    [ComVisible(true)]
    public interface IExampleClass
    
        string Name  get; set; 
        int Value  get; set; 
    

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("4E196599-F1C5-4447-84F4-E46FC1C16105")]
    [ComVisible(true)]
    public class ExampleClass : IExampleClass
    
        public ExampleClass()
         

        public string Name  get; set; 
        public int Value  get; set; 
    

    [Guid("72D276EB-FABE-4c0e-BF59-7D0799DEC020")]
    [ComVisible(true)]
    public interface IExampleClass2
    
        string UpperString  get; set; 
    

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("6712709D-8913-4911-8ABB-BFB4865D4E9F")]
    [ComVisible(true)]
    public class ExampleClass2 : IExampleClass2
    
        public ExampleClass2()
         

        public string UpperString  get; set; 
    

    [Guid("1C312E27-6B09-412c-B7AA-55F4E0FBCF8C")]
    [ComVisible(true)]
    public interface ICSharpFunctor
    
        ExampleClass RunTheFunction(int ParameterValue);
        ExampleClass2 RunAnotherFunction(string ExampleString);
    

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("9B8FAFEA-64EB-493f-95CB-B0B0EDEBADC2")]
    [ComVisible(true)]
    public class CSharpFunctor : ICSharpFunctor
    
        public CSharpFunctor()
         

        public ExampleClass RunTheFunction(int ParameterValue)
        
            ExampleClass instance = new ExampleClass();
            instance.Name = "Stack Overflow";
            instance.Value = 1 + ParameterValue;
            return instance;
        

        public ExampleClass2 RunAnotherFunction(string ExampleString)
        
            ExampleClass2 instance = new ExampleClass2();
            instance.UpperString = ExampleString.ToUpper();
            return instance;
        
    

您必须获取 C# 代码并生成程序集、清单和 tlb 文件以导入到 C++ 代码中。

C++ 方面:

using namespace CSharpCOM;
ICSharpFunctorPtr pCSharp;
HRESULT hr = pCSharp.CreateInstance(__uuidof(CSharpFunctor));
assert(SUCCEEDED(hr));
if (SUCCEEDED(hr))

    IExampleClassPtr e1 = pCSharp->RunTheFunction(10);
    assert(e1->Value == 11);
    std::string name = e1->Name;
    assert(name == "Stack Overflow");
    IExampleClass2Ptr e2 = pCSharp->RunAnotherFunction("***");
    std::string uc = e2->UpperString;
    assert(uc == "***");

这是一个完整示例的链接(包括我错过的有关接口的一些内容。) https://github.com/brandon-kohn/CSharpCOM

【讨论】:

感谢您的回答。我尝试了您的步骤,但在生成 tlb 文件时遇到了困难。为此,我必须在项目属性中启用“注册 COM 互操作” - 但此复选框是灰色的。输出类型设置为“类库”。 您不必启用它。我创建了一个不使用它的 COM 项目。您可以设置清单,这样您就不必注册程序集。您使用的是哪个版本的视觉工作室?我可以把一个小例子放在我的 github 上。 我已更新答案以包含指向完整工作示例的链接。【参考方案3】:

你有几个选择:

    将 C# 代码移动到 Windows 运行时组件中。 为 C# 代码创建一个包装 Windows 运行时组件 使 C++ 代码成为 Windows 运行时组件。 为 C++ 代码创建一个包装 Windows 运行时组件。

完成其中一项后,您可以在 C++、C# 或 javascript 中使用该组件,前提是它是用您使用的语言编写的。


使用 C++ 构建 Windows 运行时组件

http://channel9.msdn.com/events/Windows-Camp/Developing-Windows-8-Metro-style-apps-in-Cpp/Building-Windows-Runtime-Components-with-Cpp

在 C# 和 Visual Basic 中创建 Windows 运行时组件

http://msdn.microsoft.com/en-us/library/br230301.aspx

在 C++ 中创建 Windows 运行时组件

http://msdn.microsoft.com/en-us/library/hh441569.aspx

4 号的一个很好的例子是 SQLite-WinRT,可以在这里找到http://sqlwinrt.codeplex.com/

【讨论】:

以上是关于如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?的主要内容,如果未能解决你的问题,请参考以下文章

用于获取通知的通用 Windows 10 应用后台任务计时器

可以运行 2 个后台任务 - Windows Phone 8.1 通用应用程序?

是否可以在 WinRT/Windows 通用应用程序的后台任务中检索手机电池状态?

应用程序关闭时如何接收推送和通知(Toast 和磁贴) windows 通用 8.1 应用程序

c++跨平台后台任务

C++:一直在机器上运行后台任务