A little help calling Windows APIs
BlitzMax Forums/BlitzMax Programming/A little help calling Windows APIs
| ||
I have this API call to copy a file, and it works fine.Extern "win32" Function CopyFileExW:Int(SrcFile$W, DestFile$W, CallBack:Byte Ptr, Data:Int Ptr, Cancel:Int Ptr, Flags:Int) Function GetLastError:Int() End Extern Local ret:Int = CopyFileExW(src, dst, Null, Null, Null, 0) If Not ret ret = GetLastError() DebugLog ret End If This works. And here is a link to the CopyFileExW function: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363852(v=vs.85).aspx If you look in the function, there is a CallBack you can make, that will give your progress as it run. I am having a hard time figuring out how to implement that. Here is what I tried: Extern "win32" Function CopyFileExW:Int(SrcFile$W, DestFile$W, CallBack:Byte Ptr, Data:Int Ptr, Cancel:Int Ptr, Flags:Int) Function GetLastError:Int() End Extern Function CopyProgress:Int (TotalSize:Long Ptr, TotalTransferred:Long Ptr, StreamSize:Long Ptr, StreamTransferred:Long Ptr, StreamNumber:Int Ptr, CallbackReason:Int Ptr, hSourceFile:Int Ptr, hDestFile:Int Ptr, Data:Int Ptr) DebugLog Int(StreamNumber) Return 0 End Function Local ret:Int = CopyFileExW(src, dst, CopyProgress, Null, Null, 0) If Not ret ret = GetLastError() DebugLog ret End If This causes an access violation error. It is partially working though, as it seems to work until it reaches the last block of the copy stream. If it takes 5 copy blocks, it will perform the first 4 then crash after the 5th one. Also, if I return a 1 which is a copy cancel, then it will cancel and go on to the next file and not give the error either. So I am not 100% sure what I am doing wrong. Here you can find the definition of the callback: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363854(v=vs.85).aspx Any help would be appreciated. Thanks. |
| ||
First thing I notice is that you need to use the Win32 calling convention for Win32API functions and callbacks, so just stick a little "Win32" at the end of the function callback after the parameters. ie Function CopyProgress([.....])"Win32" |
| ||
Thanks col. I added that, does not seem to have changed a thing. Still does the same thing. It seems the copy goes all the way til the end, then fails to finish because of the callback. I am unsure why. |
| ||
Ok, I'll get the function running here and post back in 10 mins. It may because of using the *W and not *A version of the function..... |
| ||
Extern"Win32" Function CopyFileExA(lpExistingFileName$z,lpNewFileName$z,lpProgressRoutine:Byte Ptr,lpData:Byte Ptr,lpCancel:Int,dwCopyFlags:Int) Function GetLastError:Int() EndExtern Function CopyProgress(TotalFileSize:Long,TotalBytesTransferred:Long,SizeStream:Long,StreamBytesTransferred:Long,dwStreamNumber:Int,dwCallbackReason:Int,hSourceFile:Int,hDestinationFile:Int,lpData:Byte Ptr)"Win32" Return 0 EndFunction 'Test Local ThisFile$ = AppFile.Replace(".debug","").Replace(".exe",".bmx") Local Destfile$ = StripExt(ThisFile)+"_copy"+".bmx" ' Rename this source file to *_copy.bmx If CopyFileExA(ThisFile,DestFile,CopyProgress,Null,False,0) = 0 DebugLog "Failed with error code: " + GetLastError() EndIf This works ok. When run it copies itself ( the source file ) to the same directory with _copy appended to the filename before the file extension. |
| ||
Excellent, works great. Thanks col. So, did having all of the pointers in my callback screw it up? What is the difference between the CopyFileExA and the CopyFileExW functions? |
| ||
*A is the Ansi version, ie 1 byte per character, *W is for the unicode version which is 2 bytes. You just need to make sure that the parameters match up correctly specifically for strings. I tend to use *A as *W gives me problems that I've not investigated into being as *A works without problems. So, did having all of the pointers in my callback screw it up? I would think so. But not because they were pointers being used as pointers - its not as though youre accessing them in the callback which is when EAVs would have occured ( referencing memory ranges out of range ie address $00000000 ). But because a * Ptr is a 32bit value and a Long is a 64 bit value. A longer explanation... Parameters are passed via the stack. When a 64 bit value is pushed to the stack then the stack pointer will move back the equivalent of a 64 bit value ie 2x32 values. Because youre using a *Ptr in the function parameters and "Win32" functions rearrange the stack before they return then this will cause the stack to be misaligned, which will in turn return control to the wrong address after the function has exited. And more specifically... The CopyFileEx* function will push the equivalent of 13 integers onto the stack just before calling the BMax callback function which will be made up of.. 4 x Long values ( equivalent of 8 x 32bit integers in memory size ) 4 x Int ( 4 x 32bit integers ) 1 x *ptr ( 1 x 32bit integer ) so the CALLED function ( because ALL windows functions use and expect other functions that it calls to use the _stdcall calling convention ) should itself pop the equivalent back off the stack before returning ( or as it returns ). In this case the called function is the BMax function. Because initially your function was using all *ptr(s) in the parameters which are 1 x 32bit integers each, when the function exits the equivalent of 9 x 32bit integers are popped off but it should pop the equivalent of 13 integers, hence you get a stack misalignment and a crash. I'm not sure if you understand any if that. I find it difficult explaining things so they are easily understood :-) |
| ||
Makes perfect sense. Thanks again for the help. |