Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 04dc70b

Browse files
committed
Multiple changes. Read full commit message.
code stuff: 1. Rewrote struct generation code to support nested structs 2. Removed multithreading. It was leading to race conditions I'd rather not waste my time on. 3. [Internal] Predefined type wrappers for primitives and commonly used types. readme stuff: 1. Added changelog 2. Added progress tracker
1 parent 61ecb49 commit 04dc70b

8 files changed

Lines changed: 354 additions & 148 deletions

File tree

README.MD

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ A Project Panama-based mapping + wrapper generator for win32 headers.
1212
7. [Linking libraries](#7-linking-libraries)
1313
8. [What next?](#8-what-next)
1414
9. [Inspiration](#9-inspiration)
15+
10. [Changelog](#10-changelog)
1516

1617
## 0. Disclaimer
1718
This project is not endorsed by nor affiliated with either Microsoft, Oracle, nor the OpenJDK project.
@@ -146,8 +147,13 @@ System.loadLibrary("User32");
146147
Note the lack of file extensions.
147148

148149
## 8. What next?
149-
Over the course of the next few months I will continue polishing the generator code and extract frequently used defines into wrapper classes to improve their usage in switch statements even further.
150-
I also want to fix the main drawback of struct wrappers, which is: if you have a struct composed of smaller sub-structs (for example, `DXGI_SWAP_CHAIN_DESC`), the wrapper library does create the getters/setters properly, so you have to fall back to the pure panama mappings.
150+
Over the course of the next few months I will continue polishing the generator code and add more quality of life wrappers.
151+
152+
Goals:
153+
- [x] Create wrapper code for structs inside structs
154+
- [ ] Create wrapper code for arrays inside structs
155+
- [ ] Create wrapper classes for common defines
156+
- [x] WM_*
151157

152158
## 9. Inspiration
153159
I originally came up with this idea after having a small spike of interest in direct3D, but found C++ programming to not be my cup of tea.
@@ -159,3 +165,46 @@ A bit of lore between MS and Java, I found while researching:
159165

160166
While scouting the web for COM implementations in java, i stumbled upon an article mentioning an abandoned programming language called J++, and lawsuit between Sun Microsystems and Microsoft, which eventually lead to the creation of the .NET framework and the C# programming language.
161167
So it seems like this project brings Java and Microsoft back together, a bit like how it was 20 years ago.
168+
169+
## 10. Changelog
170+
### [0.2.0] - 2021-10-14
171+
####Added
172+
Automatic fixing for known issues in:
173+
* ID3DInclude
174+
* XMLDOMDocumentEvents
175+
####Changed
176+
* Reimplemented struct generator. Nested structs are now supported.
177+
####Removed
178+
* The following win32 structs will not have wrappers generated, due to alignment incompatibility:
179+
* _MMIOINFO
180+
* DRVCONFIGINFOEX
181+
* IMAGE_AUX_SYMBOL_TOKEN_DEF
182+
* tagDRVCONFIGINFO
183+
* midihdr_tag
184+
* tagMCI_ANIM_OPEN_PARMSA
185+
* tagMCI_ANIM_OPEN_PARMSW
186+
* tagMCI_ANIM_WINDOW_PARMSA
187+
* tagMCI_ANIM_WINDOW_PARMSW
188+
* tagMCI_BREAK_PARMS
189+
* tagMCI_OPEN_PARMSA
190+
* tagMCI_OPEN_PARMSW
191+
* tagMCI_OVLY_OPEN_PARMSA
192+
* tagMCI_OVLY_OPEN_PARMSW
193+
* tagMCI_OVLY_WINDOW_PARMSA
194+
* tagMCI_OVLY_WINDOW_PARMSW
195+
* tagMCI_WAVE_OPEN_PARMSA
196+
* tagMCI_WAVE_OPEN_PARMSW
197+
* tagMETAHEADER
198+
* tagMIXERLINEA
199+
* tagMIXERLINECONTROLSA
200+
* tagMIXERLINECONTROLSW
201+
* tagMIXERLINEW
202+
* tagBITMAPFILEHEADER
203+
* tMIXERCONTROLDETAILS
204+
205+
including all structs derived from these.
206+
207+
If a struct contains one of these as a sub-struct, that sub-struct will not receive a wrapper field.
208+
209+
### [0.0.0-0.1.1]
210+
Extremely early code, no change tracking was done

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.falsepattern</groupId>
88
<artifactId>jwin32</artifactId>
9-
<version>0.1.1</version>
9+
<version>0.2.0</version>
1010

1111
<properties>
1212
<java.version>17</java.version>
@@ -39,7 +39,7 @@
3939
<classpath/>
4040
<argument>-Dforeign.restricted=permit</argument>
4141
<argument>--enable-native-access=ALL-UNNAMED</argument>
42-
<argument> --add-modules</argument><argument>jdk.incubator.foreign</argument>
42+
<argument>--add-modules</argument><argument>jdk.incubator.foreign</argument>
4343
<mainClass>com.falsepattern.jwin32.conversion.Translator</mainClass>
4444
</arguments>
4545
</configuration>
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.falsepattern.jwin32.conversion;
2+
3+
import com.falsepattern.jwin32.conversion.common.*;
4+
import jdk.incubator.foreign.GroupLayout;
5+
import jdk.incubator.foreign.MemoryLayout;
6+
import jdk.incubator.foreign.ValueLayout;
7+
8+
import java.util.Arrays;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.stream.Stream;
12+
13+
public class Struct {
14+
private static final CField SEGMENT_FIELD = new CField();
15+
private static final CConstructor SUPER_CALL_ASSIGN = new CConstructor();
16+
private static final CConstructor SUPER_CALL_ALLOCATOR = new CConstructor();
17+
static {
18+
SEGMENT_FIELD.accessSpecifier.pub = true;
19+
SEGMENT_FIELD.accessSpecifier.fin = true;
20+
SEGMENT_FIELD.name = "segment";
21+
SEGMENT_FIELD.type = CType.MEMORY_SEGMENT;
22+
23+
SUPER_CALL_ALLOCATOR.accessSpecifier.pub = true;
24+
SUPER_CALL_ALLOCATOR.paramList.add(new CParameter(CType.SEGMENT_ALLOCATOR, "allocator"));
25+
SUPER_CALL_ALLOCATOR.code.append("super(allocator);");
26+
27+
SUPER_CALL_ASSIGN.accessSpecifier.pub = true;
28+
SUPER_CALL_ASSIGN.paramList.add(new CParameter(CType.MEMORY_SEGMENT, "segment"));
29+
SUPER_CALL_ASSIGN.code.append("super(segment);");
30+
31+
}
32+
public final CClass implementation = new CClass();
33+
private final GroupLayout layout;
34+
public final Class<?> parent;
35+
private boolean valGetSetImplemented = false;
36+
37+
public Struct(GroupLayout layout, String pkg, Class<?> parent) {
38+
this.layout = layout;
39+
this.parent = parent;
40+
implementation.pkg = pkg;
41+
implementation.importImplicitly(new CType(parent));
42+
implementation.accessSpecifier.pub = true;
43+
implementation.name = parent.getSimpleName() + "_J";
44+
implementation.addField(SEGMENT_FIELD);
45+
implementation.addConstructor(genSetterConstructor());
46+
implementation.addConstructor(genAllocatorConstructor(parent));
47+
}
48+
49+
public Struct(String pkg, Class<?> parent, Class<?> baseImpl) {
50+
this.layout = null;
51+
this.parent = parent;
52+
var baseWrapper = new CType(pkg + "." + baseImpl.getSimpleName() + "_J", baseImpl.getSimpleName() + "_J", false);
53+
implementation.pkg = pkg;
54+
implementation.accessSpecifier.pub = true;
55+
implementation.name = parent.getSimpleName() + "_J";
56+
implementation.superclass = baseWrapper;
57+
implementation.addConstructor(SUPER_CALL_ASSIGN);
58+
implementation.addConstructor(SUPER_CALL_ALLOCATOR);
59+
}
60+
61+
public boolean isBaseImplementation() {
62+
return this.layout != null;
63+
}
64+
65+
private static CConstructor genSetterConstructor() {
66+
var constructor = new CConstructor();
67+
constructor.accessSpecifier.pub = true;
68+
constructor.paramList.add(new CParameter(CType.MEMORY_SEGMENT, "segment"));
69+
constructor.code.append("this.segment = segment;");
70+
return constructor;
71+
}
72+
73+
private static CConstructor genAllocatorConstructor(Class<?> parent) {
74+
var constructor = new CConstructor();
75+
constructor.accessSpecifier.pub = true;
76+
constructor.paramList.add(new CParameter(CType.SEGMENT_ALLOCATOR, "allocator"));
77+
constructor.code.append("this(").append(parent.getSimpleName()).append(".allocate(allocator));");
78+
return constructor;
79+
}
80+
81+
public boolean layoutEqualTo(MemoryLayout layout) {
82+
return layout.withName("").equals(this.layout.withName(""));
83+
}
84+
85+
public void implementValueLayoutGetterSetters() {
86+
if (!isBaseImplementation()) return;
87+
if (valGetSetImplemented) return;
88+
valGetSetImplemented = true;
89+
layout.memberLayouts()
90+
.stream()
91+
.filter(ValueLayout.class::isInstance)
92+
.map(ValueLayout.class::cast)
93+
.flatMap((value) -> {
94+
@SuppressWarnings("OptionalGetWithoutIsPresent") //A name is always present, no need to check
95+
var name = value.name().get();
96+
var getter = new CMethod();
97+
var setter = new CMethod();
98+
getter.accessSpecifier.pub = setter.accessSpecifier.pub = true;
99+
getter.name = setter.name = name;
100+
var oGetter = Arrays.stream(parent.getMethods()).filter((method) -> method.getParameterCount() == 1 && method.getName().equals(name + "$get")).findFirst();
101+
if (oGetter.isEmpty()) {
102+
System.err.println("Could not generate getter/setter for struct field " + name);
103+
return Stream.empty();
104+
}
105+
var type = new CType(oGetter.get().getReturnType());
106+
setter.paramList.add(new CParameter(getter.returnType = type, "value"));
107+
getter.code.append("return ").append(parent.getSimpleName()).append('.').append(name).append("$get(segment);");
108+
setter.code.append(parent.getSimpleName()).append('.').append(name).append("$set(segment, value);");
109+
return Stream.of(getter, setter);
110+
})
111+
.forEach(implementation::addMethod);
112+
}
113+
114+
public void implementGroupLayoutGetters(List<Struct> allStructs) {
115+
if (!isBaseImplementation()) return;
116+
var structMapping = new HashMap<GroupLayout, Struct>();
117+
allStructs.stream()
118+
.filter(Struct::isBaseImplementation)
119+
.filter((other) -> !(other.parent.isAssignableFrom(parent) || parent.isAssignableFrom(other.parent)))
120+
.forEach((other) -> layout.memberLayouts().stream()
121+
.filter(other::layoutEqualTo)
122+
.filter(GroupLayout.class::isInstance)
123+
.map(GroupLayout.class::cast)
124+
.forEach((subLayout) -> {
125+
if (subLayout.name().orElse("$anon$").startsWith("$anon$")) return;
126+
if (other.layoutEqualTo(subLayout)) {
127+
if (structMapping.containsKey(subLayout)) {
128+
var that = structMapping.get(subLayout);
129+
boolean thisTag = other.implementation.name.startsWith("tag");
130+
boolean thatTag = that.implementation.name.startsWith("tag");
131+
if (thisTag == thatTag)
132+
throw new IllegalStateException("Struct collision! " + structMapping.get(subLayout).parent + ", " + other.parent);
133+
else if (!thisTag) {
134+
structMapping.put(subLayout, other);
135+
}
136+
}
137+
structMapping.put(subLayout, other);
138+
}
139+
}));
140+
structMapping.forEach(this::setupGroupLayoutGetter);
141+
}
142+
143+
private void setupGroupLayoutGetter(GroupLayout layout, Struct struct) {
144+
@SuppressWarnings("OptionalGetWithoutIsPresent") //A name is always present, no need to check
145+
var name = layout.name().get();
146+
var cType = struct.implementation.asCType();
147+
148+
var field = new CField();
149+
implementation.constructors.get(0).code.append("\n").append(name).append(" = new ").append(cType.simpleName()).append("(").append(parent.getSimpleName()).append(".").append(name).append("$slice(segment));");
150+
field.accessSpecifier.pub = field.accessSpecifier.fin = true;
151+
field.name = name;
152+
field.type = cType;
153+
implementation.addField(field);
154+
}
155+
156+
public void implementSequenceLayoutGetterSetter(List<Struct> allStructs) {
157+
158+
}
159+
}

src/main/java/com/falsepattern/jwin32/conversion/StructGenerator.java

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)