erklärt mir wer das wrappen ?
-
theta schrieb:
@ghostwhisperer:
Ich nehme an, dass deine API schon in einer DLL vorliegt (SR_API.dll). Korrekt?
Dann musst Du nicht extra eine neue DLL machen nur um zu Wrappen!!!
Benutze einfach den P/Invoke Mechanismus direkt mit der DLL.
In der Header Datei SR_API.h findest Du die nötigen Deklarationen.
Simon
Edit:
Das Tool "P/Invoke Interop Assistent" hilft Dir die nötigen C# Deklarationen ([DllImport...]) zu erstellen: http://clrinterop.codeplex.com/releases/view/14120Hallo theta !
Wenn ich das richtig verstehe, kann ich in c# keine c++ Libs und Header einbinden richtig??
Die SR_API besteht aus Header, DLL und Lib und zusätzlich einer SR_API_Parameter.h.
Deswegen dachte ich, dass mir nur übrigbleibt indirekt einzubinden, über c++ wrapper-dll:
Ich muss zuerst die im Header angegebenen Structs aus SR_API.h im Programm instanzieren die zudem mit vielen weiteren Structs aus der Parameter.h zusammenhängen. Die Structs benötige ich als Parameter für die eigentlichen Funktionen der DLL. Hinzu kommt, dass in der SR_API.h die Funktionsaufrufe mit LIBCALL funktionieren.
Also denk ich, ich muss in wrapper-Prog die Funktionsaufrufe schachteln UND die Structs so auflösen, dass ich die Werte in nachgebaute Structs in c# übergeben kann.
Oder gehts auch anders? Nach meinen Recherchen nicht..MFG
-
Lies dir die Antwort von theta nochmal durch. Da steht alles drin, was du brauchst.
-
@ghostwhisperer
Erstmal beachten, was theta geschrieben hat.Hast du denn eine fertige DLL mit "Extern" deklarierten Methoden die du aufrufen kannst? Dann lese nochmal über die Antwort von theta.
Allerdings habe ich es so verstanden, dass du nur die "Sources + Lib" hast. Dann ist deine Überlegung zum weiteren Vorgehen richtig. Du schaust dir an, wie die einzelnen Methoden aufgerufen werden und reichst sie in deiner "Wrapper-Schicht" durch.
Structs müssen nicht aufgelöst/konvertiert/etc. werden, solange diese nicht komplex sind. Mit komplex meine ich, verschachtelte "unions" etc. Diese Structs kannst du in deinem C# Aufrufer nachbauen. Gibts einige Tuts dazu, wie man soetwas macht. Ist alles kein Hexenwerk.
gruß
Hellsgore
-
OK jetzt versteh ich, was ich mit nem Fremdprogramm soll. Tolles Prog, werds weiterempfehlen! Ich hab den Header übersetzen lassen und daraus ne Klasse gemacht. Die API wird richtig gefunden und die einfachste Funktion GetVersion funzt.
Hat aber noch 1 Schwierigkeit. Die fürchterlich verschachtelten Structs sind alle übersetzt. Aber das Marshalling ist überfordert:Eine nicht behandelte Ausnahme des Typs "System.Runtime.InteropServices.MarshalDirectiveException" ist in mscorlib.dll aufgetreten. Zusätzliche Informationen: "parameter #1" kann nicht gemarshallt werden: Interne Einschränkung: Die Struktur ist zu komplex oder zu groß
Das wird IMMER WIEDER auftreten, da die Struktur CamDesc der Kameradescriptor für die Steuerung UND Datenverwaltung ist.
Hat jemand eine Idee ? Oder doch einziger Ausweg das ganze zu wrappen und den ganzen Kram zu kleinen Krümeln zu zerbröseln?
MFG !!
-
Zeig mal den "struct CamDesc" und google mal nach "pinvoke struct c#". Dort wird dir gezeigt wie man Structs richtig "marshalled".
BTW. ich hab das Tool mal ausprobiert, ist ein nettes Hilfsmittel. Allerdings sollte man sich trotzdem mit dem Thema beschäftigen, damit man weiß was passiert und warum man es so machen sollte.
-
Hellsgore schrieb:
Zeig mal den "struct CamDesc" und google mal nach "pinvoke struct c#". Dort wird dir gezeigt wie man Structs richtig "marshalled".
BTW. ich hab das Tool mal ausprobiert, ist ein nettes Hilfsmittel. Allerdings sollte man sich trotzdem mit dem Thema beschäftigen, damit man weiß was passiert und warum man es so machen sollte.
Hi! Ich hab mir alles angesehen, um die Unterschiede zu verstehen. Und gegoogelt hatte ich schon. Hab nur nicht alles verstanden..
Hier ALLE beteiligten (Original-)Structs. Ist aber recht viel und tief geschachtelt (btw. dies ist ein Treiber einer Firma. Kann also nicht geändert werden):
Inhalt von Camdesk:typedef struct{ int cam_index; char name[260]; char IPAdr[17]; // IP Adr String "192.168...... unsigned short portnum; int command; unsigned char header[HEADERSIZE_USER]; void* pcamdata; int camdatasize; int dataavailable; int connectionstate; int tcp_handle; int active; int alive_time; int archiv_active; int archiv_handle; void *lut; void *usercbf; //=cbf(CAMDESC* cd) int digio_out[4]; int digio_in[4]; int laser_status; int laserlight; int fps; float Temp; int running; PARAM cpar; } CAMDESC;
Inhalt von PARAM:
typedef struct{ char Bezeichnung[256]; char Description[2048]; MODUL Modul[50]; char fillbytes0[2048]; int AnzahlModule; M1 m1[2]; char fillbytes1[2048]; M2 m2[2]; char fillbytes2[2034];//2036; 2044 M3 m3[2]; char fillbytes3[2044]; M4 m4[2]; char fillbytes4[2048]; M5 m5[2]; char fillbytes5[2040]; M6 m6[2]; char fillbytes6[1944]; //2048 - 2x(2x10) - 2x(2x8) - 2x(2x8) M7 m7[2]; char fillbytes7[2044]; M8 m8[2]; char fillbytes8[2048]; M9 m9[2]; char fillbytes9[2048]; M10 m10[2]; char fillbytes10[2048]; M11 m11[2]; char fillbytes11[2048]; M12 m12[2]; char fillbytes12[1916]; M13 m13[2]; char fillbytes13[2048]; M14 m14[5]; char fillbytes14[2048]; M15 m15[5]; char fillbytes15[2048]; M16 m16[5]; char fillbytes16[2048]; M17 m17[5]; char fillbytes17[2048]; M18 m18[1]; char fillbytes18[2043]; //2047 M90 m90[10]; char fillbytes90[2048]; M80 m80[1]; char fillbytes80[2048]; M99 m99[2]; char fillbytes99[12]; //16-1*int slope = 12 char Version[64]; }PARAM;
Die structs Modul, M1-99 usw:
typedef struct { double WAB; //Winkel zw A B double WAB_X; //Drehpunkt X double WAB_Y; //Drehpunkt Y double off_X; //Verschiebung X double off_Y; //Verschiebung Z double scale; // Skalierungung NUR Rückgabewert !!! double scale_X; // X - scale : entlang der Laserlinie double scale_Y; // Y - scale : Abstand zum Sensor (Höhe) double negX; // SmartRay pos X == Arnold neg X double WB; // Winkel der SmartRay X Koord zu X-Achse double negY; // SmartRay nahe Sensor kleiner Wert = Arnold großer wert } COORD_TRANS_PARM; typedef struct { double A1X; //A - SmartRay Kalib Koordinaten double A1Y; double A2X; double A2Y; double B1X; // B- Customer soll Koordinaten double B1Y; double B2X; double B2Y; } REF_TRANS_POINTS; #define MODULNAMESIZE 256 #define PARREFNAMESIZE 256 typedef struct{ char name[MODULNAMESIZE]; char methodname[MODULNAMESIZE]; int methodcode; // identifier der Methode entsprechend Modulbibliothek char nextname[MODULNAMESIZE]; char result[10][PARREFNAMESIZE]; int resultoffset[10]; int resultsize; int inst; }MODUL; typedef struct{ short startx; short starty; short width; short height; int beli_kurz; char bitwahl; char aufloesung; char readoutspeed; char datavaliddelay; char wrreq_delay; char dummy; short dummy2; }M1; typedef struct{ unsigned char threshold; unsigned char threshold_long; //tresh für doppelbeli lange beliz. char reflexfilter; char profilswitch; unsigned short profilerate; unsigned short minNenner; unsigned short reflexsearch; unsigned char datamode; unsigned char dummy; //ex OberesLinkesEckWeg im Auswertebereich }M2; // Pars Method3 ACQUIRE (HW Datastream) typedef struct{ char subject; char mode; char dummy; //ex: camsel; //2D Bildübertragung Select 0: Cam A 1: CamB short dummy2;// num_of_images short num_of_profiles; char active; }M3; // Pars Method4 GET_NEXT_LINE (SW Sdram Ringspeicher management) typedef struct{ char width[256]; unsigned char mode; unsigned short step[8]; char nextmod[8][MODULNAMESIZE]; }M4; // Pars Method5 PROFILE_TRACKING (HW ROI_Nachfuehrung) typedef struct{ char active; char search_ymin[PARREFNAMESIZE]; char search_ymax[PARREFNAMESIZE]; unsigned short step; unsigned char mode; short offset; unsigned short maxjump; unsigned short minAnzVals; }M5; // Pars Method6 DOUBLE_EXPOSURE (HW Doppelbelichtung) typedef struct{ unsigned char active; //bit[0]: Doppelbeli activ; bit[1]: Non Zero //bit[2]: _kurz Regelung activ; bit[3]: _lang Regelung activ unsigned char dummy1; short dummy2; int beli_kurz; int beli_lang; // neu Parameter für BelichtungszeitRegelung 2009-03-02:TA unsigned short beli_kurz_min; //untere Regelgrenze unsigned short beli_kurz_max; //obere Regelgrenze unsigned short beli_kurz_maxstep; //maximale Regelschrittweite unsigned short beli_kurz_sumgreyset; //RegelSollWert unsigned short beli_kurz_dummy; //Reserve unsigned short beli_lang_min; //untere Regelgrenze unsigned short beli_lang_max; //obere Regelgrenze unsigned short beli_lang_maxstep; //maximale Regelschrittweite unsigned short beli_lang_sumgreyset; //RegelSollWert unsigned short beli_lang_dummy; //Reserve unsigned short beli_kurz_roiStart; //ROI Start für Regelung innerhalb der Imager width unsigned short beli_kurz_roiStop; //ROI Ende für Regelung innerhalb der Imager width unsigned short beli_kurz_colSumGreyThresh; //Grauwert-Schwell über der ein Spalte der LL als hell gezählt wird unsigned short beli_kurz_colCntThresh; //RegelSollWert Zahl der LL-hellen Spalten unsigned short beli_lang_roiStart; //ROI Start für Regelung innerhalb der Imager width unsigned short beli_lang_roiStop; //ROI Ende für Regelung innerhalb der Imager width unsigned short beli_lang_colSumGreyThresh; //Grauwert-Schwell über der ein Spalte der LL als hell gezählt wird unsigned short beli_lang_colCntThresh; //RegelSollWert Zahl der LL-hellen Spalten unsigned short beli_numProfilesValid; //11bit, Anzahl gültiger Profile (Profil mit mehr als 16 Punkte) dann startet die Regelung unsigned short spare[7]; }M6; // Pars Method7 CORRELATOR (HW) typedef struct { unsigned short refprofillaenge; unsigned short pruefstartpos; unsigned short pruefendpos; char step; char refprofilefile[512]; short minbestval; }M7; // Pars Method8 2D_HIGHPASS (HW) typedef struct { unsigned char active; unsigned char dummy; unsigned short filtersize_x; unsigned short filtersize_y; }M8; // Pars Method9 GET_AVERAGE_DISTANCE (SW) typedef struct{ char channel; char dummy; unsigned short command; }M9; // Pars Method10 TIMESTAMP_GENERATOR (HW) typedef struct{ char runmode; char countmode; }M10; // Pars Method11 GET_ERROR_STATUS (SW/HW) typedef struct{ char channel; unsigned short command; }M11; // Pars Method12 PROFILTRIGGER (SW) typedef struct{ char mode; unsigned short linedelay; char pcondition[PARREFNAMESIZE]; char pdata[PARREFNAMESIZE]; char nextmod[PARREFNAMESIZE]; char pnullstelle[64]; unsigned short minNullstellen; }M12; // Pars Method13 CALCULATOR (SW) typedef struct{ char mode; char inputa[PARREFNAMESIZE]; char inputb[PARREFNAMESIZE]; }M13; // Pars Method14 COMPARE (SW) typedef struct{ char mode[8]; char inputa[8][PARREFNAMESIZE]; char inputb[8][PARREFNAMESIZE]; }M14; // Pars Method15 GET_VAL (SW) typedef struct{ char data[8][PARREFNAMESIZE]; int offset[8]; char size[8]; }M15; // Pars Method16 LOGIC (SW) typedef struct{ char mode[3]; char inputa[PARREFNAMESIZE]; char inputb[PARREFNAMESIZE]; char inputc[PARREFNAMESIZE]; char inputd[PARREFNAMESIZE]; }M16; // Pars Method17 READ_INPUT (SW) typedef struct{ char active[3]; char condition[3]; char nextmod[3][MODULNAMESIZE]; char channel; unsigned short command; }M17; // Pars Method18 TRIGGER_SETUP (HW) typedef struct{ char mode; unsigned char triggercnt; char inputselect; unsigned char triggerfrq; unsigned char triggeroffset; char dummy; short dummy2; }M18; // Pars Method80 MODUL_Mercedes (HW) typedef struct { unsigned char threshold; unsigned char dummy; unsigned short dummy2; int buffersize; }M80; // Pars Method90 TCP_SEND (SW Send TCP Data) typedef struct{ char channel; unsigned short command; unsigned char reserved; char width[PARREFNAMESIZE]; char pdata[PARREFNAMESIZE]; char roi_startx[PARREFNAMESIZE]; char roi_starty[PARREFNAMESIZE]; char roi_width[PARREFNAMESIZE]; char roi_height[PARREFNAMESIZE]; }M90; // Pars Method99 CMOS_SETUP_LOW (HW Ibis) typedef struct{ short startx; short starty; short width; short height; int beli_kurz; char modulusx; char modulusy; char gain; char offset_raw; char offset_fine; char datavaliddelay; char gamma; unsigned char laserctrl;// unused; ist jetzt eigene Funktion int slope; }M99;
-
Und das ist mal nur die Übersetzung von CamDesc:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)] public struct CAMDESC { public int cam_index; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)] public string name; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 17)] public string IPAdr; public ushort portnum; public int command; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)] public string header; public System.IntPtr pcamdata; public int camdatasize; public int dataavailable; public int connectionstate; public int tcp_handle; public int active; public int alive_time; public int archiv_active; public int archiv_handle; public System.IntPtr lut; public System.IntPtr usercbf; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)] public int[] digio_out; [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)] public int[] digio_in; public int laser_status; public int laserlight; public int fps; public float Temp; public int running; /// PARAM->Anonymous_78cf3d06_3dc4_4201_9042_f198dd9034b7 public PARAM cpar; }
-
Ich würde Schritt für Schritt vorgehen und mit etwas einfachen anfangen - z.B. die Version abfragen.
-
theta schrieb:
Ich würde Schritt für Schritt vorgehen und mit etwas einfachen anfangen - z.B. die Version abfragen.
Habe ich schon ! GetApiVersion funktioniert, die DLL wird bis dato richtig angesprochen. Aber GetApiVersion ist die einzige(!) Funktion die ohne CamDesc auskommt. Der nächste Schritt wäre API_Init(int (*userCB_StatusMessage) (STATUS_MSG_ARGLST)), sicherheitshalber explizit gefolgt von API_Exit(). Die Agumentenliste für den Callback in Init enhält bereits CamDesk.
Das wurde so c# übersetzt:/// STATUS_MSG_ARGLST -> CAMDESC* cd, int msgType, int msgdata1, int msgdata2, char *msg /// Error generating expression: Expression is not parsable. Treating value as a raw string public const string STATUS_MSG_ARGLST = "CAMDESC* cd, int msgType, int msgdata1, int msgdata2, char *msg"; /// Return Type: int ///cd: CAMDESC* ///msgType: int ///msgdata1: int ///msgdata2: int ///msg: char* public delegate int Anonymous_0f4c62be_b627_4c7f_8bdf_1f94d68ecc01(ref CAMDESC cd, int msgType, int msgdata1, int msgdata2, System.IntPtr msg); /// Return Type: char* [System.Runtime.InteropServices.DllImportAttribute("SR_API.dll", EntryPoint = "SR_API_GetAPIVersion", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] public static extern System.IntPtr SR_API_GetAPIVersion(); /// Return Type: int ///userCB_StatusMessage: Anonymous_0f4c62be_b627_4c7f_8bdf_1f94d68ecc01 [System.Runtime.InteropServices.DllImportAttribute("SR_API.dll", EntryPoint = "SR_API_Init", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] public static extern int SR_API_Init(Anonymous_0f4c62be_b627_4c7f_8bdf_1f94d68ecc01 userCB_StatusMessage); /// Return Type: int [System.Runtime.InteropServices.DllImportAttribute("SR_API.dll", EntryPoint = "SR_API_Exit", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] public static extern int SR_API_Exit();
Mein bisheriges Test-Programm dazu (ist die Verwendung des delegaten des übersetzten Callback so richtig??):
using SRAPIHTRANSLATION; namespace testapitranslation { public partial class Form1 : Form { SRAPIHTRANSLATION.CAMDESC Cam1 = new SRAPIHTRANSLATION.CAMDESC(); // MECKERT NICHT(!) SRAPIHTRANSLATION.CAMDESC Cam2 = new SRAPIHTRANSLATION.CAMDESC(); // MECKERT NICHT(!) static int MESSAGEHandler(ref CAMDESC cd, int msgType, int msgdata1, int msgdata2, System.IntPtr msg) { int haltepunkt; // NUR EIN TEST haltepunkt = 5; return haltepunkt; } // MECKERT BIS HIERHER NICHT Anonymous_0f4c62be_b627_4c7f_8bdf_1f94d68ecc01 MSGHandler = MESSAGEHandler; // MECKERT BIS HIERHER NICHT //public Form1() private void button1_Click(object sender, EventArgs e) { string Version; int Eventint; Version = Marshal.PtrToStringAnsi(SRAPIHTRANSLATION.NativeMethods.SR_API_GetAPIVersion()); //funzt textBox1.Text = Version; // funzt Eventint = SRAPIHTRANSLATION.NativeMethods.SR_API_Init(MSGHandler); //funzt nicht marshalling sagt was von zu grosser struct Eventint = SRAPIHTRANSLATION.NativeMethods.SR_API_Exit(); } } }
JEMAND NE IDEE??
-
Hallo !!
Hat jemand ne Idee wie man das Problem lösen könnte ??Bringt es was, wenn ich alle Structs mit EXPLIZIT und Fieldoffset versehe??
DANKE !!