C++ Methode in C#
-
hi ich hab ein problem mit einer dll die in c++ geschrieben ist.
in der beschreibung steht:void* _stdcall Ethernet_Connect(cahr *chIP, char *chPort, unsigned int uiTimeOut)
OutPut:
void*: scuccess: Scanner object
nosuccess: NULLdie c# deklaration sieht so aus
[DllImport("EthernetScanner.dll", EntryPoint = "EthernetScanner_Connect")]
public static extern object EthernetScanner_Connect(string ip, string port, int timeout);nur schmeißt er den hier:
System.Runtime.InteropServices.MarshalDirectiveException wurde nicht behandelt.
Message="PInvoke-Einschränkung: Es können keine Varianten zurückgegeben werden."
-
Du erhälst auch kein Objekt zurück sondern einen Zeiger. Dazu gibt es in C#
IntPtr
. Zudem ist dein Timeout-Parameter ebenfalls von einem falschen Typ. Du hast in C#uint
fürunsigned int
.Dein
EntryPoint
in C# stimmt zudem mit dem von dir gezeigten Funktionsnamen nicht überein. Aber ich nehme mal an, dass das nur ein Schreibfehler von deiner Seite ist.Grüssli
-
danke hat funktioniert
nun hab ich jedoch ein weiteres problem
unsigned int _stdcall GetInfo(structESInfo *structinfo) structESInfo *structinfo: typedef struct _ESI { <<-- variablen -->> } structESInfo;
in c# sieht das bei mir so aus
//methode dekl. [DllImport("EthernetScanner.dll", EntryPoint = "GetInfo")] public static extern uint GetInfo(ethernetscannerinfo infostr); //struktur public struct ethernetscannerinfo { // public variablen } //aufruf ethernetscannerinfo infostr = new ethernetscannerinfo(); GetInfo(scannerobject, infostr, size, timeout);
wahrscheinlich ist hier wieder irgendwo ein kleiner fehler
-
Das
GetInfo(scannerobject, infostr, size, timeout);
passt doch kein bisschen zur Signatur
public static extern uint GetInfo(ethernetscannerinfo infostr);
welche wiederum nicht zu
*unsigned int _stdcall GetInfo(structESInfo structinfo)
passt.Wenn Du die struct per Referenz übergeben willst und nicht per value, kannst du es so machen:
GetInfo(structESInfo& structinfo) //C++und auf C# Seite
GetInfo(ref ethernetscannerinfo infostr);Wenn Du auf C++ Seite bei Pointern bleiben willst, solltest Du Dir die bereits empfohlene IntPtr-struct anschauen.
-
dass auf c++ seite ist fest und kann icht nicht ändern
c# seite sieht nun so aus:
[DllImport("EthernetScanner.dll", EntryPoint = "EthernetScanner_GetInfo")] public static extern uint GetInfo(out IntPtr infostrptr); //infodaten lesen IntPtr strptr = new IntPtr(); ; EthernetScanner_GetInfo(out strptr); ethernetscannerinfo infostr = new ethernetscannerinfo(); infostr = (ethernetscannerinfo)Marshal.PtrToStructure(strptr, strptr.GetType());
jetzt wahrscheinlich komplett falsch
-
Auf die schnelle Zusammengeschrieben. Habe keine Lust das auf Deine Typen zu übertragen, aber ich denke Du kannst damit arbeiten.
extern "C" __declspec( dllexport ) void Func(SpotsParameter* p); void Func(SpotsParameter* p) { p->minArea = 23; }
struct SpotsParameter { int minArea; };
public struct SpotsParameter { public int minArea; }
public static class OpenCvUtil { [DllImport("OpenCVImaging.dll", CallingConvention = CallingConvention.StdCall)] public static extern void Func(IntPtr p); }
SpotsParameter p = new SpotsParameter(); IntPtr ip = Marshal.AllocHGlobal(Marshal.SizeOf(p)); Marshal.StructureToPtr(p, ip, false); OpenCvUtil.Func(ip); SpotsParameter p2 = (SpotsParameter)Marshal.PtrToStructure(ip, typeof(SpotsParameter)); Marshal.FreeHGlobal(ip); MessageBox.Show(p2.minArea.ToString());
-
habs jetzt umgebaut - funktioniert trotzdem nicht variablen in struktur sind leer
jetzt mal komplett.
[DllImport("EthernetScanner.dll", EntryPoint = "EthernetScanner_GetInfo")] public static extern uint EthernetScanner_GetInfo(IntPtr scannerobject, IntPtr infostrptr, uint infostrgröße, uint timeout);
//infodaten lesen uint size = Convert.ToUInt32(Marshal.SizeOf(typeof(ethernetscannerinfo))); ethernetscannerinfo es1 = new ethernetscannerinfo(); IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(es1)); Marshal.StructureToPtr(es1, ptr, false); EthernetScanner_GetInfo(scannerobject, ptr, size, timeout); ethernetscannerinfo es2 = (ethernetscannerinfo)Marshal.PtrToStructure(ptr, typeof(ethernetscannerinfo)); Marshal.FreeHGlobal(ptr);
der vollständigkeit halber noch die zeile aus der .h
extern unsigned int _stdcall EthernetScanner_GetInfo(void *pEthernetScanner, structEthernetScannerInfo *structInfo, unsigned int uiInfoSize, unsigned int uiTimeOut);
-
1. Ist die C#-Assembly für die gleiche Plattform kompiliert wie die DLL? (x86,amd64)
2. Ist Dir der genaue Aufbau der ethernetscannerinfo-struct bekannst und hast Du das so in C# nachgebaut?
3. Evtl musst Du Padding-Bytes und so ein Gedöns beachten, siehe: http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.structlayoutattribute.aspx
-
die struktur sieht in c++ so aus:
structEthernetScannerInfo *structInfo: typedef struct _EtherNetScannerInfo { .... char chFirmwareName[...]; usigned int ...... } structEthernetInfo;
in c# so
// die struktur public struct ethernetscannerinfo { public string[] chSerienNummer; //= new string[/*serielnumbersize*/9]; public string[] chFirmwareName; //= new string[/*fimwarenamesize*/6]; public uint uiMBAnfang, uiMB, uiSBAnfang, uiSBEnde, uiMBLinMax, uiSBLinMax, uiMBNotLinMax, uiSBNotLinMax; public uint uiMBPixelMax, uiSBPixelMax, uiTemperatur, uiOperatinSeconsCounter, uiPowerCycleCounter, uiFiFo; public uint uiPositionEncoder, uiPositionEncoderDirection, uiProtokollVersion, uiLiniarisation, uiCameraMode; public uint uiProfileMode, uiScannerMode, uiShutterTimerForManuellMode, uiShutterTimeMaxForAutoMode; public uint uiPixelReadOutStart, uiPixelReadOutEnd, uiVideoGain, uiLaserIntensityThreshold, uiLaserTargetValue; public uint uiPeakWidthLimit, uiPeakThreshold, uiSynchronisation, uiProtocolVersion, uiShutterControl; public uint uiLiniarisation2, uiSpeed, uiFPGAVersion, uiDigitalInput, uiLaserValueOfProfile; } //ende-struktur
sollte das gleiche sein oder?
-
Ev. hilft dir das Tool P/Invoke Interop Assistant weiter. Ein Artikel darüber gibt es hier bei MSDN.
-
matze94 schrieb:
char chFirmwareName[...];
public string[] chFirmwareName;
sollte das gleiche sein oder?
Nein, C++-char[] kannst Du nicht einfach in C#-strings[] mappen.
Die MSDN hat viele Beispiele dazu.