WriteSerialPortString()

Hardware- und Elektronikbasteleien, Ansteuerung von Schnittstellen und Peripherie.
Fragen zu "Consumer"-Problemen kommen in Offtopic.
Benutzeravatar
PIC18F2550
Beiträge: 104
Registriert: 29.04.2024 09:10
Computerausstattung: Server HP Proliant G7
PC AMD FX(tm)-9590, 64Gb Ram, 2x 2TB Raid5 SAS

Re: WriteSerialPortString()

Beitrag von PIC18F2550 »

:o ES GIBT KEIN "ReadSerialPortString()"!!!!

Mal sehen wie ich das hinbekomme mit ReadSerialPortData.

Code: Alles auswählen

    Print("USBALL -> Byte: "+Str(ReadSerialPortData(0, @Pufferin,4)))
    ou$=Hex(Pufferin(0))+"- "+Hex(Pufferin(1))+"- "+Hex(Pufferin(2))+"- "+Hex(Pufferin(3)) 
Das ergebnis ist Das....Nüscht.

Code: Alles auswählen

OS Windows
Error:  Can't open the serial port: COM6
SerialPort COM7 opened With success
CHECK -> USBALL: 4
USBALL -> Byte: 4  [0-0-0-0]
START I/O -> Byte: 19
OUT I/O 55-55-55 -> Byte: 16
OUT I/O AA-AA-AA -> Byte: 16
OUT I/O 55-55-55 -> Byte: 16
OUT I/O AA-AA-AA -> Byte: 16
OUT I/O 55-55-55 -> Byte: 16
OUT I/O AA-AA-AA -> Byte: 16
STOP I/O -> Byte: 7
Error:  Can't open the serial port: COM8
Drücken Sie eine Taste zum Beenden.
Hat jemand eine Idee?
Barbarus hic ergo sum, quia non intellegor ulli.
Ein Barbar bin ich hier, da ich von keinem verstanden werde.
ʎɐqǝ ıǝq ɹnʇɐʇsɐʇ ǝuıǝ ɹǝpǝıʍ ǝıu ǝɟnɐʞ ɥɔı ´uuɐɯ ɥo
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Re: WriteSerialPortString()

Beitrag von DePe »

Ich verstehe dein Problem nicht. Kannst du mehr Code zeigen, oder besser beschreiben was falsch ist.
Man muss auf die Terminierungszeichen '0A 0D' prüfen, um eine ganze Antwort zu erhalten.

Hier ist die z.B. Ausgabe von dem Kommando für die Identifikation '#00':

Code: Alles auswählen

Länge der Daten: 51 Bytes

00| 40 30 30 2D 30 30 2D 30 41 2D 30 32 2D 32 38 2D |@00-00-0A-02-28-|
10| 30 30 2D 30 30 2D 30 30 2D 30 30 2D 30 30 2D 30 |00-00-00-00-00-0|
20| 30 2D 30 30 2D 30 30 2D 30 30 2D 30 30 2D 30 30 |0-00-00-00-00-00|
30| 2D 0A 0D                                        |-..             |
Peter
Benutzeravatar
H.Brill
Beiträge: 496
Registriert: 15.10.2004 17:42
Wohnort: 66557 Neunkirchen

Re: WriteSerialPortString()

Beitrag von H.Brill »

Was ist denn Pufferin für ein Datentyp ?
Ich denke mal, ein numerisches Array ?
Ich dachte, du bekommst schon Hex - Zahlen geliefert.
Dann wäre Chr() die richtige Umwandlung.

Perönlich würde ich dafür ein Stückchen Memory nehmen.

Code: Alles auswählen

*Mem = AllocateMemory(15)
PokeC(*Mem, $48)
PokeC(*Mem + 1, $65)
PokeC(*Mem + 2, $6C)
PokeC(*Mem + 3, $6C)
PokeC(*Mem + 4, $6F)
PokeC(*Mem + 5, $20)
PokeC(*Mem + 6, $57)
PokeC(*Mem + 7, $6F)
PokeC(*Mem + 8, $72)
PokeC(*Mem + 9, $6C)
PokeC(*Mem + 10, $64)
PokeC(*Mem + 11, $20)
PokeL(*Mem + 12, 4711)
Debug PeekS(*Mem, 11, #PB_Ascii)

For k = 0 To 10
  Debug(PeekS(*Mem + k, 1, #PB_Ascii))
Next

Debug PeekL(*Mem + 12)

Finde ich irgendwie flexibler, gerade, was das Auslesen betrifft.
PB 6.10
Benutzeravatar
PIC18F2550
Beiträge: 104
Registriert: 29.04.2024 09:10
Computerausstattung: Server HP Proliant G7
PC AMD FX(tm)-9590, 64Gb Ram, 2x 2TB Raid5 SAS

Re: WriteSerialPortString()

Beitrag von PIC18F2550 »

Ich fasse mal kurz zusammen:
Das Senden über WriteSerialPortString() hab ich hinbekommen.
Klappt super mit 0A oder 0D als Abschluss. :)

Das neue Problem ist ReadSerialPortData(0, @Pufferin,16))
Einige Commandos über WriteSerialPortString() liefern Daten zurück.
es sollen nach der Doku 16Byte sein.

Ich sehe gerade das du den Speicher mit "AllocateMemory()" reservierst.
Ich habe "Dim Pufferin$(16)" genommen.
Ist das entscheident?

Danke DePe für die darstellung des Rückgabestrings.
Hier zeigen sich unterschiede zum Handbuch wo von 16 Byts gesprochen wird in Wirklichkeit sind das aber 51 Byts.
Das muss ich erst einmal umsetzen und Testen.

Danke
Barbarus hic ergo sum, quia non intellegor ulli.
Ein Barbar bin ich hier, da ich von keinem verstanden werde.
ʎɐqǝ ıǝq ɹnʇɐʇsɐʇ ǝuıǝ ɹǝpǝıʍ ǝıu ǝɟnɐʞ ɥɔı ´uuɐɯ ɥo
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: WriteSerialPortString()

Beitrag von NicTheQuick »

Ein "Dim Pufferin$(16)" erzeugt dir einen Puffer mit 16 Strings. Das ist ein großer Unterschied zu 16 Bytes.
Also entweder du nutzt "Dim Pufferin.a(16)" um 16 Bytes zu allokieren und dann als Integerwerte im Bereich 0-255 auslesen zu können. Oder du nimmst eben "AllocateMemory(16)" und weist den Pointer einem passenden Datentyp zu.
Benutzeravatar
H.Brill
Beiträge: 496
Registriert: 15.10.2004 17:42
Wohnort: 66557 Neunkirchen

Re: WriteSerialPortString()

Beitrag von H.Brill »

Ist das entscheident?
Entscheidend nicht unbedingt. Kommt darauf an, was deine Hardware so alles ausgibt.
Bloß in so einem MemoryPuffer kann man alle Zeichen speichern. So z.b. auch die
ersten 32 NICHT druckbaren Zeichen der ASCII - Tabelle, halt alle 256 Zeichen.
Auch ganze Zahlen (Typ i oder Long), die dann 4 Bytes belegen, bekommt man dann
mit PeekL() gut heraus. Und PeekL weiß, daß es 4 Bytes hintereinander abgreifen muß.
PB 6.10
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: WriteSerialPortString()

Beitrag von NicTheQuick »

Doch, es ist ein entscheidender Unterschied, ob man 16 einzelne Strings in einem Array hat und an der Speicherstelle des Arrays nur Pointer zu nicht existierenden Strings stehen oder ob man ein Array aus Bytes oder anderen Zahlentypen erstellt.
Benutzeravatar
PIC18F2550
Beiträge: 104
Registriert: 29.04.2024 09:10
Computerausstattung: Server HP Proliant G7
PC AMD FX(tm)-9590, 64Gb Ram, 2x 2TB Raid5 SAS

Re: WriteSerialPortString()

Beitrag von PIC18F2550 »

Danke für eure Tips die waren für mich hilfreich.

So jetzt kann ich auch daten Empfangen :)

Code: Alles auswählen

CHECK -> USBALL: 4
USBALL -> Byte: 51
40-30-30-2D-30-30-2D-30-41-2D-30-32-2D-31-43-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-30-30-2D-A-D-0-0-0-0-0-0-0-0-0-0-0-0-0-
 @  0  0  -  0  0  -  0  A  -  0  2  -  1  C  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -  0  0  -
Danke.
Barbarus hic ergo sum, quia non intellegor ulli.
Ein Barbar bin ich hier, da ich von keinem verstanden werde.
ʎɐqǝ ıǝq ɹnʇɐʇsɐʇ ǝuıǝ ɹǝpǝıʍ ǝıu ǝɟnɐʞ ɥɔı ´uuɐɯ ɥo
Benutzeravatar
PIC18F2550
Beiträge: 104
Registriert: 29.04.2024 09:10
Computerausstattung: Server HP Proliant G7
PC AMD FX(tm)-9590, 64Gb Ram, 2x 2TB Raid5 SAS

Re: WriteSerialPortString()

Beitrag von PIC18F2550 »

Hier mal den ganzen Block wenn noch jemand danach sucht.

Code: Alles auswählen

*Pufferin=AllocateMemory(64)
OpenConsole("USBALL 10 Test")
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  PrintN("OS Windows")
  P$ = "COM"
CompilerElse
  PrintN("Information", "OS Linux")
  P$ = "/dev/ttyS"
CompilerEndIf

For l=0 To 10
  Port$=P$+Str(l)
  If OpenSerialPort(0, Port$, 0, #PB_SerialPort_NoParity, 0, 0, #PB_SerialPort_NoHandshake, 0, 0) 
    PrintN("SerialPort "+Port$+" opened With success")
    PrintN("CHECK -> USBALL: "+Str(WriteSerialPortString(0, "#00"+Chr($a), #PB_Ascii)))
    Print ("USBALL -> Byte: "+Str(ReadSerialPortData(0, *Pufferin,51)))
    PrintN ("")
    For g=0 To 63
      Print (Hex(PeekB(*Pufferin+g))+"-")
    Next g
    PrintN("")
    For g=0 To 63
      Print (" "+Chr(PeekB(*Pufferin+g))+" ")
    Next g
    PrintN("")
    PrintN("START I/O -> Byte: "+Str(WriteSerialPortString(0, "#50-01-00-00-00-00"+Chr($a), #PB_Ascii)))
    For z=0 To 5
      PrintN("OUT I/O 55-55-55 -> Byte: "+Str(WriteSerialPortString(0, "#50-02-55-55-55"+Chr($a), #PB_Ascii)))
      Delay(100)
      PrintN("OUT I/O AA-AA-AA -> Byte: "+Str(WriteSerialPortString(0, "#50-02-AA-AA-AA"+Chr($a), #PB_Ascii)))
      Delay(100)
    Next z
    PrintN("STOP I/O -> Byte: "+Str(WriteSerialPortString(0, "#50-00"+Chr($a), #PB_Ascii)))
  Else
    PrintN("Error:  Can't open the serial port: "+Port$)
  EndIf
Next l
  PrintN("Drücken Sie eine Taste zum Beenden.") : Input() : CloseConsole()
End
Barbarus hic ergo sum, quia non intellegor ulli.
Ein Barbar bin ich hier, da ich von keinem verstanden werde.
ʎɐqǝ ıǝq ɹnʇɐʇsɐʇ ǝuıǝ ɹǝpǝıʍ ǝıu ǝɟnɐʞ ɥɔı ´uuɐɯ ɥo
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: WriteSerialPortString()

Beitrag von mk-soft »

Wie es aussieht ist es eine ASCII Kommunikation mit Ende Zeichen #LFCR$

Da braucht man nicht Peek oder Poke. PokeC ist eh falsch weil diese Poke Character ist und PB intern Unicode. Somit werden immer bei PokeC zwei byte geschrieben.
Chr($0A) + Chr($0D) braucht man nicht. Dafür gibt es fertige Konstanten bei PB.
Linefeed #LF$, Return #CR$ oder zusammen #LFCR$

Die Kommunikation sollte in einem Thread ablaufen, damit diese nicht durch GUI gestört wird.
Ausserdem sollte der Empfangsbuffer immer ausgelesen werden wenn Daten anstehen.
Ich hatte schon vor langer Zeit mal ein Beispiel zum Senden und Empfangen von Strings mit Erkennung von Ende-Zeichen geschrieben.
Im Beispiel werdende Ende-Zeichen automatisch beim Senden angehängt und beim Empfang entfernt.

Hier mal das Beispiel. In der Procedure InitComport() werden die Einstellungen vorgenommen. Port, Ende-Zeichen, etc

Code: Alles auswählen

;-TOP

; Comment : Comport Manager Over Thread and Callback
; Author  : mk-soft
; Version : v0.07.1
; Created : 26.01.2018
; Updated : 03.09.2022

; *****************************************************************************

CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Use Option Threadsafe!"
CompilerEndIf

Prototype ProtoReceiveCB(Text.s)
Prototype ProtoStatusCB(Status, *ComData)

Enumeration
  #ComThread_Stopped
  #ComThread_Startup
  #ComThread_Running
EndEnumeration

Enumeration
  #ComStatus_Nothing
  #ComStatus_OpenPort
  #ComStatus_ClosePort
  #ComStatus_ErrorOpenPort
  #ComStatus_ErrorSend
  #ComStatus_ErrorReceive
  #ComStatus_ErrorDataSize
EndEnumeration

Structure udtComData
  ; Header
  ThreadID.i
  Exit.i
  Status.i
  ; Port Data
  ComID.i
  Port.s
  Baud.i
  Parity.i
  DataBit.i
  StopBit.i
  Handshake.i
  BufferSize.i
  ; End Of Text
  EndOfText.s
  ; Send Data
  SendSignal.i
  SendCount.i
  SendText.s
  SendError.i
  ; Receive data
  ReceiveCount.i
  ReceiveText.s
  ReceiveError.i
  ; Callback
  *StatusCB.ProtoStatusCB
  *ReceiveCB.ProtoReceiveCB
EndStructure

Procedure thComport(*ComData.udtComData)
  
  Protected *Send, *Receive, SendText.s, SendLen, ReceiveText.s, ReceiveLen, Pos
  
  With *ComData
    ; Startup
    \Status = #ComThread_Startup
    \SendCount = 0
    \ReceiveCount = 0
    \ComID = OpenSerialPort(#PB_Any, \Port, \Baud, \Parity, \DataBit, \StopBit, \Handshake, \BufferSize, \BufferSize)
    If \ComID
      \Status = #ComThread_Running
    Else
      If \StatusCB
        \StatusCB(#ComStatus_ErrorOpenPort, *ComData)
      EndIf
      \Status = #ComThread_Stopped
      ProcedureReturn 0
    EndIf
    If \StatusCB
      \StatusCB(#ComStatus_OpenPort, *ComData)
    EndIf
    *Send = AllocateMemory(\BufferSize)
    *Receive = AllocateMemory(\BufferSize)
    ; Loop
    Repeat
      If \SendSignal
        SendText = \SendText + \EndOfText
        SendLen = StringByteLength(SendText, #PB_Ascii)
        If SendLen <= \BufferSize
          PokeS(*Send, SendText, SendLen, #PB_Ascii)
          If WriteSerialPortData(\ComID, *Send, SendLen) = 0
            \SendError = SerialPortError(\ComID)
            If \StatusCB
              \StatusCB(#ComStatus_ErrorSend, *ComData)
            EndIf
          Else
            \SendError = 0
            \SendCount + 1
          EndIf
        Else
          If \StatusCB
            \StatusCB(#ComStatus_ErrorDataSize, *ComData)
          EndIf
        EndIf
        \SendSignal = #False
      EndIf
      ReceiveLen = AvailableSerialPortInput(\ComID)
      If ReceiveLen
        ReceiveLen = ReadSerialPortData(\ComID, *Receive, ReceiveLen)
        If ReceiveLen = 0
          \ReceiveError = SerialPortError(\ComID)
          If \StatusCB
            \StatusCB(#ComStatus_ErrorReceive, *ComData)
          EndIf
        Else
          \ReceiveError = 0
        EndIf
        ReceiveText + PeekS(*Receive, ReceiveLen, #PB_Ascii)
        Repeat
          pos = FindString(ReceiveText, \EndOfText, 1, #PB_String_NoCase)
          If pos
            \ReceiveText = Left(ReceiveText, pos - 1)
            ReceiveText = Mid(ReceiveText, pos + Len(\EndOfText))
            \ReceiveCount + 1
            If \ReceiveCB
              \ReceiveCB(\ReceiveText)
            EndIf
          EndIf
        Until pos = 0
      EndIf
      Delay(10)
    Until \Exit
    ; Shutdown
    CloseSerialPort(\ComID)
    If \StatusCB
      \StatusCB(#ComStatus_ClosePort, *ComData)
    EndIf
    FreeMemory(*Send)
    FreeMemory(*Receive)
    \Status = #ComThread_Stopped
    \ComID = 0
    \Exit = 0
    ProcedureReturn 1
  EndWith
  
EndProcedure

; ----

Procedure.s SerialPortErrorText(ErrorCode)
  Protected r1.s
  
  Select ErrorCode
    Case #PB_SerialPort_RxOver      : r1 = "An input buffer overflow has occurred."
    Case #PB_SerialPort_OverRun     : r1 = "A character-buffer overrun has occurred."
    Case #PB_SerialPort_RxParity    : r1 = "The hardware detected a parity error."
    Case #PB_SerialPort_Frame       : r1 = "The hardware detected a framing error."
    Case #PB_SerialPort_Break       : r1 = "The hardware detected a break condition."
    Case #PB_SerialPort_TxFull      : r1 = "The application tried to transmit a character but the output buffer was full."
    Case #PB_SerialPort_IOE         : r1 = "An I/O error occurred during communications with the device."
    Case #PB_SerialPort_WaitingCTS  : r1 = "Specifies whether transmission is waiting for the CTS (clear-To-send) signal to be sent."
    Case #PB_SerialPort_WaitingDSR  : r1 = "Specifies whether transmission is waiting for the DSR (Data-set-ready) signal to be sent."
    Case #PB_SerialPort_WaitingRLSD : r1 = "Specifies whether transmission is waiting for the RLSD (receive-line-signal-detect) signal to be sent."
    Case #PB_SerialPort_XoffReceived: r1 = "Specifies whether transmission is waiting because the XOFF character was received."
    Case #PB_SerialPort_XoffSent    : r1 = "Specifies whether transmission is waiting because the XOFF character was transmitted."
    Case #PB_SerialPort_EOFSent     : r1 = "Specifies whether the end-of-file (EOF) character has been received."
    Default                         : r1 = "ErrorCode " + Hex(ErrorCode)
  EndSelect
  ProcedureReturn r1
EndProcedure

; ----

; Threaded String Helper

Procedure AllocateString(String.s)
  Protected *mem
  *mem = AllocateMemory(StringByteLength(String) + SizeOf(Character))
  If *mem
    PokeS(*mem, String)
  EndIf
  ProcedureReturn *mem
EndProcedure

Procedure.s FreeString(*Mem)
  Protected result.s
  If *Mem
    result = PeekS(*Mem)
    FreeMemory(*Mem)
  EndIf
  ProcedureReturn result
EndProcedure

; *****************************************************************************

;- Example

CompilerIf #PB_Compiler_IsMainFile
  
  Global ComData.udtComData
  
  Enumeration EventCustomValue #PB_Event_FirstCustomValue
    #My_Event_NewData
    #My_Event_NewState
  EndEnumeration
  
  ; ---------------------------------------------------------------------------
  
  Procedure ReceiveCB(Text.s)
    PostEvent(#My_Event_NewData, 0, 0, 0, AllocateString(Text))
  EndProcedure
  
  Procedure MyEventNewDataCB()
    Protected Text.s
    Text = FreeString(EventData())
    AddGadgetItem(0, -1, Text)
    SetGadgetState(0, CountGadgetItems(0) - 1)
    SetGadgetState(0, -1)
  EndProcedure
  
  BindEvent(#My_Event_NewData, @MyEventNewDataCB())
  
  ; ---------------------------------------------------------------------------
  
  Procedure StatusCB(Status, *ComData.udtComData)
    PostEvent(#My_Event_NewState, 0, 0, Status, *ComData)
  EndProcedure
  
  Procedure MyEventNewStateCB()
    Protected Text.s, Status, *ComData.udtComData
    Status = EventType()
    *ComData = EventData()
    Select Status
      Case #ComStatus_OpenPort
        Text = "ComStatus: Open Port " + *ComData\Port
      Case #ComStatus_ClosePort
        Text = "ComStatus: Close Port " + *ComData\Port
      Case #ComStatus_ErrorOpenPort
        Text = "ComError: Open Port " + *ComData\Port
      Case #ComStatus_ErrorSend
        Text = "ComError Send: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\SendError)
      Case #ComStatus_ErrorReceive
        Text = "ComError Receive: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\ReceiveError)
      Case #ComStatus_ErrorDataSize
        Text = "ComError Send: Port " + *ComData\Port + " - Send data size to big."
    EndSelect
    If Bool(Text)
      StatusBarText(0, 0, Text)
    EndIf
  EndProcedure
  
  BindEvent(#My_Event_NewState, @MyEventNewStateCB())
  
  ; ---------------------------------------------------------------------------
  
  Procedure InitComport()
    With ComData
      If \Status
        ProcedureReturn 2 ; Always running
      EndIf
      \Port = "COM4"
      \Baud = 115200
      \Parity = #PB_SerialPort_NoParity
      \DataBit = 8
      \StopBit = 1
      \Handshake = #PB_SerialPort_NoHandshake
      \BufferSize = 2048
      \EndOfText = #LF$ ; #LFCR$
      \StatusCB = @StatusCB()
      \ReceiveCB = @ReceiveCB()
      \ThreadID = CreateThread(@thComport(), ComData)
      If Not \ThreadID
        ProcedureReturn 0 ; Error create thread
      Else
        ProcedureReturn 1 ; ok
      EndIf
    EndWith
  EndProcedure
  
  Procedure Main()
    Protected Event, Text.s, i
    If OpenWindow(0, #PB_Ignore, #PB_Ignore, 800, 600, "Comport", #PB_Window_SystemMenu)
      CreateStatusBar(0, WindowID(0))
      AddStatusBarField(#PB_Ignore)
      ListViewGadget(0, 0, 0, 800, 540)
      StringGadget(1, 5, 545, 590, 25, "")
      ButtonGadget(2, 605, 545, 90, 25, "Send")
      ButtonGadget(3, 695, 545, 90, 25, "On/Off")
      AddKeyboardShortcut(0, #PB_Shortcut_Return, 1000)
      
      CreatePopupMenu(1)
      MenuItem(101, "Copy ListView")
      
      Repeat
        Event = WaitWindowEvent()
        Select Event
          Case #PB_Event_CloseWindow
            If ComData\Status
              MessageRequester("Info", "Comport Is Open!", #PB_MessageRequester_Warning)
            Else
              Break
            EndIf
            
          Case #PB_Event_Gadget
            Select EventGadget()
              Case 0
                If EventType() = #PB_EventType_RightClick
                  DisplayPopupMenu(1, WindowID(0))
                EndIf
                
              Case 2 ; send button
                If ComData\Status = #ComThread_Running And ComData\SendSignal = #False
                  ComData\SendText = GetGadgetText(1)
                  ComData\SendSignal = #True
                EndIf
              Case 3 ; on/off button
                If ComData\Status
                  ComData\Exit = 1
                Else
                  If Not InitComport()
                    StatusBarText(0, 0, "Comport " + ComData\Port + ": Error Create Thread")
                  EndIf
                EndIf
            EndSelect
            
          Case #PB_Event_Menu
            Select EventMenu()
              Case 101 ; popup menu
                Text = ""
                For i = 0 To CountGadgetItems(0) - 1
                  text + GetGadgetItemText(0, i) + #CRLF$
                Next
                SetClipboardText(Text)
                
            EndSelect
        EndSelect
      ForEver
    EndIf
  EndProcedure : Main()
  
CompilerEndIf
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten