Skip to content

Commit de5316d

Browse files
committed
Merge pull request #533 from java-native-access/531-callback-cc-from-options
[531] Fix stdcall callback calling convention
2 parents 97978a0 + f2c2b4e commit de5316d

File tree

3 files changed

+70
-12
lines changed

3 files changed

+70
-12
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Bug Fixes
2525
---------
2626
* [#549](https://github.com/java-native-access/jna/pull/549): Fixed bug in types derived from XID - [@twall](https://github.com/twall).
2727
* [#536](https://github.com/java-native-access/jna/pull/536): Fixed bug in determining the Library and options associated with types defined outside of a Library - [@twall](https://github.com/twall).
28+
* [#531](https://github.com/java-native-access/jna/pull/531): Ensure direct-mapped callbacks use the right calling convention - [@twall](https://github.com/twall).
2829

2930
Release 4.2.1
3031
=============

src/com/sun/jna/CallbackReference.java

+21-12
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ class CallbackReference extends WeakReference {
3939
static final Map callbackMap = new WeakHashMap();
4040
static final Map directCallbackMap = new WeakHashMap();
4141
static final Map pointerCallbackMap = new WeakHashMap();
42+
// Track memory allocations associated with this closure (usually String args)
4243
static final Map allocations = new WeakHashMap();
44+
// Global map of allocated closures to facilitate centralized cleanup
4345
private static final Map allocatedMemory = Collections.synchronizedMap(new WeakHashMap());
4446

4547
private static final Method PROXY_CALLBACK_METHOD;
@@ -146,9 +148,11 @@ private static Callback getCallback(Class type, Pointer p, boolean direct) {
146148
// Keep a reference to the proxy to avoid premature GC of it
147149
CallbackProxy proxy;
148150
Method method;
151+
int callingConvention;
149152
private CallbackReference(Callback callback, int callingConvention, boolean direct) {
150153
super(callback);
151154
TypeMapper mapper = Native.getTypeMapper(callback.getClass());
155+
this.callingConvention = callingConvention;
152156
Class[] nativeParamTypes;
153157
Class returnType;
154158

@@ -180,6 +184,7 @@ private CallbackReference(Callback callback, int callingConvention, boolean dire
180184
}
181185

182186
String encoding = Native.getStringEncoding(callback.getClass());
187+
long peer = 0;
183188
if (direct) {
184189
method = getCallbackMethod(callback);
185190
nativeParamTypes = method.getParameterTypes();
@@ -188,12 +193,10 @@ private CallbackReference(Callback callback, int callingConvention, boolean dire
188193
if (callback instanceof DLLCallback) {
189194
flags |= Native.CB_OPTION_IN_DLL;
190195
}
191-
long peer = Native.createNativeCallback(callback, method,
192-
nativeParamTypes, returnType,
193-
callingConvention, flags,
194-
encoding);
195-
cbstruct = peer != 0 ? new Pointer(peer) : null;
196-
allocatedMemory.put(this, new WeakReference(this));
196+
peer = Native.createNativeCallback(callback, method,
197+
nativeParamTypes, returnType,
198+
callingConvention, flags,
199+
encoding);
197200
}
198201
else {
199202
if (callback instanceof CallbackProxy) {
@@ -236,12 +239,13 @@ private CallbackReference(Callback callback, int callingConvention, boolean dire
236239
}
237240
int flags = callback instanceof DLLCallback
238241
? Native.CB_OPTION_IN_DLL : 0;
239-
long peer = Native.createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
240-
nativeParamTypes, returnType,
241-
callingConvention, flags,
242-
encoding);
243-
cbstruct = peer != 0 ? new Pointer(peer) : null;
242+
peer = Native.createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
243+
nativeParamTypes, returnType,
244+
callingConvention, flags,
245+
encoding);
244246
}
247+
cbstruct = peer != 0 ? new Pointer(peer) : null;
248+
allocatedMemory.put(this, new WeakReference(this));
245249
}
246250

247251
private Class getNativeType(Class cls) {
@@ -404,8 +408,13 @@ private static Pointer getFunctionPointer(Callback cb, boolean direct) {
404408
if ((fp = getNativeFunctionPointer(cb)) != null) {
405409
return fp;
406410
}
411+
Map options = Native.getLibraryOptions(cb.getClass());
407412
int callingConvention = cb instanceof AltCallingConvention
408-
? Function.ALT_CONVENTION : Function.C_CONVENTION;
413+
? Function.ALT_CONVENTION
414+
: (options != null && options.containsKey(Library.OPTION_CALLING_CONVENTION)
415+
? ((Integer)options.get(Library.OPTION_CALLING_CONVENTION)).intValue()
416+
: Function.C_CONVENTION);
417+
409418
Map map = direct ? directCallbackMap : callbackMap;
410419
synchronized(callbackMap) {
411420
CallbackReference cbref = (CallbackReference)map.get(cb);

test/com/sun/jna/CallbacksTest.java

+48
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,54 @@ public void callback() {
14391439
}
14401440
}
14411441

1442+
public interface TaggedCallingConventionTestLibrary extends Library, AltCallingConvention {
1443+
interface TestCallbackTagged extends Callback, AltCallingConvention {
1444+
void invoke();
1445+
}
1446+
}
1447+
1448+
public void testCallingConventionFromInterface() {
1449+
TaggedCallingConventionTestLibrary lib = (TaggedCallingConventionTestLibrary)
1450+
Native.loadLibrary("testlib", TaggedCallingConventionTestLibrary.class);
1451+
TaggedCallingConventionTestLibrary.TestCallbackTagged cb = new TaggedCallingConventionTestLibrary.TestCallbackTagged() {
1452+
public void invoke() { }
1453+
};
1454+
try {
1455+
Pointer p = CallbackReference.getFunctionPointer(cb);
1456+
CallbackReference ref = (CallbackReference)CallbackReference.callbackMap.get(cb);
1457+
assertNotNull("CallbackReference not found", ref);
1458+
assertEquals("Tag-based calling convention not applied", Function.ALT_CONVENTION, ref.callingConvention);
1459+
}
1460+
catch (IllegalArgumentException e) {
1461+
// Alt convention not supported
1462+
}
1463+
}
1464+
1465+
public interface OptionCallingConventionTestLibrary extends Library {
1466+
interface TestCallback extends Callback {
1467+
void invoke();
1468+
}
1469+
}
1470+
1471+
public void testCallingConventionFromOptions() {
1472+
Map options = new HashMap();
1473+
options.put(Library.OPTION_CALLING_CONVENTION, Function.ALT_CONVENTION);
1474+
OptionCallingConventionTestLibrary lib = (OptionCallingConventionTestLibrary)
1475+
Native.loadLibrary("testlib", OptionCallingConventionTestLibrary.class, options);
1476+
OptionCallingConventionTestLibrary.TestCallback cb = new OptionCallingConventionTestLibrary.TestCallback() {
1477+
public void invoke() { }
1478+
};
1479+
try {
1480+
Pointer p = CallbackReference.getFunctionPointer(cb);
1481+
CallbackReference ref = (CallbackReference)CallbackReference.callbackMap.get(cb);
1482+
assertNotNull("CallbackReference not found", ref);
1483+
assertEquals("Option-based calling convention not applied", Function.ALT_CONVENTION, ref.callingConvention);
1484+
}
1485+
catch(IllegalArgumentException e) {
1486+
// Alt convention not supported
1487+
}
1488+
}
1489+
14421490
public static void main(java.lang.String[] argList) {
14431491
junit.textui.TestRunner.run(CallbacksTest.class);
14441492
}

0 commit comments

Comments
 (0)