String with Embedded Nulls?

Just starting out? Need help? Post your questions and find answers here.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ebs.

Does anyone know how I can use a string that has embedded nulls (zeros)? I have to create a string for a Windows API call that has some zeros in it, but PureBasic "stops" at the very first zero. It doesn't pass the entire string, just up to the first zero, and the API call fails. I have tested the API call in Visual Basic, which doesn't use null-terminated strings, and it works correctly. Is there some way to do this in PureBasic?

Thank you,
Eric Schuyler
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

I don't know the answer to your specific null-related question, but if you tell
me what the API is that you're trying to use, I may be able to show you a way to
do it...


PB - Registered PureBasic Coder
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by freak.

Instead of strings, you can also use an Array of bytes for the API calls.

Dim text.b(10)

Now fill up the bytes with the Ascii-values of your string. You can get them with the Asc() function. Fill in the zeros where needed.

Now call your API call with @text() instead of the string variable.

That's it, hope it helps...

Timo

--

A debugged program is one for which you have not yet found the conditions that make it fail.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ebs.

PB,

I'm trying to set up an ODBC data source with the API function SQLConfigDataSource() in odbccp32.dll. Here's the Visual Basic declaration:

Private Declare Function SQLConfigDataSource Lib "odbccp32.dll" (ByVal hwndParent As Long, ByVal fRequest As Integer, ByVal lpszDriver As String, ByVal lpszAttributes As String) As Long

The last parameter (lpszAttributes) is built like this in Visual Basic:

Attributes = "DSN=" & DSNName & vbNullChar & "Description=" & Description _
& vbNullChar & "DBQ=" & Databasename & vbNullChar & vbNullChar

(vbNullChar is a byte with a value of 0)

When I do something similar in PureBasic, the string it passes ends at the first null character (after the DSNName). Do you have any suggestions?

Thanks,
Eric


I don't know the answer to your specific null-related question, but if you tell
me what the API is that you're trying to use, I may be able to show you a way to
do it...


PB - Registered PureBasic Coder
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

> I'm trying to set up an ODBC data source with the API function SQLConfigDataSource() in odbccp32.dll

I'm not familiar with that DLL... but read on...

> Attributes = "DSN=" & DSNName & vbNullChar & "Description=" & Description _
> & vbNullChar & "DBQ=" & Databasename & vbNullChar & vbNullChar

I think you can replace vbNullChar with an empty string (""), so try replacing
vbNullString with "" in your Visual Basic source to check if the API call still
works, and if it does, then try this in your PureBasic source:

Attributes = "DSN=" + DSNName + "" + "Description=" + Description + "" + "DBQ=" + Databasename + "" + ""

If this doesn't work, then I'm not sure how to proceed just yet... sorry.

PB - Registered PureBasic Coder
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ebs.

PB,

Unfortunately, that doesn't work. The API call requires one byte of 0 separating each part of the string - that's what vbNullChar is. Thanks for the suggestion, though!

Freak,

I've tried using the byte array as you suggest, but that doesn't seem to work at all. Using the string method, I can see that the first part of the string was applied correctly - I get an ODBC datasource called "TestDSN". With a byte array, nothing happens, so I guess I must not be passing the address of the array correctly. I've tried using "@Bytes", "@Bytes()", and "@Bytes(0)" with similar results. Anything else you can suggest?

Thanks to both,
Eric

> I'm trying to set up an ODBC data source with the API function SQLConfigDataSource() in odbccp32.dll

I'm not familiar with that DLL... but read on...

> Attributes = "DSN=" & DSNName & vbNullChar & "Description=" & Description _
> & vbNullChar & "DBQ=" & Databasename & vbNullChar & vbNullChar

I think you can replace vbNullChar with an empty string (""), so try replacing
vbNullString with "" in your Visual Basic source to check if the API call still
works, and if it does, then try this in your PureBasic source:

Attributes = "DSN=" + DSNName + "" + "Description=" + Description + "" + "DBQ=" + Databasename + "" + ""

If this doesn't work, then I'm not sure how to proceed just yet... sorry.

PB - Registered PureBasic Coder
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

> Unfortunately, that doesn't work. The API call requires one byte of 0
> separating each part of the string - that's what vbNullChar is.

Oops, I just realised you said vbNullChar, not vbNullString -- no wonder I got
it wrong! Hmm, that definitely makes it harder to solve then... perhaps you
could show us your code so we can try experimenting ourselves?

Or Fred, if you're reading, perhaps an option to allow API calls to go beyond
a 0-byte and to the end of the string instead?

PB - Registered PureBasic Coder
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by freak.

It doesn't seem to work with Arrays directly. What I've been using with API successfully was Arrays inside Structures, so this could work (just an example):

Code: Select all

; ***********
  
Structure stringarray     ; define Structure
  bytes.b[10]
EndStructure
  
text.stringarray          ; create Structure
  
text\bytes[0] = 65        ; fill in the Charakters
text\bytes[1] = 66
.
.
.
text\bytes[10] = 0
  
SomeApiCommand_( @text\bytes[0] ) ; call some API command
  
; *****************
Got the point?

Hope that helps...

Timo

--

A debugged program is one for which you have not yet found the conditions that make it fail.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ebs.

Timo,

I tried your structure suggestion - still no joy!
Thanks for all your help so far.

BTW - I noticed an inconsistency with the array syntax:

When I use just a "plain" byte array, I used parentheses "(" and ")" around the array element, like this: Bytes(0) = 65. When I tried your structure suggestion like this: Text\Bytes(0) = 65, I get a syntax error. Changing the parentheses to brackets "[" and "]" makes it compile correctly.

Fred - is this by design, or is it a bug? Also, can you help me with my original problem, PLEASE????

Thanks again,
Eric


It doesn't seem to work with Arrays directly. What I've been using with API successfully was Arrays inside Structures, so this could work (just an example):

Code: Select all

; ***********
  
Structure stringarray     ; define Structure
  bytes.b[10]
EndStructure
  
text.stringarray          ; create Structure
  
text\bytes[0] = 65        ; fill in the Charakters
text\bytes[1] = 66
.
.
.
text\bytes[10] = 0
  
SomeApiCommand_( @text\bytes[0] ) ; call some API command
  
; *****************
Got the point?

Hope that helps...

Timo

--

A debugged program is one for which you have not yet found the conditions that make it fail.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Danilo.

>Attributes = "DSN=" & DSNName & vbNullChar & "Description=" & Description _
>& vbNullChar & "DBQ=" & Databasename & vbNullChar & vbNullChar

You can do this with memory commands or with
a string with many spaces.

One way with memory:

Code: Select all

mem = AllocateMemory(1,5000,0)         ; 5000 bytes should be enough (well, 1000 should be Ok!)
  PokeS(mem  , "DSN=")                 ; 4 bytes
   x = 4
  PokeS(mem+x, DSNName$)               ; variable length and vbNullChar is included at the end
   x + Len(DSNName$)+1                 ; +1 = the NullChar that is needed here
  PokeS(mem+x, "Description=")         ; 12 bytes
   x + 12
  PokeS(mem+x, Description$)           ; variable length and vbNullChar is included at the end
   x + Len(Description$)+1             ; +1 = the NullChar that is needed here
  PokeS(mem+x, "DBQ=")                 ; 4 bytes
   x + 4
  PokeS(mem+x, Databasename$)          ; 1 Nullchar is included at the end
  PokeB(mem+x+Len(Databasename$)+1,0)  ; the second NullChar at the end
                                       ; because this special "string" ends
                                       ; with double-NULL


return = SQLConfigDataSource_(hwndParent, fRequest, lpszDriver$, mem)
         ; call the API (call it with CallFunction() if you opened
                         the DLL yourself)
Hope you get the idea...

The other way would be without allocating memory
and use A$ = space(1000) or so, and follow the
same things i´ve shown above.
Instead of variable "mem" you could use "@A$" with
this method.
Anyway... The AllocateMemory way is fine and shows
exactly whats goin on.

cya,
...Danilo

(registered PureBasic user)


Edited by - Danilo on 19 June 2002 06:27:19
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ebs.

Danilo,

Yes - THANK YOU! I put your "poke memory" code into procedures called PutString() and PutStringZero(), and it works!

That's a lot of work to get a string with embedded nulls. I hope Fred considers incorporating something into PureBasic.

Thanks again,
Eric
>Attributes = "DSN=" & DSNName & vbNullChar & "Description=" & Description _
>& vbNullChar & "DBQ=" & Databasename & vbNullChar & vbNullChar

You can do this with memory commands or with
a string with many spaces.

One way with memory:

Code: Select all

mem = AllocateMemory(1,5000,0)         ; 5000 bytes should be enough (well, 1000 should be Ok!)
  PokeS(mem  , "DSN=")                 ; 4 bytes
   x = 4
  PokeS(mem+x, DSNName$)               ; variable length and vbNullChar is included at the end
   x + Len(DSNName$)+1                 ; +1 = the NullChar that is needed here
  PokeS(mem+x, "Description=")         ; 12 bytes
   x + 12
  PokeS(mem+x, Description$)           ; variable length and vbNullChar is included at the end
   x + Len(Description$)+1             ; +1 = the NullChar that is needed here
  PokeS(mem+x, "DBQ=")                 ; 4 bytes
   x + 4
  PokeS(mem+x, Databasename$)          ; 1 Nullchar is included at the end
  PokeB(mem+x+Len(Databasename$)+1,0)  ; the second NullChar at the end
                                       ; because this special "string" ends
                                       ; with double-NULL


return = SQLConfigDataSource_(hwndParent, fRequest, lpszDriver$, mem)
         ; call the API (call it with CallFunction() if you opened
                         the DLL yourself)
Hope you get the idea...

The other way would be without allocating memory
and use A$ = space(1000) or so, and follow the
same things i´ve shown above.
Instead of variable "mem" you could use "@A$" with
this method.
Anyway... The AllocateMemory way is fine and shows
exactly whats goin on.

cya,
...Danilo

(registered PureBasic user)


Edited by - Danilo on 19 June 2002 06:27:19
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Danilo.

Nice to hear, ebs.
Thanks for the feedback...

cya,
...Danilo

(registered PureBasic user)
Post Reply