2 * Copyright (c) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #define WIN32_LEAN_AND_MEAN
43 #pragma comment(lib, "shell32")
44 #pragma comment(lib, "user32")
45 #pragma comment(lib, "advapi32")
46 #endif /* _MSC_VER >= 1000 */
48 static const char win32api_type_hash
[] = "win32api:typemap";
50 __declspec(dllexport
) int Jim_OnLoad(Jim_Interp
*interp
);
52 /* ----------------------------------------------------------------------
53 * Convert Win32 error codes into an error message string object.
57 Win32ErrorObj(Jim_Interp
*interp
, const char * szPrefix
, DWORD dwError
)
59 Jim_Obj
*msgObj
= NULL
;
60 char * lpBuffer
= NULL
;
63 dwLen
= FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
64 | FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
, LANG_NEUTRAL
,
65 (char *)&lpBuffer
, 0, NULL
);
67 dwLen
= FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
68 | FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY
,
69 "code 0x%1!08X!%n", 0, LANG_NEUTRAL
,
70 (char *)&lpBuffer
, 0, (va_list *)&dwError
);
73 msgObj
= Jim_NewStringObj(interp
, szPrefix
, -1);
75 char *p
= lpBuffer
+ dwLen
- 1; /* remove cr-lf at end */
76 for ( ; p
&& *p
&& isspace(*p
); p
--)
79 Jim_AppendString(interp
, msgObj
, ": ", 2);
80 Jim_AppendString(interp
, msgObj
, lpBuffer
, -1);
82 LocalFree((HLOCAL
)lpBuffer
);
86 /* ----------------------------------------------------------------------
87 * Information recorded for API calls that we can call.
90 typedef struct Win32ApiDeclaration
{
91 HMODULE module
; /* Reference counted handle to the library */
92 LPSTR symbol
; /* The function name as used in the library */
93 FARPROC lpfn
; /* Generic function pointer for the API */
94 LPSTR rtype
; /* The return type */
95 Jim_Obj
*typeList
; /* List of parameters as type name type ... */
96 } Win32ApiDeclaration
;
99 /* ----------------------------------------------------------------------
102 * This is generic string:thing* hash.
103 * Keys are a typename. Values are pointers Win32ApiTypeInfo structs
106 typedef struct Win32ApiTypeInfo
{
107 size_t type_size
; /* The size of the type in bytes (not used yet) */
108 char type_spec
[]; /* packing details for the type */
111 static unsigned int Win32ApiTypeInfoHashTableHash(const void *key
)
113 /*return Jim_DjbHashFunction(key, strlen(key));*/
114 unsigned int h
= 5381;
115 size_t len
= strlen(key
);
117 h
= (h
+ (h
<< 5)) ^ *((const char *)key
)++;
121 static const void *Win32ApiTypeInfoHashTableCopyKey(void *privdata
, const void *key
)
123 JIM_NOTUSED(privdata
);
124 return Jim_StrDup(key
);
127 static int Win32ApiTypeInfoHashTableCompare(void *privdata
, const void *key1
, const void *key2
)
129 JIM_NOTUSED(privdata
);
130 return strcmp(key1
, key2
) == 0;
133 static void Win32ApiTypeInfoHashTableDestroyKey(void *privdata
, const void *key
)
135 JIM_NOTUSED(privdata
);
136 Jim_Free((void*)key
);
139 static void Win32ApiTypeInfoHashTableDestroyValue(void *interp
, void *val
)
141 Win32ApiTypeInfo
*entryPtr
= (Win32ApiTypeInfo
*)val
;
143 Jim_Free((void*)entryPtr
);
146 static Jim_HashTableType Win32ApiTypeHashTableType
= {
147 Win32ApiTypeInfoHashTableHash
, /* hash function */
148 Win32ApiTypeInfoHashTableCopyKey
, /* key dup */
150 Win32ApiTypeInfoHashTableCompare
, /* key compare */
151 Win32ApiTypeInfoHashTableDestroyKey
, /* key destructor */
152 Win32ApiTypeInfoHashTableDestroyValue
/* val destructor */
155 /* ----------------------------------------------------------------------
156 * The typedef object type is a caching internal rep to avoid repeat
157 * lookups into the hash table.
160 Jim_ObjType typedefObjType
= {
169 TypedefSetFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
171 if (objPtr
->typePtr
!= &typedefObjType
) {
172 const char *tname
= Jim_GetString(objPtr
, NULL
);
173 Jim_HashTable
*hashPtr
= Jim_GetAssocData(interp
, win32api_type_hash
);
174 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(hashPtr
, tname
);
175 if (entryPtr
== NULL
) {
176 Jim_Obj
*errObj
= Jim_NewEmptyStringObj(interp
);
177 Jim_AppendStrings(interp
, errObj
, "type \"", tname
, "\" is not defined", NULL
);
178 Jim_SetResult(interp
, errObj
);
182 Jim_FreeIntRep(interp
, objPtr
);
183 objPtr
->internalRep
.ptr
= entryPtr
;
184 objPtr
->typePtr
= &typedefObjType
;
189 /* ---------------------------------------------------------------------- */
191 /* Clean up the package's interp associated data */
193 Win32_PackageDeleteProc(Jim_Interp
*interp
, void *clientData
)
195 Jim_HashTable
*hashPtr
= (Jim_HashTable
*)clientData
;
196 Jim_FreeHashTable(hashPtr
);
197 Jim_Free(clientData
);
200 /* Update and introspect the type table
202 * Perls pack supports...
203 a char binary data (null padded) u uuencoded string
204 A cha binary data (space padded) U unicode char
206 c char s int16 i int l int32 n be u_int16 v le uint16 q int64 f float p pointer (null term)
207 C uchar S u_int16 I u_int L uint_32 N be u_int32 V le uint32 Q u_int64 d double P block pointer
210 Win32_Typedef(Jim_Interp
*interp
, int objc
, Jim_Obj
*const objv
[])
212 enum {OPT_NULL
, OPT_TYPE_NAMES
, OPT_TYPE_GET
, OPT_TYPE_SET
};
213 Jim_HashTable
*hashPtr
= (Jim_HashTable
*)Jim_CmdPrivData(interp
);
214 Win32ApiTypeInfo
*typePtr
;
215 const char *name
= NULL
, *spec
= NULL
;
216 int name_len
, spec_len
, n
, r
= JIM_OK
;
217 struct def
{ char c
; unsigned char n
; } defs
[] = {
218 'c', 1, 'C', 1, 's', 2, 'S', 2, 'i', 4, 'I', 4,
219 'l', 4, 'L', 4, 'n', 4, 'N', 4, 'v', 4, 'V', 4,
220 'q', 8, 'Q', 8, 'f', 4, 'd', 8, 'p', 4, 'P', 4,
221 'a', 1, 'A', 1, 'Z', 0, 'U', 2, 0, 0};
227 Jim_WrongNumArgs(interp
, 1, objv
, "typename ?pack_spec?");
232 /* Assign a new type. We validate the pack format and calculate the type size at the same time */
234 name
= Jim_GetString(objv
[1], &name_len
);
235 spec
= Jim_GetString(objv
[2], &spec_len
);
240 for (sp
= defs
; sp
->c
!= 0; sp
++) {
245 Jim_Obj
*errObj
= Jim_NewStringObj(interp
, "invalid pack character \"0\"", -1);
246 errObj
->bytes
[24] = *p
; /* NOTE: if you change the text in the above string this must be fixed */
247 Jim_AppendStrings(interp
, errObj
, " while defining type \"", name
, "\"", NULL
);
248 Jim_SetResult(interp
, errObj
);
251 if (isdigit(*(p
+1))) {
253 m
= strtol(p
+1, &pe
, 0);
262 n
= name_len
+ spec_len
+ 1;
263 typePtr
= (Win32ApiTypeInfo
*)Jim_Alloc(n
);
264 typePtr
->type_size
= size
;
265 strcpy(typePtr
->type_spec
, spec
);
266 Jim_AddHashEntry(hashPtr
, name
, typePtr
);
267 Jim_SetResultString(interp
, name
, name_len
);
271 Jim_HashEntry
*entryPtr
;
272 name
= Jim_GetString(objv
[1], &name_len
);
273 if ((entryPtr
= Jim_FindHashEntry(hashPtr
, name
)) == NULL
) {
274 Jim_Obj
*resObj
= Jim_NewEmptyStringObj(interp
);
275 Jim_AppendStrings(interp
, resObj
, "type \"", name
, "\" not found", NULL
);
276 Jim_SetResult(interp
, resObj
);
279 typePtr
= entryPtr
->val
;
280 Jim_SetResultString(interp
, typePtr
->type_spec
, -1);
284 case OPT_TYPE_NAMES
: {
286 Jim_HashEntry
*entryPtr
;
287 Jim_HashTableIterator
*it
= Jim_GetHashTableIterator(hashPtr
);
288 listPtr
= Jim_NewListObj(interp
, NULL
, 0);
289 while ((entryPtr
= Jim_NextHashEntry(it
)) != NULL
) {
290 Jim_ListAppendElement(interp
, listPtr
, Jim_NewStringObj(interp
, entryPtr
->key
, -1));
292 Jim_SetResult(interp
, listPtr
);
299 /* ---------------------------------------------------------------------- */
303 Win32_ApiCleanup(Jim_Interp
*interp
, void *clientData
)
305 Win32ApiDeclaration
*declPtr
= (Win32ApiDeclaration
*)clientData
;
306 FreeLibrary(declPtr
->module
);
307 Jim_Free((void *)declPtr
->symbol
);
308 Jim_Free((void *)declPtr
->rtype
);
309 Jim_DecrRefCount(interp
, declPtr
->typeList
);
313 Win32_ApiHandler(Jim_Interp
*interp
, int objc
, Jim_Obj
*const objv
[])
315 Win32ApiDeclaration
*declPtr
= (Win32ApiDeclaration
*)Jim_CmdPrivData(interp
);
316 Jim_HashTable
*hashPtr
;
317 int nargs
= 0, n
, np
, r
;
322 unsigned long params
[16];
325 Jim_ListLength(interp
, declPtr
->typeList
, &nargs
);
326 if (objc
-1 != nargs
/2) {
328 const char *types
= Jim_GetString(declPtr
->typeList
, &tlen
);
329 char *sz
= (char *)_alloca(tlen
+ 3);
330 sprintf(sz
, "(%s)", types
);
331 Jim_WrongNumArgs(interp
, 1, objv
, sz
);
335 ZeroMemory(¶m
, sizeof(param
));
336 hashPtr
= Jim_GetAssocData(interp
, win32api_type_hash
);
338 for (n
= 1, np
= 0; n
< objc
; n
++) {
339 Jim_HashEntry
*entryPtr
;
340 Jim_Obj
*tnameObj
, *pnameObj
;
341 const char *tname
, *pname
;
343 r
= Jim_ListIndex(interp
, declPtr
->typeList
, (np
*2), &tnameObj
, JIM_ERRMSG
);
344 tname
= Jim_GetString(tnameObj
, NULL
);
345 r
= Jim_ListIndex(interp
, declPtr
->typeList
, (np
*2)+1, &pnameObj
, JIM_ERRMSG
);
346 pname
= Jim_GetString(pnameObj
, NULL
);
348 entryPtr
= Jim_FindHashEntry(hashPtr
, tname
);
349 switch (((Win32ApiTypeInfo
*)entryPtr
->val
)->type_spec
[0]) {
351 Jim_GetWide(interp
, objv
[n
], (jim_wide
*)¶m
.params
[np
]);
355 Jim_GetLong(interp
, objv
[n
], &lval
);
356 param
.params
[np
] = (unsigned short)lval
;
360 Jim_GetDouble(interp
, objv
[n
], &dblval
);
361 memcpy(¶m
.params
[np
], &dblval
, 8);
365 Jim_GetDouble(interp
, objv
[n
], &dblval
);
366 fltval
= (float)dblval
;
367 memcpy(¶m
.params
[np
], &fltval
, 4);
370 case 'l': case 'L': case 'i': case 'I': case 'V':
372 Jim_GetLong(interp
, objv
[n
], ¶m
.params
[np
]);
381 r
= declPtr
->lpfn(param
);
383 Jim_SetResult(interp
, Jim_NewIntObj(interp
, r
));
388 Win32_Declare(Jim_Interp
*interp
, int objc
, Jim_Obj
*const objv
[])
390 Jim_HashTable
*hashPtr
= (Jim_HashTable
*)Jim_CmdPrivData(interp
); /* type hash map */
391 Win32ApiDeclaration
*declPtr
;
394 const char *lib
, *rtype
, *name
;
395 Jim_Obj
*cmdObj
= NULL
;
398 Jim_WrongNumArgs(interp
, 1, objv
, "lib return_type name typelist");
402 lib
= Jim_GetString(objv
[1], NULL
);
403 rtype
= Jim_GetString(objv
[2], NULL
);
404 name
= Jim_GetString(objv
[3], NULL
);
405 hLib
= LoadLibraryA(lib
);
407 Jim_SetResultString(interp
, "failed to load library", -1);
411 if ((lpfn
= GetProcAddress(hLib
, name
)) == NULL
) {
412 Jim_Obj
*errObj
= Jim_NewEmptyStringObj(interp
);
414 Jim_AppendStrings(interp
, errObj
, "could not load \"", name
, "\" from \"", lib
, "\"", NULL
);
415 Jim_SetResult(interp
, errObj
);
419 declPtr
= (Win32ApiDeclaration
*)Jim_Alloc(sizeof(Win32ApiDeclaration
));
420 declPtr
->module
= hLib
;
421 declPtr
->lpfn
= lpfn
;
422 declPtr
->symbol
= Jim_StrDup(name
);
423 declPtr
->rtype
= Jim_StrDup(rtype
);
424 declPtr
->typeList
= Jim_DuplicateObj(interp
, objv
[4]);
425 Jim_IncrRefCount(declPtr
->typeList
);
427 cmdObj
= Jim_NewStringObj(interp
, "", strlen(name
) + 9);
428 sprintf(cmdObj
->bytes
, "win32api.%s", name
);
429 Jim_CreateCommand(interp
, cmdObj
->bytes
, Win32_ApiHandler
, declPtr
, Win32_ApiCleanup
);
430 Jim_SetResult(interp
, cmdObj
);
434 /* ---------------------------------------------------------------------- */
437 Jim_OnLoad(Jim_Interp
*interp
)
439 Jim_HashTable
*hashPtr
;
440 Jim_InitExtension(interp
);
441 if (Jim_PackageProvide(interp
, "win32api", "1.0", JIM_ERRMSG
) != JIM_OK
)
444 hashPtr
= (Jim_HashTable
*)Jim_Alloc(sizeof(Jim_HashTable
));
445 Jim_InitHashTable(hashPtr
, &Win32ApiTypeHashTableType
, NULL
);
446 Jim_SetAssocData(interp
, win32api_type_hash
, Win32_PackageDeleteProc
, hashPtr
);
448 Jim_CreateCommand(interp
, "win32.declare", Win32_Declare
, hashPtr
, NULL
);
449 Jim_CreateCommand(interp
, "win32.typedef", Win32_Typedef
, hashPtr
, NULL
);
454 /* ----------------------------------------------------------------------
456 * indent-tabs-mode: nil