alias in C# bekannt machen vorher war es ein typedef **gelöst**
-
das soll ein array of char sein mit 12 chars größe.
meine Frage ist genau die wie deklariere ich in CLI genau das array, das ich es in C# nutzen kann. im CLI Code werde ich die daten dann von meinem C arry in das neue CLI Array Kopieren damit c# meine Daten verarbeiten kann.
MfG
-
das soll ein array of char sein mit 12 chars größe.
Ja, natürlich, das sehe ich. Aber wie wird es gebraucht? Was bedeutet es?
Geht ev. einfach ein System::String^ ??
oder ein array<char>^ ??
-
nein es Wird kein String in den Bytes kommen Nummern die als IDs interpretiert werden.
-
Hmm, warum muss es dafür unbedingt ein Char-Array sein?
-
ich denke muß es nicht also es sollte ein Typ sein der für 12 Bytes platz hat.
ich wollte nur wissen wie man ein char array deklariert in CLI damit man es in C# nutzen kann.
Ich bin auch mit einem anderen Datentyp zufrieden den C# kennt und der 12 byte Platz bietet.
MfG
Edit: ich habe sonst immer MFC programmiert und in .NET noch nix gemacht, deshalb kenne ich die Typen von C# nicht.
-
Dann ist wohl für dich das einfachste arraySystem::Char^ zu benutzen.
Ein managed char array. In C# mit char[] anzusprechen. Allerdings kommt irgendwann der Punkt wo Du das managed array in ein native array bringen musst...Trotzdem:
Was ich Dir immer noch nicht entlocken konnte ist, was die Absicht hinter den 12 Bytes sind. Denn wenn diese bekannt ist, könnte eine sinnvolle Abstraktion gemacht werden, das ganze anständig gekapselt werden und sogar noch für .NET verfügbar gemacht werden (als Klasse oder Struct).Simon
-
diese 12 Byte ergeben eine ID die später meistens Hexadezimal dargestellt wird anhand dieser ID kann man dann bestimmte einträge aus Datenbaken holen
-
So.. hier mal ein Bsp:
C++/CLI DLL, File: Lib.h
#pragma once using namespace System; using namespace System::Text; using namespace System::Diagnostics; namespace Lib { public ref class ID { public: ID(array<Byte>^ data) : _data(data) { if (data == nullptr) { throw gcnew ArgumentNullException(); } if (data->Length != 12) { throw gcnew ArgumentException(); } } ID(Byte b0, Byte b1, Byte b2, Byte b3, Byte b4, Byte b5, Byte b6, Byte b7, Byte b8, Byte b9, Byte b10, Byte b11) { _data = gcnew array<Byte>(12); _data[0] = b0; _data[1] = b1; _data[2] = b2; _data[3] = b3; _data[4] = b4; _data[5] = b5; _data[6] = b6; _data[7] = b7; _data[8] = b8; _data[9] = b9; _data[10] = b10; _data[11] = b11; } virtual String^ ToString() override { StringBuilder^ sb = gcnew StringBuilder(); for (int i = 0; i < _data->Length; ++i) { sb->AppendFormat(L"0x{0:x2}", _data[i]); if (i < _data->Length - 1) { sb->Append(L" "); } } return sb->ToString(); } property array<Byte>^ Data { array<Byte>^ get() { return _data; } } private: array<Byte>^ _data; }; } bool Marshal(Lib::ID^ id, char* buffer, size_t length) { array<Byte>^ data = id->Data; if (length != data->Length) { return false; } for (int i = 0; i < data->Length; ++i) { buffer[i] = data[i]; } return true; }
C# Code
using System; using System.Diagnostics; namespace App { class Program { static void Main(string[] args) { Lib.ID id = new Lib.ID(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }); Debug.WriteLine(id.ToString()); } } }
Dabei kannst Du die Funktion Marshal der Library innerhalb dieser benutzen um eine ID in ein natives char array zu kopieren.
Simon
-
Von der C#-Seite aus sollte es einfach sein, mit MarshalAs(UnmanagedType.ByValArray, ...) einen kompatiblen value type ("struct") zu erzeugen. Die "struct" auf der C++ Seite bleibt dabei einfach unmanaged.
Eine andere Möglichkeit wäre einfach 3 ints in eine ref struct zu packen, mit LayoutKind.Sequential:
[StructLayout(LayoutKind::Sequential, Pack = 8)] ref struct MyID { int part1; int part2; int part3; };
Hier müsste man auf der C++ Seite dann vermutlich einen pin_ptr verwenden. Oder halt die drei ints in drei getrennten Zuweisungen irgendwo reinkopieren.
-
danke erst mal für das Beispiel oben
ich fange aber erst mal mit den struckts an.
Folgendes struckt habe ich als c++ code:
typedef struct { tDllComType m_ComType; union { struct { TByte m_ubPort; //COM port TDWord m_uwBaudrate; //baud rate tDllParityMode m_DllParityMode; TBool m_bAreTwoStopBits; } m_RS232; struct { TDWord m_udwDeviceNumber; } m_USB; struct { TBool m_bIPAddressType; //0 = IPv4 or 1 = IPv6 TBool m_bIsIPAddress; union { TByte m_rgubIPAddress[16]; //IPaddress TByte m_rgubNetworkName[16]; } m_KindOfConnection; } m_Ethernet; } m_ComConfigParameters; } tComConfigData;
dazu der code in CLI
public enum tKSRWDllComType { KSRW_DLLCT_RS232 = 0, //RS232 connection KSRW_DLLCT_USB, //USB connection KSRW_DLLCT_ETHERNET //Ethernet connection }; public enum tKSRWDllParityMode { KSRW_PM_NOPARITY = 0, KSRW_PM_ODDPARITY, KSRW_PM_EVENPARITY, KSRW_PM_FORCEDTOONE, KSRW_PM_FORCEDTOZERO, }; public struct tKSRWComConfigData { tKSRWDllComType m_ComType; union { struct { TByte m_ubPort; //COM port TDWord m_uwBaudrate; //baud rate tKSRWDllParityMode m_DllParityMode; TBool m_bAreTwoStopBits; } m_RS232; struct { TDWord m_udwDeviceNumber; } m_USB; struct { TBool m_bIPAddressType; //0 = IPv4 or 1 = IPv6 TBool m_bIsIPAddress; union { TByte m_rgubIPAddress[16]; //IPaddress TByte m_rgubNetworkName[16]; } m_KindOfConnection; } m_Ethernet; } m_ComConfigParameters; };
jetzt kann ich zwar in C# eine Variable von dem Typ instanziieren kann aber nicht auf die einzelnen Teile zugreifen:
DllDotNet.tKSRWComConfigData ComConfig = new DllDotNet.tKSRWComConfigData(); ComConfig.m_ComType= KSRW_DLLCT_RS232;
er meldet:
Fehler CS1061: "ReaderDllDotNet.tKSRWComConfigData" enthält keine Definition für "m_ComType", und es konnte keine Erweiterungsmethode "m_ComType" gefunden werden, die ein erstes Argument vom Typ "ReaderDllDotNet.tKSRWComConfigData" akzeptiert. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)weiterhin brauche ich noch äquivalente typen für
#define TBool unsigned char
#define TByte unsigned char
#define TsByte signed char
#define TWord unsigned short
#define TsWord signed shortMfG
-
Sag mal.. könnte es sein, dass der Aufwand für neu schreiben in C# kleiner ist als eine C++/CLI Bridge zu bauen?
-
Nein die Dll hat ca. 100 Funktionen davon einige Callbacks und insgesamt ein paar (ca. 10) eigen definierte typen als zusätzliche übergabeparameter.
Außerdem müßte mann dann änderungen immer an beiden Codestellen machen, was ich viel schlimmer finde.
Die Callbacks hab ich jetzt müssen nur noch die typen passend gemacht werden. Mein Problem ist ich weiß nicht so recht welche Typen es in CLI gibt und welche davon dann auch in C# verfügbar sind. Zum Test habe ich mal ein char definiert als übergabeparameter aber öffensichtlich scheint auch der c# char typ anders zu sein denn das ging auch nicht.
Aber in dem struckt ist alles mögliche drion was ich benötige, deshalb hab ich das mal angegeben.
MfG
-
Mein Problem ist ich weiß nicht so recht welche Typen es in CLI gibt und welche davon dann auch in C# verfügbar sind.
Du meinst wohl C++/CLI, den CLI ist die Common Language Infrastructure.
Aber zu Frage: Der Witz ist ja gerade, dank der dem CTS (Common Type System), dass in beiden Sprachen C# und C++/CLI (und alle anderen .NET Sprachen) dieselben Typen zur Verfügung stehen.Zum Test habe ich mal ein char definiert als übergabeparameter aber öffensichtlich scheint auch der c# char typ anders zu sein denn das ging auch nicht
Was Dir Kopfzerbrechen macht, vermute ich, wie die Typen zwischen C++/CLI (CTS, .NET) und dem ISO C++ gemappt sind.
Bsp. ein System.Char (.NET) ist 16bit Zahlenwert. Ausserdem ist in C# das Keyword char auf diesen Typen gemappt. Dasselbe auch in C++/CLI.
In ISO C++ jedoch ist char ein mindestens 8 bit grosser Zahlenwert.
Simon
-
wenn char in CLI/C++ und C# gleich wäre wieso geht das nicht:
in meiner Wrapper Klasse
public delegate void tKSRWdelHandler(char uwNumberOfDevices, void *pListOfDevices);
unsafe public void DllUSBDeviceChangeHandler(char uwNumberOfDevices, void *pListOfDevices) { } DllDotNet.CReadWrapper.OnHandler += new DllDotNet.tKSRWdelHandler(DllUSBDeviceChangeHandler);
er meldet:
Fehler CS0123: Keine Überladung für "DllUSBDeviceChangeHandler" stimmt mit dem Delegaten "ReaderDllDotNet.tKSRWdelDllUSBDeviceChangeHandler" überein.mache ich aus char int klappt es.
Aber mein eigentliches Problem ist das struct zur Zeit.
MfG
-
jetzt hab ich es
dem c# char entspricht der ClI/C++ Char (groß geschrieben) der normale char (klein geschrieben) existiert ind CLI/C++ noch aber nicht mehr in C#
also hab ich den Char groß geschrieben und es ging.
Oder ich schreibe in CLI/C++ char (klein) und in C# sbyte.
Also jetzt noch mal die Frage nach dem Problem bei dem struct. Wieso kann ich nicht auf die member zugreifen?
MfG
-
Bsp. ein System.Char (.NET) ist 16bit Zahlenwert. Ausserdem ist in C# das Keyword char auf diesen Typen gemappt. Dasselbe auch in C++/CLI.
Da ist mir noch ein Fehler unterlaufen:
In C# ist das Keyword char auf System.Char gemappt (16 bit, unsigned).
In C++/CLI ist das Keyword char auf System::SByte gemappt (8 bit, signed)Simon
Edit: *g* fast gleichzeitig...
-
c++ type - C# type
unsigned char - byte
char - sbyte
unsigned short - ushort
short - short
unsigned long - uint
long - intin c# gemappt?
mein struct sieht jetzt so aus:
public struct tKSRWComConfigData { tKSRWDllComType m_ComType; union { struct { unsigned char m_ubPort; //COM port unsigned long m_uwBaudrate; //baud rate tKSRWDllParityMode m_DllParityMode; unsigned char m_bAreTwoStopBits; } m_RS232; struct { unsigned long m_udwDeviceNumber; } m_USB; struct { unsigned char m_bIPAddressType; //0 = IPv4 or 1 = IPv6 unsigned char m_bIsIPAddress; union { unsigned char m_rgubIPAddress[16]; //IPaddress unsigned char m_rgubNetworkName[16]; } m_KindOfConnection; } m_Ethernet; } m_ComConfigParameters; };
aber ich kann in C# immer noch nicht auf die member zugreifen (Fehler CS1061: "DllDotNet.tKSRWComConfigData" enthält keine Definition für "m_ComType", und es konnte keine Erweiterungsmethode "m_ComType" gefunden werden, die ein erstes Argument vom Typ "DllDotNet.tKSRWComConfigData" akzeptiert. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)
)DllDotNet.tKSRWComConfigData ComConfig = new DllDotNet.tKSRWComConfigData(); ComConfig.m_ComType = KSRW_DLLCT_RS232;
woran könnte dies liegen?
MfG
-
ich vereinfache nochmal
public struct tKSRWComConfigData { unsigned char test; //tKSRWDllComType m_ComType; };
DllDotNet.tKSRWComConfigData ComConfig = new DllDotNet.tKSRWComConfigData(); ComConfig.test = 5;
ergibt den selben Fehler.
MfG
-
Dein struct ist einfach kein .NET. Es ist kein C++/CLI.
(Ehrlich gesagt, wundert es mich, dass es in C# sichtbar / instanzierbar ist.)Ein .NET kompatibles struct wäre so:
namespace A { public value struct B { char c; } }
-
also value ist der alias für typedef?