]> gerrit.simantics Code Review - simantics/python.git/blob - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Print exception type name if we can't get a traceback.
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
1 ///////////////////////////////////////////////////////
2 //                                                   //
3 //   VTT Technical Research Centre of Finland LTD    //
4 //   For internal use only. Do not redistribute.     //
5 //                                                   //
6 //   Authors:                                        //
7 //       Antton Tapani    ext-antton.tapani@vtt.fi   //
8 //                                                   //
9 //   Last modified by Antton Tapani    9.2016        //
10 //                                                   //
11 ///////////////////////////////////////////////////////
12
13 #include "sclpy.h"
14
15 #include <windows.h>
16
17 jint throwException( JNIEnv *env, char *className, char *message )
18 {
19     jclass exClass = (*env)->FindClass( env, className);
20     if (exClass == NULL) {
21         return 0;
22     }
23
24     return (*env)->ThrowNew( env, exClass, message );
25 }
26
27 jint throwPythonException( JNIEnv *env, char *message ) {
28         return throwException( env, PYTHON_EXCEPTION, message );
29 }
30
31 jint throwIllegalArgumentException( JNIEnv *env, char *message ) {
32         return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
33 }
34
35 int moduleCount = 0;
36 int hasNumpy = 0;
37 PyThreadState *main_ts = 0;
38
39 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
40         char name[16];
41
42         if (!main_ts) {
43         Py_Initialize();
44
45         hasNumpy = _import_array();
46         hasNumpy = hasNumpy != -1;
47         main_ts = PyEval_SaveThread();
48         }
49
50         sprintf(name, "SCL_%d", ++moduleCount);
51
52         PyEval_RestoreThread(main_ts);
53         {
54                 PyObject *module = PyModule_New(name);
55                 PyObject *main = PyImport_AddModule("__main__");
56
57                 PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0);
58                 PyEval_SaveThread();
59                 return (jlong)module;
60         }
61 }
62
63 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
64         PyObject *module = (PyObject*)contextID;
65         PyEval_RestoreThread(main_ts);
66         Py_XDECREF(module);
67         PyEval_SaveThread();
68 }
69
70 PyObject *getPythonBool(jboolean value) {
71         if (value) {
72                 Py_RETURN_TRUE;
73         }
74         else {
75                 Py_RETURN_FALSE;
76         }
77 }
78
79 PyObject *getPythonString(JNIEnv *env, jstring string) {
80         jsize len = (*env)->GetStringLength(env, string);
81         const jchar *chars = (*env)->GetStringChars(env, string, NULL);
82
83         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
84
85         (*env)->ReleaseStringChars(env, string, chars);
86         return value;
87 }
88
89 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
90         jsize nitems = (*env)->GetArrayLength(env, value);
91         jint *values = (*env)->GetIntArrayElements(env, value, NULL);
92         jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
93         jint i;
94
95         PyObject *result = PyList_New(nitems);
96         for (i = 0; i < nitems; i++) {
97                 jobject item = (*env)->GetObjectArrayElement(env, value, i);
98                 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
99                         PyList_SetItem(result, i, getPythonString(env, (jstring)item));
100                 }
101                 else {
102                         PyList_SetItem(result, i, Py_None);
103                 }
104         }
105
106         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
107         return result;
108 }
109
110 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
111         jsize nitems = (*env)->GetArrayLength(env, value);
112         jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
113         jint i;
114
115         PyObject *result = PyList_New(nitems);
116         for (i = 0; i < nitems; i++) {
117                 PyList_SetItem(result, i, getPythonBool(values[i]));
118         }
119
120         (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
121         return result;
122 }
123
124 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
125         jint len = (*env)->GetArrayLength(env, value);
126         jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
127
128         PyObject *result = PyByteArray_FromStringAndSize(values, len);
129
130         (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
131         return result;
132 }
133
134 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
135         jsize nitems = (*env)->GetArrayLength(env, value);
136         jint *values = (*env)->GetIntArrayElements(env, value, NULL);
137         jint i;
138
139         PyObject *result = PyList_New(nitems);
140         for (i = 0; i < nitems; i++) {
141                 PyList_SetItem(result, i, PyLong_FromLong(values[i]));
142         }
143
144         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
145         return result;
146 }
147
148 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
149         jsize nitems = (*env)->GetArrayLength(env, value);
150         jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
151         jint i;
152
153         PyObject *result = PyList_New(nitems);
154         for (i = 0; i < nitems; i++) {
155                 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
156         }
157
158         (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
159         return result;
160 }
161
162 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
163         jsize nitems = (*env)->GetArrayLength(env, value);
164         float *values = (*env)->GetFloatArrayElements(env, value, NULL);
165         jint i;
166
167         PyObject *result = PyList_New(nitems);
168         for (i = 0; i < nitems; i++) {
169                 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
170         }
171
172         (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
173         return result;
174 }
175
176 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
177         jsize nitems = (*env)->GetArrayLength(env, value);
178         double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
179         jint i;
180
181         PyObject *result = PyList_New(nitems);
182         for (i = 0; i < nitems; i++) {
183                 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
184         }
185
186         (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
187         return result;
188 }
189
190 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
191         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
192         jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
193         jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
194
195         jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
196         jsize ndims = (*env)->GetArrayLength(env, jdims);
197         jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
198
199         jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
200         jsize len = (*env)->GetArrayLength(env, jvalues);
201         jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
202
203         npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
204
205         jint i, nelem = ndims > 0 ? 1 : 0;
206         for (i = 0; i < ndims; i++) {
207                 nelem *= dims[i];
208                 pyDims[i] = dims[i];
209         }
210
211         len = min(len, nelem);
212
213         {
214                 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
215                 double *data = (double *)PyArray_DATA((PyArrayObject*)array);
216
217                 memcpy(data, values, len * sizeof(double));
218
219                 free(pyDims);
220
221                 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
222                 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
223
224                 return array;
225         }
226 }
227
228 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
229         jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
230         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
231
232         jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
233         return getPythonBool(bvalue);
234 }
235
236 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
237         jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
238         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
239
240         jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
241         return PyLong_FromLong(v);
242 }
243
244 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
245         jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
246         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
247
248         jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
249         return PyLong_FromLong(v);
250 }
251
252 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
253         jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
254         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
255
256         jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
257         return PyLong_FromLongLong(v);
258 }
259
260 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
261         jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
262         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
263
264         jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
265         return PyFloat_FromDouble(v);
266 }
267
268 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
269         jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
270         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
271
272         jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
273         return PyFloat_FromDouble(v);
274 }
275
276 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
277         jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
278         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
279
280         jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
281         jsize len = (*env)->GetStringLength(env, string);
282         const jchar *chars = (*env)->GetStringChars(env, string, NULL);
283
284         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
285
286         (*env)->ReleaseStringChars(env, string, chars);
287         return value;
288 }
289
290 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
291         jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
292         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
293         jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
294         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
295
296         jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
297         jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
298         jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
299
300         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
301         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
302
303         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
304         jint n = (*env)->CallIntMethod(env, type, getComponentCount);
305         jint i;
306
307         PyObject *result = PyDict_New();
308         for (i = 0; i < n; i++) {
309                 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
310                 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
311                 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
312                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
313
314                 PyObject *item = getPythonObject(env, componentObject, componentBinding);
315                 PyDict_SetItem(result, getPythonString(env, fieldName), item);
316         }
317
318         return result;
319 }
320
321 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
322         jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
323         jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
324         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
325         jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
326
327         jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
328
329         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
330
331         PyObject *result = PyList_New(size);
332
333         jint i;
334         for (i = 0; i < size; i++) {
335                 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
336                 if (item != NULL)
337                         PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
338                 else
339                         PyList_SetItem(result, i, Py_None);
340         }
341
342         return result;
343 }
344
345 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
346         jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
347         jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
348         jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
349         jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
350         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
351         jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
352
353         jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
354         jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
355
356         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
357         jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
358         jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
359
360         PyObject *result = PyDict_New();
361         jint i;
362
363         (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
364
365         for (i = 0; i < size; i++) {
366                 jobject key = (*env)->GetObjectArrayElement(env, keys, i);
367                 jobject item = (*env)->GetObjectArrayElement(env, values, i);
368                 PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
369         }
370
371         (*env)->DeleteLocalRef(env, keys);
372         (*env)->DeleteLocalRef(env, values);
373
374         return result;
375 }
376
377 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
378         jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
379         jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
380
381         jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
382
383         if (hasValue) {
384                 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
385                 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
386
387                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
388                 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
389
390                 return getPythonObject(env, value, componentBinding);
391         }
392         else {
393                 return Py_None;
394         }
395 }
396
397 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
398         jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
399         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
400         jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
401         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
402         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
403
404         jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
405         jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
406
407         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
408         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
409
410         jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
411         jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
412
413         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
414         jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
415         jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
416
417         jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
418
419         PyObject *result = PyTuple_New(2);
420         PyTuple_SetItem(result, 0, getPythonString(env, compName));
421         PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
422
423         return result;
424 }
425
426 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
427         jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
428         jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
429         jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
430
431         jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
432         jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
433
434         return getPythonObject(env, content, contentBinding);
435 }
436
437 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
438         jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
439         jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
440         jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
441         jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
442         jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
443         jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
444         jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
445         jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
446         jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
447         jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
448         jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
449         jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
450         jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
451
452         if (value == NULL)
453                 return Py_None;
454
455         if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
456                 return getPythonBooleanObject(env, value, binding);
457         }
458         else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
459                 return getPythonByteObject(env, value, binding);
460         }
461         else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
462                 return getPythonIntegerObject(env, value, binding);
463         }
464         else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
465                 return getPythonLongObject(env, value, binding);
466         }
467         else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
468                 return getPythonFloatObject(env, value, binding);
469         }
470         else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
471                 return getPythonDoubleObject(env, value, binding);
472         }
473         else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
474                 return getPythonStringObject(env, value, binding);
475         }
476         else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
477                 return getPythonRecordObject(env, value, binding);
478         }
479         else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
480                 return getPythonArrayObject(env, value, binding);
481         }
482         else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
483                 return getPythonMapObject(env, value, binding);
484         }
485         else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
486                 return getPythonOptionalObject(env, value, binding);
487         }
488         else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
489                 return getPythonUnionObject(env, value, binding);
490         }
491         else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
492                 return getPythonVariantObject(env, value, binding);
493         }
494         else {
495                 return Py_None;
496         }
497 }
498
499 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
500         if (name && value) {
501                 PyDict_SetItem(PyModule_GetDict(module), name, value);
502         }
503
504         Py_XDECREF(name);
505         Py_XDECREF(value);
506 }
507
508 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
509         if (d == nd) {
510                 ncont[d] = 1;
511                 return 1;
512         }
513         else {
514                 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
515                 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
516                 return ncont[d];
517         }
518 }
519
520 static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
521         if (ncont[d] > 0) {
522                 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
523                 *offset += ncont[d];
524         }
525         else {
526                 int i;
527                 for (i = 0; i < dims[d]; i++) {
528                         copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
529                 }
530         }
531 }
532
533 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
534         jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
535         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
536
537         return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
538 }
539
540 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
541         jclass longClass = (*env)->FindClass(env, "java/lang/Long");
542         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
543
544         return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
545 }
546
547 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
548         jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
549         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
550
551         return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
552 }
553
554 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
555         Py_ssize_t size = PyByteArray_Size(value);
556         jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
557         char *bytes = PyByteArray_AsString(value);
558
559         (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
560
561         return result;
562 }
563
564 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
565         PyObject *utf16Value = PyUnicode_AsUTF16String(string);
566         Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
567         char *bytes = PyBytes_AsString(utf16Value);
568
569         // Create Java string, skipping the byte order mark in the beginning
570         jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
571
572         Py_XDECREF(utf16Value);
573
574         return result;
575 }
576
577 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
578         Py_ssize_t len = PySequence_Size(seq);
579         jsize jlen = (jsize)min(len, JAVA_MAXINT);
580         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
581
582         jint i;
583
584         for (i = 0; i < jlen; i++) {
585                 PyObject *item = PySequence_GetItem(seq, i);
586                 if (PyUnicode_Check(item)) {
587                         jstring value = pythonStringAsJavaString(env, item);
588                         (*env)->SetObjectArrayElement(env, array, i, value);
589                 }
590                 else {
591                         throwPythonException(env, "List item not a string");
592                         return NULL;
593                 }
594         }
595
596         return array;
597 }
598
599 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
600         Py_ssize_t len = PySequence_Size(seq);
601         jsize jlen = (jsize)min(len, JAVA_MAXINT);
602         jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
603
604         jint i;
605
606         for (i = 0; i < jlen; i++) {
607                 PyObject *item = PySequence_GetItem(seq, i);
608                 if (PyFloat_Check(item)) {
609                         double value = PyFloat_AsDouble(item);
610                         (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
611                 }
612                 else {
613                         throwPythonException(env, "List item not a floating point value");
614                         return NULL;
615                 }
616         }
617
618         return array;
619 }
620
621 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
622         if (PyBool_Check(value))
623                 return pythonBoolAsBooleanObject(env, value);
624         else if (PyLong_Check(value))
625                 return pythonLongAsLongObject(env, value);
626         else if (PyFloat_Check(value))
627                 return pythonFloatAsDoubleObject(env, value);
628         else if (PyUnicode_Check(value))
629                 return pythonStringAsJavaString(env, value);
630         else if (PyByteArray_Check(value))
631                 return pythonByteArrayAsByteArray(env, value);
632         else if (PyDict_Check(value))
633                 return pythonDictionaryAsMap(env, value);
634         else if (hasNumpy && PyArray_Check(value))
635                 return pythonArrayAsNDArray(env, (PyArrayObject *)value);
636         else if (PySequence_Check(value))
637                 return pythonSequenceAsObjectArray(env, value);
638         else
639                 return NULL;
640 }
641
642 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
643         Py_ssize_t len = PySequence_Size(seq);
644         jsize jlen = (jsize)min(len, JAVA_MAXINT);
645         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
646
647         jint i;
648
649         for (i = 0; i < jlen; i++) {
650                 PyObject *item = PySequence_GetItem(seq, i);
651                 jobject object = pythonObjectAsObject(env, item);
652                 (*env)->SetObjectArrayElement(env, array, i, object);
653         }
654
655         return array;
656 }
657
658 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
659         Py_ssize_t len = PySequence_Size(seq);
660         jsize jlen = (jsize)min(len, JAVA_MAXINT);
661         jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
662
663         jint i;
664
665         for (i = 0; i < jlen; i++) {
666                 PyObject *item = PySequence_GetItem(seq, i);
667                 if (PyBool_Check(item)) {
668                         jboolean value = item == Py_True;
669                         (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
670                 }
671                 else {
672                         throwPythonException(env, "List item not a boolean");
673                         return NULL;
674                 }
675         }
676
677         return array;
678 }
679
680 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
681         Py_ssize_t len = PySequence_Size(seq);
682         jsize jlen = (jsize)min(len, JAVA_MAXINT);
683         jintArray array = (*env)->NewIntArray(env, jlen);
684
685         jint i;
686
687         for (i = 0; i < jlen; i++) {
688                 PyObject *item = PySequence_GetItem(seq, i);
689                 if (PyLong_Check(item)) {
690                         jint value = PyLong_AsLong(item);
691                         (*env)->SetIntArrayRegion(env, array, i, 1, &value);
692                 }
693                 else {
694                         throwPythonException(env, "List item not an integer");
695                         return NULL;
696                 }
697         }
698
699         return array;
700 }
701
702 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
703         Py_ssize_t len = PySequence_Size(seq);
704         jsize jlen = (jsize)min(len, JAVA_MAXINT);
705         jlongArray array = (*env)->NewLongArray(env, jlen);
706
707         jint i;
708
709         for (i = 0; i < jlen; i++) {
710                 PyObject *item = PySequence_GetItem(seq, i);
711                 if (PyLong_Check(item)) {
712                         jlong value = PyLong_AsLongLong(item);
713                         (*env)->SetLongArrayRegion(env, array, i, 1, &value);
714                 }
715                 else {
716                         throwPythonException(env, "List item not an integer");
717                         return NULL;
718                 }
719         }
720
721         return array;
722 }
723
724 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
725         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
726         jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
727
728         int ndims = PyArray_NDIM(array);
729         npy_intp *dims = PyArray_DIMS(array);
730
731         npy_intp len = PyArray_Size((PyObject*)array);
732         double *values = (double*)PyArray_DATA(array);
733
734         jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
735
736         int i;
737
738         if (len > JAVA_MAXINT) {
739                 throwPythonException(env, "Array too large");
740                 return NULL;
741         }
742
743         {
744                 jintArray jdims = (*env)->NewIntArray(env, ndims);
745                 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
746
747                 for (i = 0; i < ndims; i++) {
748                         jint dim = (jint)dims[i];
749                         (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
750                 }
751
752                 if (PyArray_IS_C_CONTIGUOUS(array)) {
753                         (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
754                 }
755                 else {
756                         npy_intp offset = 0;
757                         npy_intp *strides = PyArray_STRIDES(array);
758                         npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
759                         nContiguous(0, ndims, strides, dims, ncont);
760                         copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
761                         free(ncont);
762                 }
763
764                 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
765         }
766 }
767
768 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
769         jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
770         jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
771         jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
772
773         Py_ssize_t size = PyDict_Size(dict);
774         jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
775
776         PyObject *key, *value;
777         Py_ssize_t pos = 0;
778
779         while (PyDict_Next(dict, &pos, &key, &value)) {
780                 jobject keyObject = pythonObjectAsObject(env, key);
781                 jobject valueObject = pythonObjectAsObject(env, value);
782                 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
783         }
784
785         return map;
786 }
787
788 #define DEF_SETTER(typename, jtype, j2py)                               \
789     JNIEXPORT void JNICALL                                              \
790     Java_org_simantics_pythonlink_PythonContext_setPython##typename     \
791     ##VariableImpl(                                                     \
792         JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
793         jtype value) {                                                  \
794             PyObject *module = (PyObject*)contextID;                    \
795                                                                         \
796             PyEval_RestoreThread(main_ts);                              \
797             setPythonVariable(module, getPythonString(env, variableName), \
798                               j2py(env, value));                        \
799             PyEval_SaveThread();                                        \
800     }
801
802 #define getPythonBoolean(env, value) getPythonBool(value)
803 #define getPythonLong(env, value) PyLong_FromLongLong(value)
804 #define getPythonDouble(env, value) PyFloat_FromDouble(value)
805
806 DEF_SETTER(Boolean, jboolean, getPythonBoolean)
807 DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
808 DEF_SETTER(Long, jlong, getPythonLong)
809 DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
810 DEF_SETTER(LongArray, jlongArray, getPythonLongList)
811 DEF_SETTER(Double, jdouble, getPythonDouble)
812 DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
813 DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
814 DEF_SETTER(String, jstring, getPythonString)
815 DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
816
817 JNIEXPORT void JNICALL
818 Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
819                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
820                 jobject value) {
821         PyObject *module = (PyObject*)contextID;
822
823         if (!hasNumpy) {
824                 throwPythonException(env, "Importing numpy failed");
825                 return;
826         }
827
828         PyEval_RestoreThread(main_ts);
829         {
830                 PyObject *pythonName = getPythonString(env, variableName);
831                 PyObject *val = getPythonNDArray(env, value);
832
833                 setPythonVariable(module, pythonName, val);
834         }
835         PyEval_SaveThread();
836 }
837
838 JNIEXPORT void JNICALL
839 Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
840                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
841                 jobject value, jobject binding) {
842         PyObject *module = (PyObject*)contextID;
843
844         PyEval_RestoreThread(main_ts);
845         setPythonVariable(module, getPythonString(env, variableName),
846                                           getPythonObject(env, value, binding));
847         PyEval_SaveThread();
848 }
849
850 JNIEXPORT jint JNICALL
851 Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
852                 JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
853         PyObject *module = (PyObject*)contextID;
854
855         const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
856
857         PyEval_RestoreThread(main_ts);
858         PyErr_Clear();
859         {
860                 PyObject *globals;
861
862                 globals = PyModule_GetDict(module);
863
864                 {
865                         PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
866
867                         PyObject *exceptionType = PyErr_Occurred();
868                         if (exceptionType != NULL) {
869                                 PyObject *exception, *traceback;
870                                 PyErr_Fetch(&exceptionType, &exception, &traceback);
871
872                                 {
873                                         PyObject *tracebackModule = PyImport_ImportModule("traceback");
874                                         if (tracebackModule != NULL) {
875                                                 PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
876                                                 if (formatExc != NULL) {
877                                                         PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback);
878                                                         PyObject *message = PyObject_CallObject(formatExc, args);
879                                                         if (message != NULL) {
880                                                                 PyObject *emptyStr = PyUnicode_FromString("");
881                                                                 PyObject *joined = PyUnicode_Join(emptyStr, message);
882                                                                 char *messageStr = PyUnicode_AsUTF8(joined);
883                                                                 throwPythonException(env, messageStr);
884                                                                 Py_DECREF(joined);
885                                                                 Py_DECREF(emptyStr);
886                                                                 Py_DECREF(message);
887                                                         }
888                                                         else {
889                                                                 PyTypeObject
890                                                                         *ty = (PyTypeObject *)exceptionType;
891                                                                 throwPythonException(
892                                                                                 env, ty ? ty->tp_name
893                                                                                                 : "Internal error, null exception type");
894                                                         }
895                                                         Py_DECREF(args);
896                                                         Py_DECREF(formatExc);
897                                                 }
898                                                 else {
899                                                         throwPythonException(env, "Internal error, no format_exc function");
900                                                 }
901                                                 Py_DECREF(tracebackModule);
902                                         }
903                                         else {
904                                                 throwPythonException(env, "Internal error, no traceback module");
905                                         }
906                                 }
907                                 Py_XDECREF(exceptionType);
908                                 Py_XDECREF(exception);
909                                 Py_XDECREF(traceback);
910                         }
911
912                         PyEval_SaveThread();
913                         (*env)->ReleaseStringUTFChars(env, statement, utfchars);
914
915                         return result != NULL ? 0 : 1;
916                 }
917         }
918 }
919
920
921 // Returns a borrowed reference.
922 static PyObject *getPythonValue(
923                 JNIEnv *env, jlong contextID, jstring variableName) {
924     PyObject *module = (PyObject*)contextID;
925     PyObject *pythonName = getPythonString(env, variableName);
926     PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
927
928     Py_DECREF(pythonName);
929     if (value == NULL) {
930         throwPythonException(env, "Python variable not found");
931     }
932     return value;
933 }
934
935 #define DEF_GETTER(typename, jtype, check, desc, py2j)                  \
936     JNIEXPORT jtype JNICALL                                             \
937     Java_org_simantics_pythonlink_PythonContext_getPython##typename     \
938     ##VariableImpl(                                                     \
939             JNIEnv *env, jobject thisObj, jlong contextID,              \
940             jstring variableName) {                                     \
941         jtype result = 0;                                               \
942         PyEval_RestoreThread(main_ts);                                  \
943         do {                                                            \
944             PyObject *value = getPythonValue(env, contextID, variableName); \
945             if (value == 0) break;                                      \
946             if (check(value)) {                                         \
947                 result = py2j(env, value);                              \
948             } else {                                                    \
949                 throwPythonException(env, "Python variable not " desc); \
950             }                                                           \
951         } while (0);                                                    \
952         PyEval_SaveThread();                                            \
953         return result;                                                  \
954     }
955
956 #define pythonBoolAsJboolean(env, value) ((value) == Py_True)
957 #define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
958 #define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
959
960 DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
961                    pythonStringAsJavaString)
962 DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
963                    pythonSequenceAsStringArray)
964 DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
965 DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
966                    pythonSequenceAsBooleanArray)
967 DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
968 DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
969                    pythonSequenceAsIntegerArray)
970 DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
971                    pythonSequenceAsLongArray)
972 DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
973 DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
974                    pythonSequenceAsDoubleArray)
975
976 JNIEXPORT jobject JNICALL
977 Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
978                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
979         jobject result = NULL;
980
981         if (!hasNumpy) {
982                 throwPythonException(env, "Importing numpy failed");
983                 return NULL;
984         }
985
986         PyEval_RestoreThread(main_ts);
987         do {
988                 PyObject *value = getPythonValue(env, contextID, variableName);
989                 if (value == NULL) break;
990                 if (!PyArray_Check(value)) {
991                         throwPythonException(env, "Python variable not an ndarray");
992                 } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
993                         throwPythonException(
994                                         env, "Only ndarrays of type double are supported");
995                 } else {
996                         result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
997                 }
998         } while (0);
999         PyEval_SaveThread();
1000         return result;
1001 }
1002
1003 #define python_anything_goes(value) 1
1004
1005 DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
1006                    pythonObjectAsObject)
1007
1008 JNIEXPORT jint JNICALL
1009 Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
1010                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1011         jint result = 0;
1012         PyEval_RestoreThread(main_ts);
1013         {
1014                 PyObject *value = getPythonValue(env, contextID, variableName);
1015                 if (PyBool_Check(value))
1016                         result = 1;
1017                 else if (PyLong_Check(value))
1018                         result = 2;
1019                 else if (PyFloat_Check(value))
1020                         result = 3;
1021                 else if (PyUnicode_Check(value))
1022                         result = 4;
1023                 else if (PyByteArray_Check(value))
1024                         result = 5;
1025                 else if (PyDict_Check(value))
1026                         result = 6;
1027                 else if (hasNumpy && PyArray_Check(value))
1028                         result = 7;
1029                 else if (PySequence_Check(value))
1030                         result = 8;
1031                 else
1032                         result = -1;
1033         }
1034         PyEval_SaveThread();
1035         return result;
1036 }
1037
1038 JNIEXPORT jobjectArray JNICALL
1039 Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
1040                 JNIEnv *env, jobject thisObj, jlong contextID) {
1041         jobjectArray result = NULL;
1042         PyEval_RestoreThread(main_ts);
1043         {
1044                 PyObject *module = (PyObject*)contextID;
1045                 PyObject *dict = PyModule_GetDict(module);
1046
1047                 PyObject *keys = PyDict_Keys(dict);
1048                 Py_ssize_t size = PyList_Size(keys);
1049                 Py_ssize_t i;
1050
1051                 result = (*env)->NewObjectArray(
1052                                 env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
1053
1054                 for (i = 0; i < size; i++) {
1055                         jstring javaName = pythonStringAsJavaString(
1056                                         env, PyList_GetItem(keys, i));
1057                         (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
1058                 }
1059
1060                 Py_XDECREF(keys);
1061         }
1062         PyEval_SaveThread();
1063         return result;
1064 }
1065
1066 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1067 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1068 {
1069     switch (fdwReason)
1070     {
1071         case DLL_PROCESS_ATTACH:
1072             // attach to process
1073             // return FALSE to fail DLL load
1074             break;
1075
1076         case DLL_PROCESS_DETACH:
1077             // detach from process
1078             break;
1079
1080         case DLL_THREAD_ATTACH:
1081             // attach to thread
1082             break;
1083
1084         case DLL_THREAD_DETACH:
1085             // detach from thread
1086             break;
1087     }
1088     return TRUE; // succesful
1089 }