diff --git a/ext/ffi_c/LastError.c b/ext/ffi_c/LastError.c index 795a42e55..8a460f3b4 100644 --- a/ext/ffi_c/LastError.c +++ b/ext/ffi_c/LastError.c @@ -49,8 +49,17 @@ # define USE_PTHREAD_LOCAL #endif +#if defined(__CYGWIN__) +typedef uint32_t DWORD; +DWORD __stdcall GetLastError(void); +void __stdcall SetLastError(DWORD); +#endif + typedef struct ThreadData { int td_errno; +#if defined(_WIN32) || defined(__CYGWIN__) + DWORD td_winapi_errno; +#endif } ThreadData; #if defined(USE_PTHREAD_LOCAL) @@ -126,6 +135,19 @@ get_last_error(VALUE self) return INT2NUM(thread_data_get()->td_errno); } +#if defined(_WIN32) || defined(__CYGWIN__) +/* + * call-seq: winapi_error + * @return [Numeric] + * Get +GetLastError()+ value. Only Windows or Cygwin. + */ +static VALUE +get_last_winapi_error(VALUE self) +{ + return INT2NUM(thread_data_get()->td_winapi_errno); +} +#endif + /* * call-seq: error(error) @@ -146,22 +168,40 @@ set_last_error(VALUE self, VALUE error) return Qnil; } +#if defined(_WIN32) || defined(__CYGWIN__) +/* + * call-seq: error(error) + * @param [Numeric] error + * @return [nil] + * Set +GetLastError()+ value. Only on Windows and Cygwin. + */ +static VALUE +set_last_winapi_error(VALUE self, VALUE error) +{ + SetLastError(NUM2INT(error)); + return Qnil; +} +#endif + void rbffi_save_errno(void) { int error = 0; - #ifdef _WIN32 error = GetLastError(); #else error = errno; #endif +#if defined(_WIN32) || defined(__CYGWIN__) + DWORD winapi_error = GetLastError(); + thread_data_get()->td_winapi_errno = winapi_error; +#endif + thread_data_get()->td_errno = error; } - void rbffi_LastError_Init(VALUE moduleFFI) { @@ -175,6 +215,11 @@ rbffi_LastError_Init(VALUE moduleFFI) rb_define_module_function(moduleError, "error", get_last_error, 0); rb_define_module_function(moduleError, "error=", set_last_error, 1); +#if defined(_WIN32) || defined(__CYGWIN__) + rb_define_module_function(moduleError, "winapi_error", get_last_winapi_error, 0); + rb_define_module_function(moduleError, "winapi_error=", set_last_winapi_error, 1); +#endif + #if defined(USE_PTHREAD_LOCAL) pthread_key_create(&threadDataKey, thread_data_free); #else