Write a Word with Xojo to PLC S71200

Hi everyone,

I need to pass variables from Xojo to an s71200 PLC using the snap7.dll library.
I state that I have been using this language for a very short time but I still managed to load the library and connect the PLC correctly.
As a first step I’m trying to send the set value of a frequency, which I write in a TextField in the Xojo environment, to the first word of database1 (DB1.DBW0) of the PLC.
Attached I send the code and I’d like to know from those who are much more experienced than me where I’m going wrong.
Thank you

Declare Function WriteArea Lib “C:\Users\gianc\Desktop\Progetti_2023\Xojo\Test_SCADA\snap7\snap7.dll” Alias “Cli_WriteArea” (Client As Integer,Area as Integer, DBNumber As Integer, Start As Integer, Amount As Integer,WordLen as Integer, pUsrData As Ptr) As Integer
Declare Function Create Lib “C:\Users\gianc\Desktop\Progetti_2023\Xojo\Test_SCADA\snap7\snap7.dll” Alias “Cli_Create” () As Integer

// Create an instance of the Snap7 client
Dim Client As Integer
Client = Create()

Dim value As Integer
// Check that the value is valid
If value >= 0 And value <= 65535 Then

// Convert the value to a pointer (MemoryBlock)
Dim pUsrData As New MemoryBlock(2) // Assuming the size of the Integer is 2 bytes

// Write the value to the MemoryBlock
pUsrData.Int16Value(0) = value

// Specifies the parameters of the WriteArea function
Dim Area As Integer = &h84 // S7AreaDB
Dim DBNumber As Integer = 1
Dim Start As Integer = 0
Dim Amount As Integer = 1 // It means quantity of words, not byte size
Dim WordLen As Integer = &h04 // S7WLWord

If WriteArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData) = 0 Then
// Successful writing
MsgBox “Writing successful! The value " + Str(value) + " was successfully written to the PLC.”
// Writing failed
MsgBox “Error writing to PLC.”
End If

MsgBox “Invalid value. Make sure it is between 0 and 65535.”
End If

The DLL declare says that “pUsrData” should be a Ptr. Since you’re passing in a 2-byte MemoryBlock, this is theoretically being converted to a Ptr for you, however, Xojo’s implicit data conversion sometimes fails. My thoughts:

  • You may want to try explicitly passing the Ptr [e.g. pUsrData.Ptr(0) ]
  • You may want to verify if the PLC is 16-bit or 32-bit
    • Since your Ptr only contains 16-bits of data, it is a 16-bit memory address.
    • If the PLC is using 16-bit memory addressing, then you can ignore this idea.

I also use snap7. However, use an additional wrapper.

It is important that the Cli_ConnectTo command is also used.
Here you specify which IP address, slot and rack should be used.

I write Read/Write MemoryBlock to the PLC.
In addition, the following must be observed in the PLC project:

For me it looks like this:

Declare function xojo_Cli_Create lib  "snap7Wrapper.dll" () as integer
Declare function xojo_Cli_ConnectTo lib  "snap7Wrapper.dll" (clientID as integer,ip as wstring,rack as integer,slot as integer) as integer
Declare function xojo_Cli_Disconnect lib  "snap7Wrapper.dll" (clientID as integer) as integer
Declare function xojo_Cli_DBRead lib  "snap7Wrapper.dll" (clientID as integer,DB as integer,Start as integer,Ende as integer,mb as ptr) as integer
Declare function xojo_Cli_DBWrite lib  "snap7Wrapper.dll" (clientID as integer,DB as integer,Start as integer,Ende as integer,mb as ptr) as integer

var error as integer

var myClient as integer = xojo_Cli_Create() 

error = xojo_Cli_ConnectTo(myCLient,"",0,1)
system.DebugLog error.totext

Var BigBlock as MemoryBlock  = new MemoryBlock(256)
error = xojo_Cli_DBRead(myCLient,3,0,110,BigBlock)

for i as integer = 0 to 24-1
  system.debuglog "Anlage: " + i.totext + "  :"+TranslateDouble(BigBlock,0+(i*4)).totext

for i as integer = 0 to 110
  var b as byte = BigBlock.byte(i)
  'system.DebugLog "index: " + i.totext +"  "+ b.totext
  'Label1(i).text = TranslateDouble(BigBlock,0+(i*4)).totext

error = xojo_Cli_Disconnect(myClient)
system.DebugLog error.totext

If required, I can provide you with the wrapper DLL. I use this because I had problems passing the memory block in Xojo. If you find a solution, it would be nice if you would share it.

Greetings Norbert

Hi Norbert,
I downloaded and inserted snap7Wrapper.dll I did a test with the part of the code that you kindly wrote, obviously adapting it to my system specifications, but I got an error while compiling like:

Window1.TextField8.TextChange, line 19
This article does not exist
system.debuglog “Anlage: " + i.totext + " :”+TranslateDouble(BigBlock,0+(i*4)).totext

How can I fix it? Also, what event should I bind this code to? Is a TextChange of a read-only TextField correct?

Hi Edward,
I tried to modify the code as you recommended, the application starts, but when it comes to inserting the value in the TextField, it tells me that there was a problem loading the value with error code 262144.
snap7 codeError 262144 is Bad Datasize passed to send/recv

I apologize that I don’t have a definitive answer, but the error you reported does support my suspicions. In short, I think one of the problems you’re encountering is the data type of the pointer. You are using a 2-byte MemoryBlock, and Xojo docs say that the internal Ptr is either 4-bytes (for 32-bit systems) or 8-bytes (for 64-bit systems). That’s why your 2-byte pointer variable seemed to me to be a problem.

@Norbert_Kollmetz solution is using a 256-byte MemoryBlock for the pointer. I am assuming that their solution is working on their system because of Xojo’s implicit type conversion into an actual pointer.

But again, my point is to simply get you looking at and thinking about the details of the data types and type conversion. Hopefully that will help you get it sorted out. :grinning:

Hi donato,

the right wrapper dll can’t do that because I wrote it myself.

Here is the link to download the 64-bit dll.

Here is the code for the TranslateDouble function.

Public Function TranslateDouble(m as MemoryBlock, offset as integer) As Single
  var wert as MemoryBlock = new MemoryBlock(4)
  var s as single =  wert.SingleValue(0)
  return s
End Function

Here is another example as a project for download.

Hello Edward,

when i try directly in xojo without wrapper dll i get no values back. this is how the code looks like.

Declare function Cli_Create lib  "snap7.dll" () as integer
Declare function Cli_ConnectTo lib  "snap7.dll" (clientID as integer,ip as wstring,rack as integer,slot as integer) as integer
Declare function Cli_Disconnect lib  "snap7.dll" (clientID as integer) as integer
Declare function Cli_DBRead lib  "snap7.dll" (clientID as integer,DB as integer,Start as integer,Ende as integer, mb as ptr) as integer
Declare function Cli_DBWrite lib  "snap7.dll" (clientID as integer,DB as integer,Start as integer,Ende as integer,mb as ptr) as integer

var error as integer

var myClient as integer = cli_Create() 
error = Cli_ConnectTo(myClient,"",0,1)

var mb2 as MemoryBlock = new MemoryBlock(256)

var p as ptr = mb2

error = Cli_DBRead(myClient,3,0,48,p)

for i as integer = 0 to 16-1
  system.DebugLog mb2.Byte(i).totext

system.DebugLog error.totext

error = Cli_Disconnect(myClient)

here is the code from the wrapper that gives me the correct values to xojo. would love to ditch the wrapper and do it all through xojo.

  ProcedureDLL.i xojo_Cli_DBRead(clientID.i,DB.i,Start.i,Ende.i,*Array_ptr) 
        Structure MemoryArray

        Define *Array.MemoryArray = *Array_ptr
        ProcedureReturn Cli_DBRead(clientID, DB, Start, Ende, *Array)

I hope this helps to track down the problem.