@@ -226,7 +226,12 @@ pub fn cp(src string, dst string) ! {
226226 w_src := src.replace ('/' , '\\ ' )
227227 w_dst := dst.replace ('/' , '\\ ' )
228228 if C.CopyFile (w_src.to_wide (), w_dst.to_wide (), false ) == 0 {
229- return error_win32 (msg: 'failed to copy ${src } to ${dst }' )
229+ // we must save error immediately, or it will be overwritten by other API function calls.
230+ code := int (C.GetLastError ())
231+ return error_win32 (
232+ msg: 'failed to copy ${src } to ${dst }'
233+ code: code
234+ )
230235 }
231236 } $else {
232237 fp_from := C.open (& char (src.str), C.O_RDONLY, 0 )
@@ -480,8 +485,11 @@ pub fn rmdir(path string) ! {
480485 rc := C.RemoveDirectory (path.to_wide ())
481486 if ! rc {
482487 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya - 0 == false, is failure
488+ // we must save error immediately, or it will be overwritten by other API function calls.
489+ code := int (C.GetLastError ())
483490 return error_win32 (
484- msg: 'Failed to remove "${path }": ' + get_error_msg (int (C.GetLastError ()))
491+ msg: 'Failed to remove "${path }"'
492+ code: code
485493 )
486494 }
487495 } $else {
@@ -1077,7 +1085,7 @@ pub fn last_error() IError {
10771085}
10781086
10791087// Magic constant because zero is used explicitly at times
1080- pub const error_code_not_set = int (0x7EFEFEFE )
1088+ pub const error_code_not_set = int (- 1 )
10811089
10821090@[params]
10831091pub struct SystemError {
@@ -1086,7 +1094,7 @@ pub:
10861094 code int = error_code_not_set
10871095}
10881096
1089- // Return a POSIX error:
1097+ // error_posix returns a POSIX error:
10901098// Code defaults to last error (from C.errno)
10911099// Message defaults to POSIX error message for the error code
10921100@[inline; manualfree]
@@ -1096,15 +1104,33 @@ pub fn error_posix(e SystemError) IError {
10961104 return error_with_code (message, code)
10971105}
10981106
1099- // Return a Win32 API error:
1100- // Code defaults to last error (calling C.GetLastError())
1107+ // error_win32 returns a Win32 API error:
1108+ // example:
1109+ // ```
1110+ // // save error code immediately, or it will be overwritten by other API
1111+ // // function calls, even by `str_intp`.
1112+ // code := int(C.GetLastError())
1113+ // error_win32(
1114+ // msg : 'some error'
1115+ // code : code
1116+ // )
1117+ // ```
1118+ // wrong usage:
1119+ // ```
1120+ // error_win32(
1121+ // msg : 'some error ${path}' // this will overwrite error code
1122+ // code : int(C.GetLastError())
1123+ // )
1124+ // ```
11011125// Message defaults to Win 32 API error message for the error code
11021126@[inline; manualfree]
11031127pub fn error_win32 (e SystemError) IError {
11041128 $if windows {
1105- code := if e.code == error_code_not_set { int (C.GetLastError ()) } else { e.code }
1106- message := if e.msg == '' { get_error_msg (code) } else { e.msg }
1107- return error_with_code (message, code)
1129+ if e.code == error_code_not_set {
1130+ panic ('before calling `error_win32`, you must set `e.code` first.' )
1131+ }
1132+ message := if e.msg == '' { get_error_msg (e.code) } else { e.msg }
1133+ return error_with_code (message, e.code)
11081134 } $else {
11091135 panic ('Win32 API not available on this platform.' )
11101136 }
0 commit comments