Domanda

Ho un codice C standard ANSI che è autorevole. Ciò significa che, sebbene io abbia la fonte, non posso tradurre in un'altra lingua né modificare argomenti di chiamata, poiché tali azioni invaliderebbero l'autorità. Ci sono oltre 150 funzioni.

Posso apportare modifiche accidentali, come cambiare i nomi dei file da .C a .CPP in modo che si compili usando il compilatore C ++ di Visual Studio 2009, cosa che ho fatto. Direttive del compilatore e simili possono anche essere aggiunte. Posso anche passare attraverso un livello wrapper, se necessario.

Un'altra limitazione è che la mia azienda non vuole che io usi la parola chiave non sicura in qualsiasi codice C #.

Devo accedere a queste funzioni da un programma C #.

Una tipica funzione C / C ++ è simile alla seguente:
  double SomeFunction (double a, double [3] vec, double [3] [3] mat);
Laddove il contenuto dell'array viene talvolta immesso, talvolta emesso e raramente entrambi.

Ho provato prima a creare una DLL non gestita (con le funzioni contrassegnate come Extern C). Le funzioni con solo argomenti semplici (int, double) hanno funzionato bene, ma non sono riuscito a determinare come eseguire il marshalling degli array. (In realtà, ho trovato del codice di esempio, ma era estremamente complesso e irragionevole duplicare 150 volte.)

Ho quindi provato due progetti all'interno della stessa soluzione, uno in C ++ e l'altro in C #. Nel progetto C ++, ho creato una funzione gestita che ha appena chiamato la funzione originale contrassegnata come non gestita. Questo era estremamente pulito e semplice, e ancora una volta, gli argomenti semplici funzionavano bene. Ma per le matrici, non sono riuscito a trovare come far corrispondere i tipi di argomento attraverso il limite da C # a C ++:
Argomento '2': impossibile convertire da 'double []' a 'double *'
(e come detto sopra, non posso usare unsafe per ottenere un puntatore).

Certamente quello che sto cercando di fare deve essere possibile.
Qual è il modo migliore per accedere a queste funzioni?
(Il codice di esempio che utilizza la funzione precedente sarebbe davvero interessante.)

È stato utile?

Soluzione

Esempio di implementazione C / C ++:

extern "C" __declspec(dllexport)
double SomeFunction(double a, double vec[3], double mat[3][3]) {
  double sum = a;
  for (int ix = 0; ix < 3; ++ix) {
    sum += vec[ix];
    for (int iy = 0; iy < 3; ++iy) {
      sum += mat[ix][iy];
    }
  }
  return sum;
}

Esempio di utilizzo C #:

private void Form1_Load(object sender, EventArgs e) {
  double[] vec = new double[3];
  double[,] mat = new double[3, 3];
  for (int ix = 0; ix < 3; ++ix) {
    vec[ix] = ix;
    for (int iy = 0; iy < 3; ++iy) {
      mat[ix, iy] = (ix + 1) * iy;
    }
  }
  double sum = SomeFunction(1, vec, mat);
}
[System.Runtime.InteropServices.DllImport("cpptemp8.dll")]
private static extern double SomeFunction(double a, double[] vec, double[,] mat);

Altri suggerimenti

Se non riesci a far funzionare la soluzione extern e P / Invoke, un wrapper è probabilmente la soluzione migliore. Creare una DLL C ++ gestita che utilizza sia codice gestito che non gestito. Aggiungere una classe .NET a questa DLL che è solo un thin wrapper sulle funzioni nella DLL C. Il tuo codice C # può chiamare la classe C ++ .NET, che a sua volta avanzerà sulle funzioni C.

In questo modo puoi scrivere tu stesso la traduzione tra .NET e codice non gestito, invece di fare affidamento sul runtime per farlo per te.

usa swig, genererà il tuo pinvoke per te

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top