/* Copyright (c) 2007-2014 Timothy Wall, All Rights Reserved * * The contents of this file is dual-licensed under 2 * alternative Open Source/Free licenses: LGPL 2.1 or later and * Apache License 2.0. (starting with JNA version 4.0.0). * * You can freely decide which license you want to apply to * the project. * * You may obtain a copy of the LGPL License at: * * http://www.gnu.org/licenses/licenses.html * * A copy is also included in the downloadable source code package * containing JNA, in file "LGPL2.1". * * You may obtain a copy of the Apache License at: * * http://www.apache.org/licenses/ * * A copy is also included in the downloadable source code package * containing JNA, in file "AL2.0". */ package com.sun.jna.win32; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import junit.framework.TestCase; import com.sun.jna.FunctionMapper; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLibrary; import com.sun.jna.NativeLong; import com.sun.jna.Structure; /** * @author twall@users.sf.net */ public class W32StdCallTest extends TestCase { public static interface TestLibrary extends StdCallLibrary { public static class Inner extends Structure { public static final List<String> FIELDS = createFieldsOrder("value"); public double value; @Override protected List<String> getFieldOrder() { return FIELDS; } } public static class TestStructure extends Structure { public static class ByValue extends TestStructure implements Structure.ByValue { } public static final List<String> FIELDS = createFieldsOrder("c", "s", "i", "j", "inner"); public byte c; public short s; public int i; public long j; public Inner inner; @Override protected List<String> getFieldOrder() { return FIELDS; } } int returnInt32ArgumentStdCall(int arg); TestStructure.ByValue returnStructureByValueArgumentStdCall(TestStructure.ByValue arg); interface Int32Callback extends StdCallCallback { int callback(int arg, int arg2); } int callInt32StdCallCallback(Int32Callback c, int arg, int arg2); interface ManyArgsStdCallCallback extends StdCallCallback { void callback(NativeLong arg1, int arg2, double arg3, String arg4, String arg5, double arg6, NativeLong arg7, double arg8, NativeLong arg9, NativeLong arg10, NativeLong arg11); } int callManyArgsStdCallCallback(ManyArgsStdCallCallback c, NativeLong arg1, int arg2, double arg3, String arg4, String arg5, double arg6, NativeLong arg7, double arg8, NativeLong arg9, NativeLong arg10, NativeLong arg11); } public static void main(java.lang.String[] argList) { junit.textui.TestRunner.run(W32StdCallTest.class); } private TestLibrary testlib; @Override protected void setUp() { testlib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_FUNCTION_MAPPER, StdCallLibrary.FUNCTION_MAPPER)); } @Override protected void tearDown() { testlib = null; } public void testFunctionMapper() throws Exception { FunctionMapper mapper = StdCallLibrary.FUNCTION_MAPPER; NativeLibrary lib = NativeLibrary.getInstance("testlib"); Method[] methods = { TestLibrary.class.getMethod("returnInt32ArgumentStdCall", int.class), TestLibrary.class.getMethod("returnStructureByValueArgumentStdCall", TestLibrary.TestStructure.ByValue.class), TestLibrary.class.getMethod("callInt32StdCallCallback", TestLibrary.Int32Callback.class, int.class, int.class) }; for (Method m : methods) { String name = mapper.getFunctionName(lib, m); assertTrue("Function name not decorated for method " + m.getName() + ": " + name, name.indexOf("@") != -1); assertEquals("Wrong name in mapped function", name, lib.getFunction(name, StdCallLibrary.STDCALL_CONVENTION).getName()); } } public void testStdCallReturnInt32Argument() { final int MAGIC = 0x12345678; assertEquals("Expect zero return", 0, testlib.returnInt32ArgumentStdCall(0)); assertEquals("Expect magic return", MAGIC, testlib.returnInt32ArgumentStdCall(MAGIC)); } public void testStdCallReturnStructureByValueArgument() { TestLibrary.TestStructure.ByValue s = new TestLibrary.TestStructure.ByValue(); assertTrue("Wrong struct value", s.dataEquals(testlib.returnStructureByValueArgumentStdCall(s))); } public void testStdCallCallback() { final int MAGIC = 0x11111111; final boolean[] called = { false }; TestLibrary.Int32Callback cb = new TestLibrary.Int32Callback() { @Override public int callback(int arg, int arg2) { called[0] = true; return arg + arg2; } }; final int EXPECTED = MAGIC*3; int value = testlib.callInt32StdCallCallback(cb, MAGIC, MAGIC*2); assertTrue("stdcall callback not called", called[0]); if (value == -1) { fail("stdcall callback did not restore the stack pointer"); } assertEquals("Wrong stdcall callback value", Integer.toHexString(EXPECTED), Integer.toHexString(value)); value = testlib.callInt32StdCallCallback(cb, -1, -2); if (value == -1) { fail("stdcall callback did not restore the stack pointer"); } assertEquals("Wrong stdcall callback return", -3, value); } public void testStdCallCallbackStackAlignment() { final boolean[] called = { false }; TestLibrary.ManyArgsStdCallCallback cb = new TestLibrary.ManyArgsStdCallCallback() { @Override public void callback(NativeLong arg1, int arg2, double arg3, String arg4, String arg5, double arg6, NativeLong arg7, double arg8, NativeLong arg9, NativeLong arg10, NativeLong arg11) { called[0] = true; } }; int value = testlib.callManyArgsStdCallCallback(cb, new NativeLong(1), 2, 3, "four", "five", 6, new NativeLong(7), 8, new NativeLong(9), new NativeLong(10), new NativeLong(11)); assertTrue("stdcall callback not called", called[0]); if (value == -1) { fail("stdcall callback did not restore the stack pointer"); } } }