Page 1 of 2

Am I having a UNICODE issue?

Posted: Wed Aug 27, 2008 8:57 pm
by Rook Zimbabwe
OK here is a simple Client / Server program Set.

If both are compiled in ASCII and by that I mean WITHOUT the flag for CREATE UNICODE EXECUTABLE being set in compiler options... it works well.

BUT

If I set the CLIENT to CREATE UNICODE EXECUTABLE and not the server... The server shows the program is there, but when it returns strings to the CLIENT nothing gets shown! Nothing is recieved by the client?

It is WORSE if BOTH are compiled with the UNICODE option!

So WHY?

CLIENT CODE

Code: Select all


Enumeration
  #Window_0
EndEnumeration

Enumeration
  #String_INPUT
  #Button_PLINKSERVER
  #String_SERVERADDRESS
  #Button_SEND
  #Button_GETNUM
  #Listview_CLIENT
EndEnumeration

Structure VisualDesignerGadgets
  Gadget.l
  EventFunction.l
EndStructure

Global ConnectionID
Global NewList EventProcedures.VisualDesignerGadgets()
Global *buffer = AllocateMemory(2000) ; to send and recieve info from DB

Procedure String_INPUT_Event(Window, Event, Gadget, Type)
  ; Debug "#String_INPUT"
EndProcedure

Procedure Button_PLINKSERVER_Event(Window, Event, Gadget, Type)
  Debug "#Button_PLINKSERVER"
  
EndProcedure

Procedure String_SERVERADDRESS_Event(Window, Event, Gadget, Type)
  ; Debug "#String_SERVERADDRESS"
EndProcedure

Procedure Button_SEND_Event(Window, Event, Gadget, Type)
  Debug "#Button_SEND"
    txt$ = GetGadgetText(#String_INPUT)
    If txt$ > ""
        query$ = "TXTSET"+txt$
         SendNetworkString(ConnectionID, query$)
    Else
        MessageRequester("PEBKC Error", "Please INPUT more then 2 characters..."+Chr(10)+"Then press [SEND]")
   EndIf
   
EndProcedure

Procedure Button_GETNUM_Event(Window, Event, Gadget, Type)
  Debug "#Button_GETNUM"
  big$ = GetGadgetText(#String_INPUT)
    If big$ > ""
        query$ = "GETNUM"+big$
         SendNetworkString(ConnectionID, query$)
    Else
        MessageRequester("PEBKC Error", "Please INPUT a Maximum Value for your Random Number..."+Chr(10)+"Then press [GET NUMBER]")
    EndIf
    
EndProcedure

Procedure Listview_CLIENT_Event(Window, Event, Gadget, Type)
  Debug "#Listview_CLIENT"
EndProcedure

Procedure RegisterGadgetEvent(Gadget, *Function)
  
  If IsGadget(Gadget)
    AddElement(EventProcedures())
    EventProcedures()\Gadget        = Gadget
    EventProcedures()\EventFunction = *Function
  EndIf
  
EndProcedure

Procedure CallEventFunction(Window, Event, Gadget, Type)
  
  ForEach EventProcedures()
    If EventProcedures()\Gadget = Gadget
      CallFunctionFast(EventProcedures()\EventFunction, Window, Event, Gadget, Type)
      LastElement(EventProcedures())
    EndIf
  Next
  
EndProcedure

Procedure Open_Window_0()
  
  If OpenWindow(#Window_0, 50, 41, 400, 264, "5n4r3 <l13nT3.14159",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
    If CreateGadgetList(WindowID(#Window_0))
      ListViewGadget(#Listview_CLIENT, 5, 10, 390, 135)
      RegisterGadgetEvent(#Listview_CLIENT, @Listview_CLIENT_Event())
      ButtonGadget(#Button_GETNUM, 5, 175, 195, 40, "GET RANDOM NUMBER")
      RegisterGadgetEvent(#Button_GETNUM, @Button_GETNUM_Event())
      ButtonGadget(#Button_SEND, 205, 175, 185, 40, "SEND LINE")
      RegisterGadgetEvent(#Button_SEND, @Button_SEND_Event())
      StringGadget(#String_SERVERADDRESS, 205, 225, 185, 25, "")
      RegisterGadgetEvent(#String_SERVERADDRESS, @String_SERVERADDRESS_Event())
      ButtonGadget(#Button_PLINKSERVER, 5, 225, 190, 25, "PLINK SERVER")
      RegisterGadgetEvent(#Button_PLINKSERVER, @Button_PLINKSERVER_Event())
      StringGadget(#String_INPUT, 5, 150, 385, 20, "")
      RegisterGadgetEvent(#String_INPUT, @String_INPUT_Event())
      
    EndIf
  EndIf
EndProcedure

Open_Window_0()

; ***************************************
; Change this for the address in your Server before you run this program
Server$ = "192.168.1.2"
; ***************************************

If InitNetwork() = 0
    Debug " NO NETWORK"
    MessageRequester("NETWORK ERROR", "NO NETWORK DETECTED"+Chr(10)+"Please verify Network Connection!"+Chr(10))
EndIf

AddGadgetItem(#ListView_CLIENT, -1,"NETWORK FOUND")

If ExamineIPAddresses()
    IP.l = NextIPAddress()
EndIf

PI$ = Str(IP.l)
PI$ = Right(PI$,5)

ip$ = Server$

ConnectionID = OpenNetworkConnection(ip$, 6654)
If ConnectionID = 0
    MessageRequester("NO SERVER", "NO SERVER DETECTED"+Chr(10)+Chr(10)+"Please verify Server Address"+Chr(10)+"and run resQ1.exe to change."+Chr(10)+Chr(10)+"Server IP:  "+server$+Chr(10)+Chr(10)+"Click OK To End program.")
    ip$ = "MANAGER"
    Goto Zoey
EndIf

Repeat
  
  Event  = WaitWindowEvent(12)
  Gadget = EventGadget()
  Type   = EventType()
  Window = EventWindow()
  
  Select Event
    Case #PB_Event_Gadget
      CallEventFunction(Window, Event, Gadget, Type)
      
  EndSelect
      If NetworkClientEvent(ConnectionID)
        length.l = ReceiveNetworkData(ConnectionID, *buffer, 4800)
        Str$ = PeekS(*buffer,4800)  ; , #PB_Ascii)
        Debug "recvd: "+str$
        t$ = Left(Str$,6)
        length = Len(Str$)
        Select t$
            Case "SETNUM"
                long = length - 6
                Sr$ = Right(Str$,long)
                AddGadgetItem(#ListView_CLIENT, -1, "RCVD: "+Sr$)
            Case "TXTSET"
                long = length - 6
                Sr$ = Right(Str$,long)
                AddGadgetItem(#ListView_CLIENT, -1, ":DVCR "+Sr$)
             ;   clearmemory()
        EndSelect        
       ; ClearMemory()
    EndIf
Until Event = #PB_Event_CloseWindow

Zoey:

End

and

SERVER CODE

Code: Select all

; (c) Copyright 2007 - Ralph Wm Dunn and Blue Mesa Software
; All Notional and International Rights Reserved for Perpetuity
Enumeration
    #Window_0
EndEnumeration

Enumeration
    #String_INPUT
    #Button_SEND
    #Text_1
    #Text_SERVADDRESS
    #Listview_TEXT
    #Listview_ACTIVITY
    #Server
    #Font1
EndEnumeration

Structure VisualDesignerGadgets
    Gadget.l
    EventFunction.l
EndStructure

Global ClientID
Global NewList EventProcedures.VisualDesignerGadgets()
Global FontID1
FontID1 = LoadFont(#Font1, "Courier", 9)
Global String$
Global buffet
Global query$

Global *bufferS = AllocateMemory(4800)

Declare ClearMemory(*memory.b, length.l)

Procedure GetNumber(MAX, ClientID)
    ReturnNumber = Random(MAX)
    goof$ = "SETNUM"+Str(ReturnNumber)
        SendNetworkString(ClientID, goof$)
    AddGadgetItem(#Listview_ACTIVITY, -1, "SENT: "+goof$)
EndProcedure

Procedure SwitchText(DOIT$,ClientID)
    blab = Len(DOIT$)
    For X = blab To 1 Step -1
        jok$ = Mid(DOIT$,X,1)
        joker$ = joker$ + jok$
    Next
    SendNetworkString(ClientID, "TXTSET"+joker$)
    AddGadgetItem(#Listview_ACTIVITY, -1, "SENT: "+joker$)
EndProcedure

Procedure UpdateList()
    
    Result = CountGadgetItems(#Listview_TEXT)
    SetGadgetItemState(#Listview_TEXT,Result,#PB_ListIcon_Selected)
    
    Result1 = CountGadgetItems(#Listview_ACTIVITY)
    SetGadgetItemState(#Listview_ACTIVITY,Result1+1,#PB_ListIcon_Selected)
    
EndProcedure

Procedure ClearMemory(buf,size) ; from tinman
    
    fillmemory_(*bufferS , 4799 , 0)
    
EndProcedure

Procedure String_INPUT_Event(Window, Event, Gadget, Type)
    Debug "#String_INPUT"
EndProcedure

Procedure Button_SEND_Event(Window, Event, Gadget, Type)
    String$ = GetGadgetText(#String_INPUT) ; to enter something to send
    SendNetworkData(ClientID, @String$, Len(String$))
    SetGadgetText(#String_INPUT, "") ; clear the text from memory
    AddGadgetItem(#Listview_TEXT, -1,"YOU: "+String$) ; throw the text in the window
    String$ = ""
    SetActiveGadget(#String_INPUT) ; reset the input string
    ClearMemory(*bufferS,48000)
    
EndProcedure

Procedure Text_SERVADDRESS_Event(Window, Event, Gadget, Type)
    Debug "#Text_SERVADDRESS"
EndProcedure

Procedure Listview_TEXT_Event(Window, Event, Gadget, Type)
    Result = GetGadgetState(#Listview_TEXT)
    msg$ = GetGadgetItemText(#ListView_TEXT, Result)
    MessageRequester("WHATSIT", msg$)
EndProcedure

Procedure Listview_ACTIVITY_Event(Window, Event, Gadget, Type)
    Result = GetGadgetState(#Listview_ACTIVITY)
    msg$ = GetGadgetItemText(#ListView_ACTIVITY, Result)
    MessageRequester("WHATSIT", msg$)
EndProcedure

Procedure RegisterGadgetEvent(Gadget, *Function)
    
    If IsGadget(Gadget)
        AddElement(EventProcedures())
        EventProcedures()\Gadget        = Gadget
        EventProcedures()\EventFunction = *Function
    EndIf
    
EndProcedure

Procedure CallEventFunction(Window, Event, Gadget, Type)
    
    ForEach EventProcedures()
        If EventProcedures()\Gadget = Gadget
            CallFunctionFast(EventProcedures()\EventFunction, Window, Event, Gadget, Type)
            LastElement(EventProcedures())
        EndIf
    Next
    
EndProcedure

Procedure Open_Window_0()
    
    If OpenWindow(#Window_0, 99, 332, 510, 380, "Sn4r3 53r\/3R .0999",  #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)
        If CreateGadgetList(WindowID(#Window_0))
            ListViewGadget(#Listview_ACTIVITY, 324, 42, 174, 246)
            SetGadgetFont(#Listview_ACTIVITY, FontID1)
            RegisterGadgetEvent(#Listview_ACTIVITY, @Listview_ACTIVITY_Event())
            ListViewGadget(#Listview_TEXT, 6, 42, 312, 246)
            RegisterGadgetEvent(#Listview_TEXT, @Listview_TEXT_Event())
            
            TextGadget(#Text_SERVADDRESS, 130, 12, 80, 18, "0.0.0.0", #PB_Text_Center) ; 6, 12, 120, 18
            RegisterGadgetEvent(#Text_SERVADDRESS, @Text_SERVADDRESS_Event())
            TextGadget(#Text_1, 20, 12, 120, 18, "SERVER ADDRESS ::") ; 132, 12, 132, 18
            ButtonGadget(#Button_SEND, 6, 336, 312, 36, "SEND")
            RegisterGadgetEvent(#Button_SEND, @Button_SEND_Event())
            StringGadget(#String_INPUT, 6, 294, 312, 42, "")
            RegisterGadgetEvent(#String_INPUT, @String_INPUT_Event())
            
        EndIf
    EndIf
EndProcedure

Open_Window_0()

;**********
InitNetwork()
If ExamineIPAddresses()
    IP.l = NextIPAddress()
EndIf

CreateNetworkServer(#Server, 6654)

AddGadgetItem(#Listview_ACTIVITY,-1,"Server Online") ;  Listening on IP (" + IPString(IP) + ")")
AddGadgetItem(#Listview_ACTIVITY,-1,"IP: (" + IPString(IP) + ")")
SetGadgetText(#Text_SERVADDRESS, ""+IPString(IP))
SetActiveGadget(#String_INPUT) ; reset the input string

Repeat

Event  = WaitWindowEvent(22)
Gadget = EventGadget()
Type   = EventType()
Window = EventWindow()

Select Event
Case #PB_Event_Gadget
CallEventFunction(Window, Event, Gadget, Type)
EndSelect

If NetworkServerEvent() = 1
    AddGadgetItem(#Listview_ACTIVITY,-1,"A new connection")
    ClientID.l = EventClient()
    IP = GetClientIP(ClientID)
    Cl$ = Str(IP)
    AddGadgetItem(#Listview_ACTIVITY,-1,"CLIENT: "+Cl$)
EndIf
If NetworkServerEvent() = 2
    ClearMemory(*bufferS,48000)
    length.l = ReceiveNetworkData(ClientID, *bufferS, 48000)
    String$ = PeekS(*bufferS, 48000)
    AddGadgetItem(#Listview_TEXT, -1,"INQ: "+String$)
    UpdateList()
    boogie = Len(String$)
    DOIT$ = Right(String$,boogie-6)
    command$ = Left(String$,6)
    
        Select command$
            Case "GETNUM" ; gets next ticket number
                MAX = Val(DOIT$)
                getnumber(MAX,ClientID)
                UpdateList()
                ClearMemory(*bufferS,48000)
            Case "TXTSET"
                SwitchText(DOIT$, ClientID)
        EndSelect

EndIf

Until Event = #PB_Event_CloseWindow

Zork:

End

I have a problem... My POS program has become popular in several Asian countries... they use UNICODE to enter Menu Items...

Posted: Wed Aug 27, 2008 9:04 pm
by Derek
My guess is that the use of peeks() on a buffer of unicode characters is failing real quick due to the null's.

Run this, with and without unicode enabled, to see what I mean.

Code: Select all

a$="test"
l=Len(a$)*SizeOf(character)
*m=AllocateMemory(l+2)
PokeS(*m,a$)
For n=0 To l-1
Debug PeekB(*m+n)
next

Posted: Wed Aug 27, 2008 9:09 pm
by srod
I think that's a good guess. Rook, SendNetworkString() does not send a terminating null - could this be your problem in that, in unicode, things are locking up whilst a double null is searched for etc?

Posted: Wed Aug 27, 2008 9:14 pm
by Rook Zimbabwe
I see what you mean... one gives me 4 numbers... and WITH unicode I get four numbers and 4 0's alternating...

SO Unicode sends a terminating 0?

But would that NOT still send something to the CLIENT? I mean it shows NOthing recived... even stuff it doesn't understand!

How can I work around this?

Do I have to add a #NULL to the end of the string sent to the CLIENT?

Posted: Wed Aug 27, 2008 9:22 pm
by Derek
I think you are going to have to work towards having both the client and server compiled using unicode for starters.

I think you'll need to work around using peeks().

Posted: Wed Aug 27, 2008 9:28 pm
by Rook Zimbabwe
Unicode :P Me now HATE unicode!
I think you'll need to work around using peeks()


{sigh} Yep I agree with that... I am probably gonna have to get the size of the buffer and then SCAN the whole size from 0 to ... and parse out what is there...

HEY it works with the SERVER as ASCII and the Client as UNi IF you change line 151 to:

Code: Select all

 Str$ = PeekS(*buffer,4800, #PB_Ascii) 

Posted: Wed Aug 27, 2008 9:35 pm
by srod
Yes, either send the number of characters before the string so that the receiving server can then use PeekS() with the 'length' parameter set accordingly to read the string, or, place the string into a buffer, add the 2 trailing nulls (PokeS() will do this automatically) and then use SendNetworkData.

Posted: Wed Aug 27, 2008 9:35 pm
by Derek
Rook Zimbabwe wrote:Unicode :P Me now HATE unicode!
You're not alone there, I never use unicode!

Posted: Wed Aug 27, 2008 9:37 pm
by srod
I never use ascii myself; unicode all the way! :wink:

Posted: Wed Aug 27, 2008 9:52 pm
by Rook Zimbabwe
Well if I use the #PB_Ascii in my program (the unicode version...) I get INVALID MEMORY ACCESS...

but it does work in the Client/Server? Oh heck... I have been beating my brain against this all day... I quit.

Time for ST:Voyager and then to cook dinner! :D

If anyone has any ideas, please let me know!

Posted: Wed Aug 27, 2008 9:58 pm
by Derek
Rook Zimbabwe wrote:Time for ST:Voyager and then to cook dinner! :D

If anyone has any ideas, please let me know!
Well, seeing as you're a Texan I'd suggest a steak with chips, maybe some peas and definately gravy! :lol: :lol: :lol:

Posted: Thu Aug 28, 2008 2:40 am
by Rook Zimbabwe
OK first things first...

A: You know what I meant! :P

B: No one in Texas over the age of 12 can be forced to eat peas... It is state law!

C: (back on topic) How come when I check unicode flag for both and run I see Asian character recieved by the server?

Posted: Thu Aug 28, 2008 4:24 am
by pdwyer
if you are reading ascii as unicode then the doublebyte values will be high, up into the CJK range so you would see asian chars.

can't say more just yet as I'm not at home with my compiler.

Posted: Thu Aug 28, 2008 9:03 pm
by Trond
Here is how to send and recieve an arbitrary-length string in unicode mode:

Code: Select all

; Server

Procedure.s ReceiveNetworkString()
  #BufferSize = 1024
  Protected Buffer = AllocateMemory(#BufferSize)
  Protected Result.s
  Repeat
    Bytes = ReceiveNetworkData(EventClient(), Buffer, #BufferSize)
    If Bytes > 0
      Result + PeekS(Buffer, Bytes)
    EndIf
  Until Bytes <> #BufferSize
  FreeMemory(Buffer)
  ProcedureReturn Result
EndProcedure

InitNetwork()

OpenWindow(0, 100, 100, 100, 100, "Server", #PB_Window_SystemMenu)
CreateGadgetList(WindowID(0))

Connection = CreateNetworkServer(0, 999)

Repeat
  
  Event  = WaitWindowEvent(12)
  Gadget = EventGadget()
  Type   = EventType()
  Window = EventWindow()
  
  N = NetworkServerEvent()
  Select N
    Case #PB_NetworkEvent_Connect
      Debug "SERVER: client connected"
    Case #PB_NetworkEvent_Data
      Debug "SERVER: receive: " + ReceiveNetworkString()
  EndSelect
Until Event = #PB_Event_CloseWindow


Code: Select all

; Client

InitNetwork()
Connection = OpenNetworkConnection("127.0.0.1", 999)

Debug SendNetworkString(Connection, "Any string can go here, #ยค%&/(")

; if I leave this out the string isn't sent correctly for some reason.
Repeat
  NetworkClientEvent(Connection)

ForEver

Posted: Thu Aug 28, 2008 9:27 pm
by srod
Yes, that is better!

However, with your server code Trond, ReceiveNetworkData() returns the number of bytes, whilst PeekS() expects length to be in characters. Must admit that I am not very experienced with Network code so I could be seeing a problem which isn't there! :)