如果从.NET程序集中公开COM对象,是否可以从R中调用COM对象?

时间:2013-02-13 20:50:37

标签: .net r com

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

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

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

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

  1. 我在我的系统中获得了一个ProgID列表(参见link to C# code)。以下是我系统中相关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( “类”)   1“COMObject”

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

  5. 更新

    在.NET中,调用将是:

        string x = "hello".Reverse();
    

    那么,在R中,调用将是?

    更新

    有关R调用C#的示例,请参阅幻灯片61上Embedding R in Applications on Windows中的 R调用C#

    请注意,ProgId是来自.NET类的ProjectName.ClassName

3 个答案:

答案 0 :(得分:3)

我刚刚通过COM成功调用了来自R的.NET代码,基于Embedding R in Applications on Windows幻灯片61到65的说明。

这是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文件(您必须运行{{1}手动,自己)。

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

  4. 如果您构建项目,并且VS2012抱怨它无法写入输出.dll,这意味着R由于调用regtlibv12.exe而锁定它。解锁.dll以便可以编译VS2012,关闭R,编译C#,然后重启R.

  5. 其他信息

    1. 请参阅R help on rcom package
    2. 请参阅User manual for rcom
    3. 请参阅statconn Wiki page
    4. 如果它不适用于R v2.15,请尝试使用R v2.14。

答案 1 :(得分:2)

我知道这个问题已经过时了,我正在报告我的经验,以帮助未来的.Net / R开发人员。

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

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

enter image description here

我发现this article他们同时使用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类型,例如string,datetime,int&amp;当我试图返回一个对象数组时,它失败了.Net调用将NULL返回给R.

答案 2 :(得分:1)

通常你使用comInvoke

s <- comInvoke(x,"Reverse")

但是,由于System.Text.ASCIIEncodingstring都没有Reverse方法,因此您需要选择其他方法来执行。