marlersoft / zigwin32gen Goto Github PK
View Code? Open in Web Editor NEWGenerates Complete Zig bindings for Win32. See https://github.com/marlersoft/zigwin32 for the bindings themselves.
Generates Complete Zig bindings for Win32. See https://github.com/marlersoft/zigwin32 for the bindings themselves.
The _T function found in /src/zig.zig#L17 gives back the following error when you use it when running the program in ansi mode:
.\win32\win32\zig.zig:17:75: error: expected type '*const [4:0]u8', found '[]const u8'
Ran into this when I was playing around trying to see if I could build my program run on Windows 2000(Found out it doesn't).
I'm not sure if this is an issue with the metadata project or the interpretation into Zig types. If it's the former let me know and I will open an issue over there. ๐
The documentation for DirectSoundCreate and IDirectSound::CreateSoundBuffer says the following about their final LPUNKNOWN pUnkOuter
parameters:
- pUnkOuter
Controlling unknown of the aggregate. Its value must be NULL.
However these parameters are not optional in the Zig interface. Is null
a valid value for all LPUNKNOWN
s or is this an omission in the metadata?
A "PackingSize" of 0
is equivalent to an extern struct/union
in Zig, and a PackingSize of 1
is equivalent to a packed struct/union
in Zig. However, Zig doesn't have a way to modify a struct to emulate packing sizes larger than 1.
My current idea to support this, is when the packing size is greater than 1, I can use a packed
struct, and then add padding between each field based on the size of the previous field, i.e.
// emulate PackingSize of 2
const S = packed struct {
foo: T,
_padding0_: PaddingFor(T, 2),
bar: U,
_padding1_: PaddingFor(U, 2),
};
// emulate PackingSize of 4
const S = packed struct {
foo: T,
_padding0_: PaddingFor(T, 4),
bar: U,
_padding1_: PaddingFor(U, 4),
};
I am a zig noob so not entirely sure, but I believe this file needs to be updated for the new zig version in order to be able to build the examples properly
This is a follow up to the discussion here: microsoft/win32metadata#623
The issue is that some win32 pointer parameters accept more than just pointers, but Zig verifies pointer alignment which prevents these non-pointer values from being passed. For example, calling CreateWindowEx with the return value of RegisterClass for lpClassName
will trigger a pointer alignment issue when performing an alignCast
from ATOM
to LPCSTR
.
It was also discussed that changing these pointer parameters to a union type can break the ABI since some ABI's treat pointers and structure types differently, even if the structure itself is made up of a single pointer value.
So given these constraints, the solution I came up with for Zig is to maintain additional metadata that indicates which of these pointer parameters or fields can accept other non-pointer values and add align(1)
to those pointer types. If another projection would also like this additional metadata, then this extra data could be upstreamed and turned into a new attribute in the Microsoft supplied metadata. Note that since this is a possibility, I should make the implementation as similar to an attribute as I can.
The issue is that some win32 string pointer parameters accept strings that are optionally zero terminated. The associated length parameter determines the length (e.g. TextOut()
) or in some instances (e.g. DrawTextEx()
) a length parameter of -1 can allow the string to be zero terminated.
There is "NullNullTerm":false
in the JSON metadata that appears to indicate where the parameter should be [*]
rather than the current [0:*]
.
The goal is to be able to share type definitions between the std
and win32
packages. The long-term plan is to update this tool to be able to generate the bindings that will be included in std
. This should be as simple as keeping a list of constants/types/functions that would be set apart for inclusion in std
. At the same type, all references to these types would be updated to pull them from "std
".
In order to support updates to win32
that aren't necessarily in sync with std
, I'll also want a way to switch between referencing std
and referencing the std
win32 types generated by this project. I'm not sure the best way to do this yet. Maybe std
should allow this package to be overriden? I could reserve stdwin32" as a special package name that
std` imports to get all the win32 types.
std
needs as a set of functions, then perform a first pass on the metadata to determine what types/constants it needs.std
, then an alias will remain in the api
it appears in. This means that inter-api references will still work.win32/std.zig
module for now I think.std
The current idea is to allow an application to override the win32
bindings in std
with the following line in the root module:
// Use the version of std code in win32
pub const stdwin32 = @import("win32").std;
zigwin32gen will generate code meant to be included in std. That being said, a user may want to use the currently generated version of this std
code rather than the one shipped with their compiler. I think I can do this by checking for a pub symbol named stdwin32
in the root
module.
In these examples, assume that the generated code meant for std is deployed to std/os/windows/win32.zig
.
In std/os/windows.zig
const root = @import("root");
pub const win32 = if (@hasDecl(root, "stdwin32")) root.stdwin32 else @import("windows/win32.zig");
daurnimator asked if zigwin32 had the ability to override types. He suggested the root module could do something like this:
pub const zigwin32_config = struct {
pub const overrides = struct {
pub const SOME_STRUCT = struct{....}
};
};
To support this, whenever I generate a type, instead of this:
pub const SOME_STRUCT = struct {
//...
};
I could do something like this:
pub const SOME_STRUCT = if (getOverride("SOME_STRUCT")) |o| o else struct {
//...
};
Where getOverride
would look something like:
pub fn getOverride(comptime sym: []const u8) ?type {
const root = @import("root");
if (@hasDecl(root, "zigwin32_config")) {
if (@hasDecl(root.zigwin32_config, "override")) {
if (@hasDecl(root.zigwin32_config.override, sym)) {
return @field(root.zigwin32_config.override, sym);
}
}
}
return null;
}
Note that this mechanism could be leveraged to help with a solution to the std
interop problem.
Regarding this TODO:
Line 1669 in b42acec
Is there a big benefit to representing these values as non-exhaustive enums? My impression is that the common case is combining multiple bitmask values together which is awkward with the current setup. For example:
const std = @import("std");
const win32 = @import("win32").everything;
const class = std.mem.zeroInit(win32.WNDCLASSEXA, .{
.style = @intToEnum(win32.WNDCLASS_STYLES, @enumToInt(win32.CS_HREDRAW) | @enumToInt(win32.CS_VREDRAW) | @enumToInt(win32.CS_OWNDC)),
});
for (slice) |item, i|
-> for (slice, 0..) |item, i|
change as of 0.11.0-dev.1681+0bb178bbb
Win32 will sometimes use a "flexible array member" to copy data to/from the application. The GetInterfaceInfo function is an example:
https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getinterfaceinfo
//...
dwRetVal = GetInterfaceInfo(NULL, &ulOutBufLen);
if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
pInfo = (IP_INTERFACE_INFO *) MALLOC(ulOutBufLen);
if (pInfo == NULL) {
printf
("Unable to allocate memory needed to call GetInterfaceInfo\n");
return 1;
}
}
// Make a second call to GetInterfaceInfo to get
// the actual data we need
dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);
if (dwRetVal == NO_ERROR) {
printf("Number of Adapters: %ld\n\n", pInfo->NumAdapters);
for (i = 0; i < pInfo->NumAdapters; i++) {
printf("Adapter Index[%d]: %ld\n", i,
pInfo->Adapter[i].Index);
printf("Adapter Name[%d]: %ws\n\n", i,
pInfo->Adapter[i].Name);
}
//...
Zig could make this easier to do with a convenience method, i.e.
pub const IP_INTERFACE_INFO = extern struct {
NumAdapters: i32,
Adapter: [1]IP_ADAPTER_INDEX_MAP,
pub fn AdapterSlice(self: *IP_INTERFACE_INFO) []IP_ADAPTER_INDEX_MAP {
return @ptrCast([*]IP_ADAPTER_INDEX_MAP, &self.Adapter)[0 .. self.NumAdapters];
}
};
The tricky part here would be knowing that NumAdapters
is the length of the slice, but I think that info is available in the metadata.
Followed instructions on readme - throws an error.
loading 226 api json files...
1/226: loading 'AI.MachineLearning.DirectML.json'
read 124465 bytes
thread 12428 panic: reached unreachable code
C:\Users\kashifr\scoop\apps\ziglang\current\lib\std\debug.zig:226:14: 0x7ff67cfe1078 in std.debug.assert (genzig.obj)
if (!ok) unreachable; // assertion failure
^
W:\zigwin32gen\src\genzig.zig:1151:25: 0x7ff67d033c5a in CodeWriter::CodeWriter.writeBlock (genzig.obj)
std.debug.assert(s[s.len-1] == '\n');
^
W:\zigwin32gen\src\genzig.zig:670:26: 0x7ff67d01e1a7 in generateFile (genzig.obj)
try writer.writeBlock(
^
W:\zigwin32gen\src\genzig.zig:579:21: 0x7ff67d00f867 in readAndGenerateApiFile (genzig.obj)
try generateFile(module_dir, module, json_tree);
^
W:\zigwin32gen\src\genzig.zig:306:39: 0x7ff67cffe034 in main2 (genzig.obj)
try readAndGenerateApiFile(root_module, out_win32_dir, api_json_basename, file);
^
W:\zigwin32gen\src\genzig.zig:210:17: 0x7ff67cfe47ce in main (genzig.obj)
return main2() catch |e| switch (e) {
^
C:\Users\kashifr\scoop\apps\ziglang\current\lib\std\start.zig:458:37: 0x7ff67cfe36e4 in std.start.callMain (genzig.obj)
const result = root.main() catch |err| {
^
C:\Users\kashifr\scoop\apps\ziglang\current\lib\std\start.zig:255:65: 0x7ff67cfe3037 in std.start.WinStartup (genzig.obj)
std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
^
Unable to dump stack trace: FileNotFound
The following command exited with error code 2147483651 (expected 0):
cd W:\zigwin32gen && W:\zigwin32gen\zig-out\bin\genzig.exe
error: the following build command failed with exit code 1:
W:\zigwin32gen\zig-cache\o\a6258a072a6104458bfca3ecccfdf019\build.exe C:\Users\kashifr\scoop\apps\ziglang\current\zig.exe W:\zigwin32gen W:\zigwin32gen\zig-cache C:\Users\kashifr\AppData\Local\zig genzig
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.