April 28, 2024, 10:44:27 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Strings vs IStrings

Started by tbohon, June 20, 2007, 10:38:29 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

tbohon

Am using ISTRINGs for the first time and keep getting an error.  It was working just fine when I defined the variables as STRINGs but the strings I'm using are well beyond the 255 byte length.

I declare three working variables and make them global:
DEF wvar1, wvar2, wvar3:istring

GLOBAL wvar1
                GLOBAL wvar2
                GLOBAL wvar3


Next, I clear them to blank (which may be the issue?):

wvar1 = ""
                wvar2 = ""
                wvar3 = ""


Next, I copy a RT control's contents into one of the variables:

rv = CONTROLCMD w,8,@RTSAVE,wvar1,0


after which I start parsing the string, copying pieces of wvar1 to wvar2. 

I never get to the #DEBUGPRINT statements right before the parsing section of the code.  Instead, I get the following error in the DEBUG window:

Starting debug session...
Loading DLL: ntdll.dll
Loading DLL: C:\WINDOWS\system32\kernel32.dll
Loading DLL: C:\WINDOWS\system32\USER32.DLL
Loading DLL: C:\WINDOWS\system32\GDI32.dll
Loading DLL: C:\WINDOWS\system32\COMDLG32.DLL
Loading DLL: C:\WINDOWS\system32\SHLWAPI.dll
Loading DLL: C:\WINDOWS\system32\ADVAPI32.dll
Loading DLL: C:\WINDOWS\system32\RPCRT4.dll
Loading DLL: C:\WINDOWS\system32\msvcrt.dll
Loading DLL: C:\WINDOWS\system32\COMCTL32.dll
Loading DLL: C:\WINDOWS\system32\SHELL32.dll
Loading DLL: C:\WINDOWS\system32\OLE32.DLL
Loading DLL: C:\WINDOWS\system32\CRTDLL.DLL
Loading DLL: C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b641W
Loading DLL: C:\WINDOWS\system32\uxtheme.dll
Loading DLL: C:\WINDOWS\system32\riched32.dll
Loading DLL: C:\WINDOWS\system32\RICHED20.dll
First chance exception: Address 0x7C910466 Access Violation.
Final chance exception: Address 0x7C910466 Access Violation.
First chance exception: Address 0x7C910466 Access Violation.
The program 'C:\EBasicWork\parserv3.exe' exited with code: 1


Comments/thoughts/pointers appreciated - I've read the help files and can't see what I'm doing wrong.

Tnx in advance.

Tom
"If you lead your life the right way, the karma will take care of itself ... the dreams will come to you."  -- Randy Pausch, PhD (1961-2008)

sapero

June 20, 2007, 11:01:00 AM #1 Last Edit: June 20, 2007, 11:23:35 AM by sapero
All your strings are ONE byte in size, that is, a ISTRING is an alias to CHAR (also one byte of memory), but with build-in 'string' functionality.
Check this out:
DEF wvar1, wvar2, wvar3:istring
print &wvar1 - &wvar2 /*subtract addresses of two variables*/
print &wvar2 - &wvar3

The above code is equal to
istring wvar1
and (from alias perspective) this is equal to
char wvar1
where wvar1 allocates only one byte of memory. Now, you need array of bytes for your strings, which can be done using [] operator
char wvar1[256] /*256 byte memory space*/
After replacing 'char' with 'istring' you are able to use this variable as standard string.

In your code you got an Access Violation exception.
Why? @RTSAVE command has overwriten all your local variables, the return address where current function should return,
and the (first pushed) pointer to 'rv' variable, where the @RTSAVE command should store the result. This was the real buffer overflow :)

If you use ISTRING's, always define the dimension:DEF wvar1[1024], wvar2[32], wvar3[2048]:istring

Using @RTSAVE to store text in a string is very unsafe, your unable to crop the text to destination buffer length.
Option 1:
POINTER lpStr : settype lpStr, string
lpStr = GetControlText(w, 8)
' do something: print *lpStr
FreeHeap(lpStr) /* free the string from memory */

Option 2:
const WM_GETTEXTLENGTH = 0xe
int required
required = SendMessage(w, WM_GETTEXTLENGTH, 0, 0, 8/*control id*/) + 1
POINTER lpStr
lpStr = new(char, required)
settype lpStr, string
CONTROLCMD w,8, @RTSAVE, *lpStr,0
' do something: print *lpStr
delete lpStr

tbohon

Arrrrrrrrghhhhhhhhhhhhhhhh!   :(  I hate it when I do 'stoopid' things ...  :) 

I'll rewrite the routine - not that much work - and press on.

Thanks, Sapero!!!!!

Tom
"If you lead your life the right way, the karma will take care of itself ... the dreams will come to you."  -- Randy Pausch, PhD (1961-2008)

tbohon

OK, recoded the routine and it works in test.  However, when I use this program 'for real', I'm not going to have any idea how long the input string is going to be ... it's HL7 message traffic from our hospital network and it could be 30-40 characters or several thousand - some of the transcribed documents go on forever and ever.

One thought was to dimension the strings as large as I can (and I'm not sure how large that is ... ???) and then trim it once I've loaded the string.  As it currently stands, I'm pasting the string from the clipboard, cleaning up the Unix line endings by going through it and eliminating all chr(10) and chr(13) ... which means that I'm also removing the end-of-string cr/lf as well so don't know how I'll know when I've reached the end of the string if I dimension it as big as possible.

Another idea I had was to grow the string dynamically ... but that seems to be a bit complicated and probably difficult to implement.

Any suggestions here ... ?
"If you lead your life the right way, the karma will take care of itself ... the dreams will come to you."  -- Randy Pausch, PhD (1961-2008)

LarryMc

My answer will only make sense if I'm understanding your problem correctly:

You have a richedit control that you want to read what it contains; store in a variable; and strip out the CRLF characters.

I have no idea how you are capturing the information that you are wanting to paste in the RE but maybe the following will help you.

By default a RE control will only hold 32767 bytes.  You can increase that by using:
CONTROLCMD  window | dialog, ID, @RTSETLIMITTEXT, length

You can determine how much text is currently in a RE control by using:
length  = CONTROLCMD (window | dialog, ID, @RTGETTEXTLENGTH)


you can create a static istring variable to some max size or, based upon the RTGETTEXTLENGTH command you can
create a ptr to a NEW(char,length+1)

you can then read the contents of the RE into that memory location

then you can created a 2nd ptr to another NEW(char,length+1)

then, in while end while loop you can read each char of the 1st ptrs memory and if it is a keeper then write it to the 2nd ptrs location.

the data in the 2nd ptr location shorter the created length(because you stripped out characters)

Then you can do whatever you need to with the data.

Another way is to write the RE contents to a file instead of a variable; open the file and use the LEN(file) command to create a ptr to a NEW(char,len(file)+1) and read the file a char at a time and keep only those characters you want in the ptr location.

Hope this makes sense and that it helps you.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team

(larry was faster typing than I)

Don't be afraid to use more than one memory buffer to get the job done. Dynamic strings are easy once you get the hang of it.

pointer mystring
mystring = new(char, length+1)
rv = CONTROLCMD w,8,@RTSAVE,#<STRING>mystring,0
...
delete mystring


If you are using a rich edit control and pasting the text into try

1.  Allocate memory large enough to hold the pasted text.  Use @RTGETTEXTLENGTH.  Save the text into that buffer as I did above.
2. use INSTR to find each end of line, keeping track of the position.  INSTR has an optional starting position that you can use to advance through the primary buffer, remember to add 2 to this pos after each iteration to skip the found end of line.
3. Use MID$ to copy the substring to a new allocated buffer using the previous and current postions.
4. repeat until done.

I can code it for you, or you can give it a shot first ;)

Paul.
Ionic Wind Support Team

tbohon

Thanks, guys - and thank you, Paul, for the coding offer.  However, I won't learn a darned thing if I don't muddle through this myself so I'm going to do just that - muddle  ;)

FYI, I have the remainder of the routine working and can pick out the segments - the 255 character length of the string in which I'm storing the RE contents (which come from the clipboard, BTW) is what was slowing me down.  I'm going to work on it a bit more tomorrow (Monday) - I'm a 'ham' (amateur radio operator) and just finished a 30+ hour stint during our annual Field Day and I know better than to make any major decisions or even look at code as tired as I am.

Appreciate it!

Tom
"If you lead your life the right way, the karma will take care of itself ... the dreams will come to you."  -- Randy Pausch, PhD (1961-2008)