1- /* Copyright (c) 2024 Lauri Ahonen, All Rights Reserved
1+ /* Copyright (c) 2025 Lauri Ahonen, All Rights Reserved
22 *
33 * The contents of this file is dual-licensed under 2
44 * alternative Open Source/Free licenses: LGPL 2.1 or later and
2121 * A copy is also included in the downloadable source code package
2222 * containing JNA, in file "AL2.0".
2323 */
24- package com .sun .jna .platform .win32 .COM ;
25-
26- import com .sun .jna .platform .win32 .OaIdl .FUNCDESC ;
27- import com .sun .jna .platform .win32 .OaIdl .TLIBATTR ;
28- import com .sun .jna .platform .win32 .OaIdl .TYPEATTR ;
29- import com .sun .jna .platform .win32 .OaIdl .VARDESC ;
24+ package com .sun .jna .platform .win32 ;
3025
26+ import com .sun .jna .platform .win32 .COM .ITypeInfo ;
27+ import com .sun .jna .platform .win32 .COM .TypeInfoUtil ;
28+ import com .sun .jna .platform .win32 .COM .TypeLibUtil ;
3129import java .io .File ;
32- import java .util .Arrays ;
33- import java .util .HashSet ;
34- import java .util .Set ;
30+ import org .junit .Test ;
31+
32+ import static org .junit .Assert .*;
33+
34+
35+ public class OaIdlTest {
36+
37+ public OaIdlTest () {
38+ }
39+
40+ /**
41+ * Test for TYPEDESC and FUNCDESC union handling.
42+ * This test iterates through functions in a Shell32 type library interface
43+ * and verifies that JNA correctly reads the discriminated unions in
44+ * TYPEDESC
45+ * and handles the lprgelemdescParam array correctly when cParams=0.
46+ */
47+ @ Test
48+ public void testReadFuncDesc () {
49+ TypeLibUtil libUtil = new TypeLibUtil ("{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}" , 1 , 0 ); // C:\Windows\SysWOW64\shell32.dll
50+
51+ // At time of test writing index 21 as IShellFolderViewDual3
52+ int typeIndex = 21 ;
53+
54+ ITypeInfo typeInfo = libUtil .getTypeInfo (typeIndex );
55+ TypeInfoUtil util = new TypeInfoUtil (typeInfo );
56+ OaIdl .TYPEATTR attr = util .getTypeAttr ();
3557
36- public class OaIdlRandomErrors {
37- static Set <String > includedFilenames = new HashSet <>();
58+ System .out .println (util .getDocumentation (new OaIdl .MEMBERID (-1 )).getName ());
59+
60+ assertTrue ("Expecting at least 1 function in the target type" , attr .cFuncs .intValue () > 0 );
61+
62+ for (int i = 0 ; i < attr .cFuncs .intValue (); i ++) {
63+ OaIdl .FUNCDESC func = util .getFuncDesc (i );
64+ TypeInfoUtil .TypeInfoDoc funcDoc = util .getDocumentation (func .memid );
65+ System .out .println ("Function " + i + ": " + funcDoc .getName () + " (cParams=" + func .cParams .shortValue () + ")" );
66+ util .ReleaseFuncDesc (func );
67+ }
68+
69+ // Reaching the end of the function is an implicit test that reading
70+ // succeeded and not exception was raised
71+ }
72+
73+ @ Test
74+ public void testReadVarDesc () {
75+ TypeLibUtil libUtil = new TypeLibUtil ("C:\\ Windows\\ System32\\ stdole2.tlb" );
76+ int count = libUtil .getTypeInfoCount ();
77+ for (int i = 0 ; i < count ; i ++) {
78+ TypeInfoUtil infoUtil = new TypeInfoUtil (libUtil .getTypeInfo (i ));
79+ OaIdl .TYPEATTR attr = infoUtil .getTypeAttr ();
80+ for (int j = 0 ; j < attr .cVars .intValue (); j ++) {
81+ infoUtil .getVarDesc (j );
82+ }
83+ }
84+ // Reaching the end of the function is an implicit test that reading
85+ // succeeded and not exception was raised
86+ }
3887
39- public static void main (String [] args ) {
40- String [] filenames = new String [] {
88+ @ Test
89+ public void testOaidlRandomErrors () {
90+ String [] filenames = new String []{
4191 "accessibilitycpl.dll" ,
4292 "activeds.tlb" ,
4393 "adprovider.dll" ,
@@ -266,64 +316,46 @@ public static void main(String[] args) {
266316 "xwtpdui.dll" ,
267317 "xwtpw32.dll"
268318 };
269- includedFilenames .addAll (Arrays .asList (filenames ));
270- processDir (new File ("C:\\ Windows\\ System32" ));
271- processDir (new File ("C:\\ Windows\\ SysWOW64" ));
272- System .out .println ("Finished." );
273- }
274-
275- protected static void processDir (File dir ) {
276- if (dir == null || !dir .exists ()) {
277- return ;
278- }
279- File [] files = dir .listFiles ();
280- if (files == null ) {
281- // Could not list files (not a directory or I/O error)
282- return ;
283- }
284- for (File file : files ) {
285- if (includedFilenames .contains (file .getName ())) {
286- processFile (file );
287- }
288- }
289- }
290-
291- protected static void processFile (File file ) {
292- try {
293- System .out .println (file );
294- TypeLibUtil libUtil = new TypeLibUtil (file .toString ());
295319
296- // Lib attributes
297- TLIBATTR libAttr = libUtil .getLibAttr ();
298- libUtil .ReleaseTLibAttr (libAttr );
299-
300- // Types
301- int count = libUtil .getTypeInfoCount ();
302- System .out .println ("Type count: " + count );
303- for (int i = 0 ; i < count ; i ++) {
304- TypeInfoUtil typeUtil = libUtil .getTypeInfoUtil (i );
305-
306- // Type attributes
307- TYPEATTR typeAttr = typeUtil .getTypeAttr ();
308- typeUtil .ReleaseTypeAttr (typeAttr );
309-
310- // Functions
311- for (int j = 0 ; j < typeAttr .cFuncs .intValue (); j ++) {
312- FUNCDESC funcDesc = typeUtil .getFuncDesc (j );
313- typeUtil .ReleaseFuncDesc (funcDesc );
314- }
315-
316- // Variables
317- for (int j = 0 ; j < typeAttr .cVars .intValue (); j ++) {
318- VARDESC varDesc = typeUtil .getVarDesc (j );
319- typeUtil .ReleaseVarDesc (varDesc );
320+ boolean atLeastOneTypeLibraryWithTypes = false ;
321+ for (String directory : new String []{"C:\\ Windows\\ System32" , "C:\\ Windows\\ SysWOW64" }) {
322+ for (String filename : filenames ) {
323+ File file = new File (directory , filename );
324+ if (file .exists ()) {
325+ TypeLibUtil libUtil = new TypeLibUtil (file .toString ());
326+ // Lib attributes
327+ OaIdl .TLIBATTR libAttr = libUtil .getLibAttr ();
328+ libUtil .ReleaseTLibAttr (libAttr );
329+ // Types
330+ int count = libUtil .getTypeInfoCount ();
331+ if (count > 0 ) {
332+ atLeastOneTypeLibraryWithTypes = true ;
333+ }
334+ System .out .printf ("%s => %d types%n" , file , count );
335+ for (int i = 0 ; i < count ; i ++) {
336+ TypeInfoUtil typeUtil = libUtil .getTypeInfoUtil (i );
337+ // Type attributes
338+ OaIdl .TYPEATTR typeAttr = typeUtil .getTypeAttr ();
339+ typeUtil .ReleaseTypeAttr (typeAttr );
340+ // Functions
341+ for (int j = 0 ; j < typeAttr .cFuncs .intValue (); j ++) {
342+ OaIdl .FUNCDESC funcDesc = typeUtil .getFuncDesc (j );
343+ typeUtil .ReleaseFuncDesc (funcDesc );
344+ } // Variables
345+ for (int j1 = 0 ; j1 < typeAttr .cVars .intValue (); j1 ++) {
346+ OaIdl .VARDESC varDesc = typeUtil .getVarDesc (j1 );
347+ typeUtil .ReleaseVarDesc (varDesc );
348+ }
349+ }
350+ libUtil .getTypelib ().Release ();
320351 }
321352 }
353+ }
322354
323- libUtil . getTypelib (). Release ( );
355+ assertTrue ( "No typelibrary with types read" , atLeastOneTypeLibraryWithTypes );
324356
325- } catch (Throwable e ) {
326- e .printStackTrace (System .out );
327- }
357+ // Reaching the end of the function is an implicit test that reading
358+ // succeeded and not exception was raised
328359 }
329- }
360+
361+ }
0 commit comments