Ho fatto questo prima di usare un approccio un po 'contorto ma funziona!
Innanzitutto, è necessario creare una DLL C# contenente la propria funzione. Puoi farlo in Visual Studio selezionando "libreria di classi" come opzione quando crei un nuovo progetto. Il codice nel file .cs dovrebbe essere simile
namespace MyNamespace
{
//expose an interface with functions to be called from R
public interface MyInterface
{
string MyFunction(string name);
}
//create a class that implements the above interface
public class MyClass : MyInterface
{
public string MyFunction(string name)
{
return "Hello " + name;
}
}
}
Ora compilare il progetto e si otterrà un C# DLL. Questa DLL è una DLL gestita che è diversa da una DLL C/C++ nativa. Non può essere direttamente consumato da linguaggi non. NET e quindi deve essere esposto come un oggetto COM. È possibile farlo in uno dei due modi
- In Visual Studio, è possibile andare alle proprietà del progetto, clicca su "informazioni Assembly" pulsante sotto scheda "Applicazioni" e selezionare la casella di controllo che dice "Make assembly COM visibile ".
- In alternativa, è possibile utilizzare regasm.exe che può essere trovato nella cartella di installazione .net per registrare la DLL come componente COM. Ecco un link che descrive questo processo. http://msdn.microsoft.com/en-us/library/tzat5yw6(v=vs.71).aspx. Il comando è in genere "regasm myTest.dll /tlb:myTest.tlb"
Il processo di registrazione COM ora avrà creato un file .tlb nella stessa cartella della DLL. Conserva questo file .tlb. Ne avremo bisogno nel passaggio successivo
Il passaggio successivo consiste nel creare una DLL C++ che possa chiamare la DLL COM. Questo passaggio è necessario perché R può chiamare direttamente una DLL C++ ma non può chiamare direttamente la COM (correggimi se ho torto o salta questo passaggio se conosci un modo migliore per chiamare COM da R). Il codice per il ++ DLL C in dllmain.cpp Si riporta di seguito (accertarsi di scorrerlo per vedere il codice completo)
#include "stdafx.h"
#include <iostream>
//import the .tlb file create by COM registration
#import "path_to_Dll\MyDll.tlb" named_guids raw_interfaces_only
void _cdecl MyCPPFunction(char ** strName)
{
//Initialize COM
HRESULT hr = CoInitialize(NULL);
//create COM interface pointer
MyNamespace::MyInterfacePtr myPtr;
//create instance of COM class using the interface pointer
HRESULT hr2 = myPtr.CreateInstance(MyNamespace::CLSID_MyClass);
//create variable to hold output from COM.
BSTR output;
//call the COM function
myPtr->MyFunction(_bstr_t(strName[0]), &output);
//convert the returned BSTR from .net into char*
int length = (int) SysStringLen(output);
char *tempBuffer;
tempBuffer = (char *) malloc(1 + length);
WideCharToMultibyte(CP_ACP, 0, output, -1, tempBuffer, length, NULL, NULL);
tempBuffer[length] = '\0';
//release interface
myPtr->Release();
//uninitialize COM
if(hr == S_OK)
CoUninitialize();
//set output in input for returning to R (this is weird but the only way I could make it work)
strName[0] = tempBuffer;
}
Ora compilare il progetto e si otterrà una DLL C++. Siamo quasi arrivati ora! Non arrenderti ancora :). Ora, hai una DLL C# esposta come un oggetto COM e una DLL C++ che può chiamare questo oggetto COM. Il passo finale è quello di chiamare la funzione C++ da R. Qui è il codice R per farlo
#load C++ DLL
dyn.load("path_to_C++_DLL")
#call function in C++ DLL and pass in a test name.
# The C++ DLL will in turn call the C# function
output <- .C("MyCPPFunction", as.character("Peter"))
#print output
print(output)
e si dovrebbe vedere "Ciao Peter" visualizzato da C# nella console R! Un punto molto importante da notare.
Compilare sempre la DLL COM utilizzando l'opzione "qualsiasi CPU". Compila sempre la DLL C++ in modo che corrisponda alla tua installazione R! Ad esempio, se hai 32 bit R installati, assicurati di compilare la DLL C++ come DLL a 32 bit. Se hai 64 bit R installati e vuoi usarli, assicurati di compilare la tua DLL C++ come una DLL a 64 bit. Buona fortuna!
Perché non riscrivere la funzione in R? – agstudy
@agstudy solo perché la (e) funzione (i) è (sono) scritta in più di 50 classi e più di 10000 linee. :( – MBS
Puoi condividere un esempio di una di queste funzioni per fornire un contesto aggiuntivo? Puoi condividere il tuo codice C# che non funziona pure. –