This tool was used to generate almost everything in com.ms.win32.*. Nontrivial issues this tool handles include:
However there were many cases that had to be checked or totally redone by hand. Some of the items this tool will not translate include:
#define foo(x) x
, foo
will not be recognized as a function.
The parser was written to parse C code reasonably well, build
up an accurate representation of the C code, then apply
some Java conversion heuristics. While this works for simple types most
of the time, there are cases developers may want to handle specially.
For this reason, developers are encouraged to edit the program, adding
conversion rules wherever appropriate. For example, you could increase
Java performance by declaring some classes as final
.
But since this was designed as a generalized tool, the author felt allowing
customizability through subclassing would be more important than the
slight performance gain.
Inheritance isn't supported - J/Direct currently has no way to marshal the virtual function pointer correctly.
cl
, included with MS VC++.
dumpbin
, included with MS DevStudio (optional if you're only parsing one DLL).
grep
is strongly recommended.
WINAPI
,
APIENTRY
, or CALLBACK
(or another #define'd token that
expands to __stdcall
or __cdecl
) between a
function's return type and the function name. Example:
BOOL WINAPI SwitchDesktop(HDESK hDesktop);
Create symbol files for your DLL. If you only want to export one DLL, you can ignore this step, but its still recommended since skipping it adds one more step and a decent amount of filtering. Run this command on each DLL:
dumpbin /exports your_lib.dll > your_lib.sym
.
This list of symbols tells the parser which classes your functions belong in. All functions that aren't listed in a symbol file are put in Misc.java and need special attention (discussed below).
Create symbolfiles.txt in the same directory that the parser will be run in, listing all the symbol files you generated. Format of the file is one file per line, comment character is #.
Create a header file that includes all necessary headers. Make a file
called (for example) gen.h
, that includes everything you need.
This is optional if you only have one header file to parse and/or you have one
header file that includes all the other headers needed. Also make sure that
your headers are only included once each, or if they are included multiple times
that you wrap the headers with #ifdef's. Here's what your header should look like:
#ifdef __YOUR_HEADER_H__
#define __YOUR_HEADER_H__
<all of your header file code>
#endif
(In addition to being necessary for running the parser, this may speed up compile time for your code. The only time you don't want this is if you have a circular dependency in your header files, which is bad style.)
#define
's you
need for your code to compile in the current environment, then run the C
preprocessor over your header files. Example:
cl /Iinclude-path [/Dyour_symbol] /E gen.h > gen.prep
cl /I. /E windows.h > windows.prep
This generates a C preprocessed version of your headers with all the macros expanded, which is easier to parse.
Parser.PackageName
to be whatever you want.
Parser.ReadSymbols
, Parser.Suppress_UnknownLib_Functions
, and
Parser.Suppress_Unused_Structures
to reasonable values.Parser.SetupOutputClasses()
, add a PrintWriter for your class, output
the name of the class to that file, and add the PrintWriter to the hash
table, associating it with the name of your symbol file. This should be
very easy - just cut and paste the code already there, changing names around.
Note that this is useless without a symbol file (all of your
output will go into Misc.java).
Parser.SetupFileFilters()
, adding in any header files you parse to either
the ExcludeHeaders or IncludeHeaders vectors as appropriate. By default,
any unknown header file should be parsed, but this gives you a reasonable
amount of control.
jview Parser gen.prep
@dll.import
line to your
DLL's name. There may be other functions in this class that might not be in
your DLL and if you erroneously say they are, you'll get linking errors.To process #define'd constants, use defscan, a separate tool for scanning through files. As input, it expects files containing only #defines that span only one line with no other text in between. A good way to generate these is as follows:
grep #define your_header.h > your_header.def
After you do that, scan for C-style comments that span multiple lines. If you
don't do this, you may end up commenting out most of your constants! For any lines
that pop up from the following command, fix them up, usually by adding
a */
in the correct place.
grep \/\* your_header.def | grep -v \*\/
It cannot parse macros, although a few extremely simple ones have been special cased into the code. If you only have a handful of macros, you could add them into the code. Casting is supported to a limited extend. Strings can be outputted into the file or suppressed, depending on the value of defscan.SuppressStrings.
Run defscan with the following command if you have a small number of files:
jview defscan your_file.def
If there are many files, then list them all in files and run defscan with no arguments.
The output is a set of interface files containing all the constants. Since this was written to handle the Win32 constants, the output files all start with win. They are broken down alphabetically into multiple interfaces (win[a-z].java), plus there's one master interface file that contains them all (win.java).