summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2013-11-10 14:23:20 +0100
committerLars Kanis <lars@greiz-reinsdorf.de>2013-11-10 14:29:28 +0100
commit0499df7ed35cc3f4ffaee6a8f2ba2a09eef04fd4 (patch)
tree3c5dc991df82575fc6dacfff7635a0fa93cee609
parent2ae64ccf11a4201ff08d1eb6cfaf9aabdb06580a (diff)
downloadffi-0499df7ed35cc3f4ffaee6a8f2ba2a09eef04fd4.tar.gz
Fix stdcall ABI call convention.
FFI_STDCALL is no define, so stdcall was never used. This fixes issue #302 and adds a test case for stdcall callbacks..
-rw-r--r--ext/ffi_c/FunctionInfo.c4
-rw-r--r--ext/ffi_c/Variadic.c4
-rw-r--r--libtest/ClosureTest.c15
-rw-r--r--spec/ffi/callback_spec.rb23
4 files changed, 42 insertions, 4 deletions
diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c
index b42b539..8085c87 100644
--- a/ext/ffi_c/FunctionInfo.c
+++ b/ext/ffi_c/FunctionInfo.c
@@ -119,7 +119,7 @@ fntype_initialize(int argc, VALUE* argv, VALUE self)
ffi_status status;
VALUE rbReturnType = Qnil, rbParamTypes = Qnil, rbOptions = Qnil;
VALUE rbEnums = Qnil, rbConvention = Qnil, rbBlocking = Qnil;
-#if defined(_WIN32) || defined(__WIN32__)
+#if defined(X86_WIN32)
VALUE rbConventionStr;
#endif
int i, nargs;
@@ -181,7 +181,7 @@ fntype_initialize(int argc, VALUE* argv, VALUE self)
fnInfo->ffiReturnType = fnInfo->returnType->ffiType;
-#if (defined(_WIN32) || defined(__WIN32__)) && defined(FFI_STDCALL)
+#if defined(X86_WIN32)
rbConventionStr = (rbConvention != Qnil) ? rb_funcall2(rbConvention, rb_intern("to_s"), 0, NULL) : Qnil;
fnInfo->abi = (rbConventionStr != Qnil && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0)
? FFI_STDCALL : FFI_DEFAULT_ABI;
diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c
index 51e9785..687e8bc 100644
--- a/ext/ffi_c/Variadic.c
+++ b/ext/ffi_c/Variadic.c
@@ -103,7 +103,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE
VALUE retval = Qnil;
VALUE convention = Qnil;
VALUE fixed = Qnil;
-#if defined(_WIN32) || defined(__WIN32__)
+#if defined(X86_WIN32)
VALUE rbConventionStr;
#endif
int i;
@@ -116,7 +116,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE
invoker->rbAddress = rbFunction;
invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address;
-#if (defined(_WIN32) || defined(__WIN32__)) && defined(FFI_STDCALL)
+#if defined(X86_WIN32)
rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL);
invoker->abi = (RTEST(convention) && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0)
? FFI_STDCALL : FFI_DEFAULT_ABI;
diff --git a/libtest/ClosureTest.c b/libtest/ClosureTest.c
index 64ea2b4..dfeabde 100644
--- a/libtest/ClosureTest.c
+++ b/libtest/ClosureTest.c
@@ -50,6 +50,21 @@ P(D, double);
P(P, const void*);
P(UL, unsigned long);
+#if defined(_WIN32) && !defined(_WIN64)
+bool __stdcall testClosureStdcall(long *a1, void __stdcall(*closure)(void *, long), long a2) { \
+ void* sp_pre;
+ void* sp_post;
+
+ asm volatile (" movl %%esp,%0" : "=g" (sp_pre));
+ (*closure)(a1, a2);
+ asm volatile (" movl %%esp,%0" : "=g" (sp_post));
+
+ /* %esp before pushing parameters on the stack and after the call returns
+ * should be equal, if both sides respects the stdcall convention */
+ return sp_pre == sp_post;
+}
+#endif
+
void testOptionalClosureBrV(void (*closure)(char), char a1)
{
if (closure) {
diff --git a/spec/ffi/callback_spec.rb b/spec/ffi/callback_spec.rb
index d3151b4..59635f5 100644
--- a/spec/ffi/callback_spec.rb
+++ b/spec/ffi/callback_spec.rb
@@ -664,4 +664,27 @@ describe "Callback with " do
}.should raise_error(ArgumentError)
end
+ #
+ # Test stdcall convention with function and callback.
+ # This is Windows 32-bit only.
+ #
+ if FFI::Platform::OS =~ /windows|cygwin/ && FFI::Platform::ARCH == 'i386'
+ module LibTestStdcall
+ extend FFI::Library
+ ffi_lib TestLibrary::PATH
+ ffi_convention :stdcall
+
+ callback :cbStdcall, [ :pointer, :long ], :void
+ attach_function :testCallbackStdcall, 'testClosureStdcall', [ :pointer, :cbStdcall, :long ], :bool
+ end
+
+ it "stdcall convention" do
+ v = 0xdeadbeef
+ po = FFI::MemoryPointer.new :long
+ pr = proc{|a,i| v = a,i; i }
+ res = LibTestStdcall.testCallbackStdcall(po, pr, 0x7fffffff)
+ v.should == [po, 0x7fffffff]
+ res.should be_true
+ end
+ end
end