I am using SHFileOperation to copy some files, on single files all works ok you pass a pointer to the string containing the file and full path.
To copy more than one file in one call to the function you delimit each filepath in the string with a NULL character but I get an error cannot read source fiile
example String: Source="C:\\Test1.txt"+chr$(0)+chr$(0) Works Ok
example multi-file String: Source="C:\\Test1.txt"+chr$(0)+"C:\\Test2.txt"+chr$(0)+chr$(0) error cannot read source fiile
Is this the right way to insert a Null into a string.
Try with inline nulls :
c:\\file1.ext\x00c:\\file2.txt\x00c:\\file3.ext\x00
The last \x00 is required to ensure that the string is terminated with two nulls; second null is automatically added by the compiler.
In your example, chr$(0) works like empty string, so the second string is appended to the first one, and the result is "C:\\Test1.txtC:\\Test2.txt"
Does not give any error but only copies first file in list
' // Shell File Operations
' const for wFunc
CONST FO_MOVE = 0x1
CONST FO_COPY = 0x2
CONST FO_DELETE = 0x3
CONST FO_RENAME = 0x4
' constants for fFlags
CONST FOF_MULTIDESTFILES = 0x1
CONST FOF_CONFIRMMOUSE = 0x2
CONST FOF_SILENT = 0x4 :rem don't create progress/report
CONST FOF_RENAMEONCOLLISION = 0x8
CONST FOF_NOCONFIRMATION = 0x10 :rem Don't prompt the user.
CONST FOF_WANTMAPPINGHANDLE = 0x20 :rem Fill in SHFILEOPSTRUCT.hNameMappings Must be freed using SHFreeNameMappings
CONST FOF_ALLOWUNDO = 0x40 :rem Uses Recycle bin for deletion if set
CONST FOF_FILESONLY = 0x80 :rem on *.*, do only files
CONST FOF_SIMPLEPROGRESS = 0x100 :rem means don't show names of files
CONST FOF_NOCONFIRMMKDIR = 0x200 :rem don't confirm making any needed dirs
TYPE SHFILEOPSTRUCT
DEF hwnd AS INT
DEF wFunc AS INT
DEF pFrom AS pointer
DEF pTo AS pointer
DEF fFlags AS WORD
DEF fAnyOperationsAborted AS INT
DEF hNameMappings AS INT
DEF lpszProgressTitle AS POINTER :' only used if FOF_SIMPLEPROGRESS
ENDTYPE
DECLARE IMPORT, _SHFileOperation ALIAS SHFileOperationA(lpFileOp AS SHFILEOPSTRUCT),INT
' pointers for source and destination
def s,d:pointer
' strings for source and destination
def source,destination as string
' Source string use path to your sources here
source="C:\\test.mpg\x00C:\\test2.mpg\x00c:\\test.avi\x00"
' Destination string use path to your destination here
destination="d:\\\x00"
' Pointer to Source string
s=source
' Pointer to Destination string
d=destination
' define our structure
def SHFileOp:SHFILEOPSTRUCT
' Fill in our structure for copy function
SHFileOp.wFunc=FO_COPY :'copyfile
SHFileOp.pFrom=s :' pointer for source
SHFileOp.pTo=d :' pointer for destination
' call function
_SHFileOperation(SHFileOp)
'delete pointers
delete s
delete d
end
Some bad stuff in there ;)
You shouldn't be deleting the pointers. Just because they are pointers doesn't qualify them for a DELETE operation. It is only when you are using NEW. You don't need those pointers anyway.
Strings in Emergence are NULL terminated so trying to copy the string will only copy up to the first NULL. So you have a few choices. The easiest method is just a substition of another character, and a loop before the function is called.
STRING src,dst
src = "C:\\Test1.txt|C:\\Test2.txt|"
dst = "D:\\|"
for i = 0 to len(src)
if src[i] = '|' THEN src[i] = 0
next i
for i = 0 to len(dst)
if dst[i] = '|' THEN dst[i] = 0
next i
' define our structure
def SHFileOp:SHFILEOPSTRUCT
' Fill in our structure for copy function
SHFileOp.wFunc=FO_COPY :'copyfile
SHFileOp.pFrom=src :' pointer for source
SHFileOp.pTo=dest :' pointer for destination
...
Since the strings are already NULL terminated only one | is needed at the end, which gives you two terminating nulls after the loop.
Paul.
Used your code paul and just get error cannot copy file: Cannot read from source file or disk
Do you have a test1.txt and test2.txt file in the root directory?
Just typed the code out of my head, so it may need tweaking. Can't test it at the moment as I am working in Linux. But have used the same technique many times before. FILEREQUEST uses it for substituing the | character in the extensions string.
Paul.
Try it this way ;)
src = "C:\\Test1.txt|C:\\Test2.txt|"
dst = "D:\\|"
ln = len(src)
for i = 0 to ln
if src[i] = '|' THEN src[i] = 0
next i
ln = len(dst)
for i = 0 to ln
if dst[i] = '|' THEN dst[i] = 0
next i
The substitution works ok because if I print the string it just prints the first filename upto the null
Yes, however, that would have been the case in my first snippet as well. The second snippet gets the length of the string before the loop since substituting the | for a NULL will change the value returned bye LEN.
Which is why I posted again ;)
Thank you Paul second version works a treat thank you very much ::)
I wasn't aware you could use single quotes in EB, it does work?
No, but again it was off the top of my head and he understood ;)
Hmm... But if I really want to set a string into NULL, how can I do it? In my program I tried the chr$(0) and worked as intended, but as I learn after reading this post, it is not a true null.
I can't speak specifically about EBasic but my guess is that this applies: traditionally the problem with 0 terminated strings is that they can't contain binary 0s. Some languages offer other counted strings; strings that begin with a length count, as an alternative since they can contain 0s but they have the drawback of limited length and that in a lot of cases dealing with them is slower. Some languages offer both types of strings.
But in general the answer to how to include a true 0 in a 0 terminated string is that you can't, by definition. The string consists of those characters preceding the 0.
Traditional Basics used counted strings or fixed length strigs. Ebasic doesn't, I guess, partly because it's written in C, which uses 0 terminated strings, and partly because it's efficent and probably mostly because that's what Paul chose to do. It's probably faster this way for most things and it's rarely a problem once you get used to it.
When I've had to deal with something that could contain a 0 in C in the past I've (usually) used some untyped memory and a pointer to it instead of making it a string. I haven't done anything in Ebasic that's required that so I'm not sure how I'd deal with it in Ebasic.
Barry
It's not too hard. Remember a string can be accessed as a character array
str = "put a null here >|< passed the null"
pos = instr(str, "|")
str[pos-1] = NULL
Generally I just use a pointer to a string, and derference it as a character, replacing | with nulls before sending it to archaic windows API functions that don't know how to handle string arrays ;)
string temp
pointer p
str = "file1.txt|file2.txt|file3.txt||"
temp = str
p = temp
while #<char>p <> 0
if #<char>p = ASC("|") then #<char>p = 0
p++
endwhile
SomeAPIFunction(temp)
As long as you immediately pass the string to the API function that expects embedded nulls then you are fine, if you try to copy the resulting string to another string it will only copy up to the first embedded NULL. I used the temp string just because it could be a reusable section of code.
Paul
Thanks for the information. Was more easy if string=NULL could be understud by EB :P