alias in C# bekannt machen vorher war es ein typedef **gelöst**



  • 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 short

    MfG



  • 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 - int

    in 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?



  • jetzt kennt er das enum nicht

    public enum tKSRWDllComType
    	{
    		KSRW_DLLCT_RS232 = 0,					//RS232 connection
    		KSRW_DLLCT_USB,							//USB connection
    		KSRW_DLLCT_ETHERNET						//Ethernet connection
    	};
    
    ComConfig.m_ComType = KSRW_DLLCT_RS232;
    

    Fehler CS0103: Der Name "KSRW_DLLCT_RS232" ist im aktuellen Kontext nicht vorhanden.

    MfG



  • Ok

    das verursacht den selben Fehler:

    DllDotNet.tKSRWDllComType test = new DllDotNet.tKSRWDllComType();
                test = KSRW_DLLCT_USB;
    

    wie mache ich das enum bekannt?



  • Destiniy schrieb:

    also value ist der alias für typedef?

    Nein.

    In ISO C++ gibts das Keyword struct. In C++/CLI gibts das Keyword value struct.

    Lies mal das: http://www.codeproject.com/KB/books/CppCliInActionCh1Ex1.aspx



  • die Seite ist ganz gut.

    Nur leider sagt sie auch nichts warum ich das enum nicht zuweisen kann.

    public enum tKSRWDllComType
        {
            KSRW_DLLCT_RS232 = 0,                    //RS232 connection
            KSRW_DLLCT_USB,                            //USB connection
            KSRW_DLLCT_ETHERNET                        //Ethernet connection
        };
    
    DllDotNet.tKSRWDllComType test = new DllDotNet.tKSRWDllComType();
                test = KSRW_DLLCT_USB;
    

    kannst du mir nochmal nen tip geben?

    MfG



  • so wenn ich aus dem enum ein enum struct mache

    public enum struct tKSRWDllComType
    	{
    		KSRW_DLLCT_RS232 = 0,					//RS232 connection
    		KSRW_DLLCT_USB,							//USB connection
    		KSRW_DLLCT_ETHERNET						//Ethernet connection
    	};
    

    dann kann ich es in C# setzen.

    DllDotNet.tKSRWDllComType test = new DllDotNet.tKSRWDllComType();
                test = DllDotNet.tKSRWDllComType.KSRW_DLLCT_USB;
    

    Jetz frage ich mich was ist da der unterschied? Kann mir den einer erklären?

    MfG




Anmelden zum Antworten