Мне нужно отобразить графики функций, используя программную среду R. Путь к R.dll уже находится в переменной среды «PATH».Но когда я запускаю свой код, я получаю исключение: «System.AccessViolationException: попытка чтения или записи защищенной памяти.Это часто свидетельствует о том, что другая память повреждена ».Это происходит в этой части кода:
public static void Execute(string command)
{
IntPtr cmd, expr;
ParseStatus status = 0;
int error = 0;
cmd = Rf_mkString(command);
Rf_protect(cmd);
Rf_protect(expr = R_ParseVector(cmd, -1, ref status, R_NilValue));
Rf_unprotect(2);
if (status != ParseStatus.PARSE_OK)
throw new Exception("Failed");
R_tryEvalSilent(VECTOR_ELT(expr, 0), R_GlobalEnv, ref error);
}
точно в Rf_protect(expr = R_ParseVector(cmd, -1, ref status, R_NilValue));;
Я не понимаю причину.Полный код:
using System;
using System.Runtime.InteropServices;
using System.Threading;
/// <summary>
/// Interface to the R engine
/// </summary>
public static class REngine
{
/// <summary>
/// TODO: write summary
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct vecsxp_struct
{
int length;
int truelength;
}
/// <summary>
/// TODO: write summary
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct VECTOR_SXPREC
{
int sxpinfo;
IntPtr attrib;
IntPtr gengc_next_node, gengc_prev_node;
vecsxp_struct vecsxp;
}
/// <summary>
/// TODO: write summary
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = sizeof(double))]
struct SXPREC_ALIGN
{
VECTOR_SXPREC s;
}
/// <summary>
/// R parser status code
/// </summary>
enum ParseStatus : int
{
PARSE_NULL,
PARSE_OK,
PARSE_INCOMPLETE,
PARSE_ERROR,
PARSE_EOF
}
// External functions from R.dll
// NOTE: on Win32 the default calling convention is Stdcall, on Win64 CC does not matter
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Rf_initEmbeddedR(int argc, IntPtr argv);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr Rf_mkString(string s);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr Rf_protect(IntPtr e);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr R_ParseVector(IntPtr e, int n, ref ParseStatus PraseStatus, IntPtr SrcFile);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void Rf_unprotect(int n);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr R_tryEvalSilent(IntPtr e, IntPtr env, ref int error);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr Rf_findVar(IntPtr e, IntPtr env);
[DllImport("R.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr Rf_install(string s);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Rf_length(IntPtr e);
[DllImport("R.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void Rf_endEmbeddedR(int fatal);
/// <summary>
/// Attribute
/// </summary>
/// <param name="e">e</param>
/// <returns>IntPtr</returns>
static IntPtr ATTRIB(IntPtr e)
{
unsafe
{
return *(IntPtr*)IntPtr.Add(e, sizeof(int));
}
}
/// <summary>
/// Data pointer
/// </summary>
/// <param name="e">e</param>
/// <returns>IntPtr</returns>
static IntPtr DATAPTR(IntPtr e)
{
return IntPtr.Add(e, Marshal.SizeOf(new SXPREC_ALIGN()));
}
/// <summary>
/// Real value
/// </summary>
/// <param name="e">e</param>
/// <returns>value</returns>
static double REAL(IntPtr e)
{
unsafe
{
return *(double*)DATAPTR(e);
}
}
/// <summary>
/// Element of a vector
/// </summary>
/// <param name="e">vector</param>
/// <param name="i">0-based element index</param>
/// <returns>element</returns>
static IntPtr VECTOR_ELT(IntPtr e, int i)
{
unsafe
{
return *(IntPtr*)IntPtr.Add(DATAPTR(e), sizeof(IntPtr) * i);
}
}
/// <summary>
/// Empty value
/// </summary>
static IntPtr R_NilValue = IntPtr.Zero;
/// <summary>
/// Global environment
/// </summary>
static IntPtr R_GlobalEnv = IntPtr.Zero;
/// <summary>
/// Absent value
/// </summary>
static IntPtr R_UnboundValue = IntPtr.Zero;
static REngine()
{
Rf_initEmbeddedR(0, IntPtr.Zero);
}
/// <summary>
/// Run command in R
/// </summary>
/// <param name="command">command</param>
public static void Execute(string command)
{
IntPtr cmd, expr;
ParseStatus status = 0;
int error = 0;
cmd = Rf_mkString(command);
Rf_protect(cmd);
Rf_protect(expr = R_ParseVector(cmd, -1, ref status, R_NilValue));
Rf_unprotect(2);
if (status != ParseStatus.PARSE_OK)
throw new Exception("Failed");
R_tryEvalSilent(VECTOR_ELT(expr, 0), R_GlobalEnv, ref error);
}
/// <summary>
/// Read real variable from R
/// </summary>
/// <param name="varname">variable name</param>
/// <returns>value</returns>
public static double GetDouble(string varname)
{
double result = 0.0;
IntPtr var;
Rf_protect(var = Rf_findVar(Rf_install(varname), R_GlobalEnv));
if (var == R_UnboundValue)
{
Rf_unprotect(1);
throw new Exception("Unknown variable");
}
else
{
result = REAL(var);
}
Rf_unprotect(1);
return result;
}
/// <summary>
/// Terminate R
/// </summary>
public static void Exit()
{
Rf_endEmbeddedR(0);
}
}
/// <summary>
/// Win32 API data structures and funtions
/// </summary>
class Win32
{
/// <summary>
/// Win32 Message
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public UInt32 message;
public IntPtr wParam;
public IntPtr lParam;
public UInt32 time;
public POINT pt;
}
/// <summary>
/// Point
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
[DllImport("user32.dll")]
public static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
uint wMsgFilterMax);
[DllImport("user32.dll")]
public static extern bool TranslateMessage([In] ref MSG lpMsg);
[DllImport("user32.dll")]
public static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
}
/// <summary>
/// Main class
/// </summary>
class Program
{
/// <summary>
/// Displays a plot window
/// </summary>
static void Plot()
{
REngine.Execute("plot(x, y, type=\"l\")");
// Message loop
Win32.MSG msg;
while (Win32.GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
{
Win32.TranslateMessage(ref msg);
Win32.DispatchMessage(ref msg);
}
}
/// <summary>
/// The entry point
/// </summary>
/// <param name="args">Command line arguments</param>
static void Main(string[] args)
{
// Show info
// TODO: think about localization
Console.WriteLine("This program displays a plot of a function specified by a formula.");
Console.WriteLine();
// TODO: implement automatic detection of R
Console.WriteLine("Before using this program, please download and install the R language from");
Console.WriteLine();
Console.WriteLine("\t\t\thttp://www.r-project.org");
Console.WriteLine();
Console.WriteLine("and add the path to R.dll to your PATH environment variable.");
Console.WriteLine();
Console.WriteLine("If you already have R, press any key. Otherwise, close this program.");
Console.ReadKey();
// Input formula and x range
Console.WriteLine("Enter a formula of the form y = f(x), for example: y = 2*sin(x)+5:");
string formula = Console.ReadLine();
Console.WriteLine("Enter the range of x, for example: -5 5");
string[] xrange = Console.ReadLine().Split(' ');
REngine.Execute(string.Format("xmin = {0}", xrange[0]));
REngine.Execute(string.Format("xmax = {0}", xrange[1]));
REngine.Execute("x = seq(xmin, xmax, by=(xmax-xmin)/100)"); // hmmm... 100 points ?
REngine.Execute(formula);
// Show the plot
new Thread(Plot).Start();
// Wait until the user hits a key
Console.WriteLine("Press any key to exit");
Console.ReadKey();
// Close R and exit
// TODO: check if there are "static destructors" in C#
REngine.Exit();
Environment.Exit(0);
}
}
Кто-нибудь знает в чем причина?Спасибо!
PS Мой вопрос о том, как реализовать R.dll в c #, а не в lib.Этот вопрос не является дубликатом.