5

我想知道是否可以通过 COM 调用从 R 调用 .NET 函数。

该库rcom允许调用 COM 对象,因此理论上,对于任何作为 COM 对象公开的 .NET 程序集,这应该是可能的。

为简单起见,我将看看是否可以调用 in 中的.Reverse()函数System.Text,默认情况下,它作为 .NET 框架中的 COM 对象公开。

这是我到目前为止所尝试的:

  1. 我在我的系统中获得了 ProgID 的列表(请参阅C# 代码的链接)。这是我系统中相关 ProgID 的列表:

    ---start list of COM ProgID entries---
    <snip>
    System.SystemException -> mscoree.dll
    System.Text.ASCIIEncoding -> mscoree.dll
    System.Text.StringBuilder -> mscoree.dll
    System.Text.UnicodeEncoding -> mscoree.dll
    System.Text.UTF7Encoding -> mscoree.dll
    System.Text.UTF8Encoding -> mscoree.dll
    <snip>
    ---end list---
    
  2. 此 R 代码加载作为 COM 对象公开的 .NET .dll:

    library('rcom')
    x <- comCreateObject("System.Text.ASCIIEncoding")
    
  3. 它肯定会找到 COM 对象:

    x attr(,"class") 1 "COMObject"

  4. 我的问题是 - 我如何调用.Reverse()这个 COM 对象中的函数?

更新

在 .NET 中,调用将是:

    string x = "hello".Reverse();

那么,在 R 中,调用会是什么?

更新

有关 R 调用 C# 的示例,请参阅幻灯片 61中在 Windows 应用程序中嵌入 R 中的R 调用 C# 。

请注意,这ProgIdProjectName.ClassName来自 .NET 类。

4

3 回答 3

3

我刚刚根据Embedding R in Applications on Windows幻灯片 61 到 65 中的说明,通过 COM 从 R 中成功调用了 .NET 代码。

这是R代码:

# This is a once-off call.
install.packages("rcom")
library(rcom)
# This is a once-off call. See rcom user manual at:
# http://cran.r-project.org/web/packages/rcom/rcom.pdf
installstatconnDCOM() 

x <- comCreateObject("InteropSample.MyClass32")
comSetProperty(x,"Text","xxx")
comSetProperty(x,"Connector",comThis())
comInvoke(x,"DoCallback")

这是R中的输出:

> DoCallback: xxxNULL

这是 .NET 类的 C# 代码:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

// Before running this, get rid of errors with "RCOMServerLib" by adding the rcom type library:
//
// Make sure everything is 32-bit (32-bit build in .NET, 32-bit run of Revolution R).
//
// Tick "Register for COM interop" in .NET project settings.
// 
// 1.Browse to "C:\Revolution\R-Enterprise-6.1\R-2.14.2\library\rcom\libs\i386>", then execute:
// C:\Revolution\R-Enterprise-6.1\R-2.14.2\library\rcom\libs\i386> C:\Windows\Microsoft.NET\Framework\v4.0.30319\regtlibv12.exe rcom_srv.tlb
// Registration of rcom_srv.tlb successful.
//
// 2. Add reference to "rcom_srv.tlb", this gets rid of errors for RComServerLib.
//    (browse to "C:\Revolution\R-Enterprise-6.1\R-2.14.2\library\rcom\libs\i386")
//
// 3. If we are using VS2012, this .NET assembly class will be automatically registered as COM server on build if we are using VS2012. If using VS2012, you must do this manually on the command line.
// 
// See:
// http://generally.wordpress.com/2006/07/28/exposing-your-net-assembly-through-com/
// http://www.inside-r.org/packages/cran/rcom/docs/comCreateObject

// In R:
// comCreateObject("InteropSample.MyClass32")
// comSetProperty(x,"Text","xxx")
// comSetProperty(x,"Connector",comThis())
// comInvoke(x,"DoCallback")

namespace COM___called_from_R
{
    [Guid("3ddfe021-a0c6-4218-a254-4fc4328c99a7"),
     InterfaceType(ComInterfaceType.InterfaceIsDual)]
    internal interface IMyComponent
    {
        RCOMServerLib.IStatConnector Connector { set; }
        string Text { set; }
        void DoCallback();
    }

    [Guid("133fee0e-9b32-4429-8a43-6e2a706a9beb"), ComVisible(true)]
    [ProgIdAttribute("InteropSample.MyClass32")]
    public class MyComponent : IMyComponent
    {
        private string mText;
        private RCOMServerLib.IStatConnector mConnector;

        public RCOMServerLib.IStatConnector Connector
        {
            set { mConnector = value; }
        }

        public string Text
        {
            set { mText = value; }
        }

        public string MyProperty;

        public void DoCallback()
        {
            if (mConnector != null)
            {
                mConnector.EvaluateNoReturn("cat(\"DoCallback: "
                                            + mText + "\")\n");
            }
        }
    }
}

笔记

  1. 为了使其正常工作,所有内容都必须始终为 32 位或始终为 64 位。通过使用以下设置,我让它在 32 位模式下工作:

    • C# 程序集(设置为 32 位)。
    • R 的版本(我在 32 位模式下使用了 Revolution R)。
  2. 如果您使用 Visual Studio 2012 (VS2012),那么如果您在 .NET 项目设置中勾选“注册 COM 互操作”,它将C:\Windows\Microsoft.NET\Framework\v4.0.30319\regtlibv12.exe在编译时自动运行以将您的自定义 .NET 类注册为系统范围的 COM 组件。但是,如果您使用 Visual Studio 2010 (VS2010),它不会自动运行regtlibv12.exe,所有这些设置都会创建 .tlb 文件(您必须regtlibv12.exe自己手动运行)。

  3. 可以通过调用“regtlibv12.exe -u MyComDLL.tlb”取消注册 COM 组件。

  4. 如果您构建您的项目,并且 VS2012 抱怨它无法写入输出 .dll,这意味着 R 由于调用而锁定它x <- comCreateObject("InteropSample.MyClass32")。要解锁 .dll 以便可以编译 VS2012,请关闭 R,编译 C#,然后重新启动 R。

附加信息

  1. 请参阅有关package的R 帮助rcom
  2. 参见用户手册rcom
  3. 请参阅statconn Wiki 页面
  4. 如果它不适用于 R v2.15,请尝试使用 R v2.14。
于 2013-02-13T23:22:28.420 回答
2

我知道这个问题很老,我报告我的经验来帮助未来的 .Net/R 开发人员。

无论我尝试了什么,我都无法参考rcom_srv.tlb

C:\Program Files\R\R-2.15.3\library\rcom\libs\i386\rcom_srv.tlb无法添加对的引用。请确保该文件是可访问的,并且它是一个有效的程序集或 COM 组件。

在此处输入图像描述

我发现这篇文章同时使用了 RCOMServerLib 和 STATCONNECTORSRVLib:

public STATCONNECTORSRVLib.StatConnectorClass rdcom = null;
//public RCOMServerLib.InternalConnectorClass rdcom = null; // Use 'rcom' for debugging

我都无法取得进展,所以我最终在没有 RcomServerLib 的情况下做到了:

namespace XYZ.dotNetProject_R
{
    [Guid("FA6F70DD-CDD0-4FF3-94BA-E2B94E68321D"),
    InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IDataHelper
    {
        string[,] GetdotNetProject2DArray(string code, DateTime fromDate, DateTime toDate);        
    }

    [ComVisible(true)]
    [ProgId("XYZ.dotNetProject_R")]
    public class DataHelper : IDataHelper
    {
        public string[,] GetdotNetProject2DArray(string code, DateTime fromDate = default(DateTime), DateTime toDate = default(DateTime))
        {

        }
    }
}

我通过R调用它:

# On some PC's it wont download the Package until you set it to use your IE Proxy Settings:
setInternet2(TRUE)
# This is a once-off call.
install.packages("rcom")
# This is a once-off call.
installstatconnDCOM()

#Resusable calls
> library('rcom')
Loading required package: rscproxy
> dll = comCreateObject("XYZ.dotNetProject_R")
> dll
<pointer: 0x2079002c>
attr(,"class")
[1] "COMObject"
> series = comInvoke(dll,"GetdotNetProject2DArray","abc123","2000-01-01","2010-01-01")
> series
    [,1]         [,2]                 
 [1,] "2000-01-01" "1236.1" 

COM 不支持泛型,所以我只返回了一个字符串数组。我发现R仅支持基本/原始 .Net 类型,例如字符串、日期时间、int 等。当我尝试返回对象数组时,它失败了,.Net 调用将 NULL 返回给 R。

于 2013-03-27T22:11:32.957 回答
1

一般来说,你使用comInvoke

s <- comInvoke(x,"Reverse")

但是,由于既没有方法System.Text.ASCIIEncoding也没有string方法Reverse,因此您需要选择不同的方法来执行。

于 2013-02-13T21:10:35.080 回答