Last update March 7, 2012

Windows API

StewartGordon is coordinating a project to create a well-crafted translation of the Windows 32-bit API headers in the D programming language.

The official pages for this project are now hosted on the Dsource wiki.


This is a record of discussions that happened while this page was the official project page. To date, no decision has been made on what will happen to this section. Please don't start new discussions here, but rather use the Dsource forum.

What to do with set-type constants (1,2,4,8,...) which are ORed together? An enum does not seem appropriate. (Maybe D will get sets some day?) I've used grouped const for now. - Don.
  • I've tended to use enums for these as well. But you're right that it isn't exactly what enums are designed for. Anyway, many such groups contain more than just bit flags, e.g. many WS_xxxx constants are bit flags, but there are also some groups of mutually exclusive options such as WS_POPUP, WS_OVERLAPPED, WS_CHILD. On the whole, they're analogous to bit fields, with the advantage of literals. -- Stewart

I've had an idea about how to deal with the Windows versions!

We can turn w32api.d into a module that defines constants based on what version identifiers are set. All modules will then import this module and use static if to select by them. Effectively we'd be using the _WIN32_WINDOWS, _WIN32_WINNT and _WIN32_IE we already have in the C headers, except that all three constants would be always defined, and therefore && will replace || when checking _WIN32_WINDOWS and _WIN32_WINNT together. Using the existing values for these constants will also make the translation process that little bit easier. -- Stewart

Implemented! -- Stewart

For mswsock and winsock2, I've had to make two version identifiers: Win32_Winsock and Win32_Winsock2, which are set by winsock.d and winsock2.d. First of all, from what I've seen in the MinGW headers, including winsock automatically precludes including winsock2 and vice-versa, so the version identifiers are used to stop that. Secondly, mswsock needs to import various definitions (such as SOCKET, etc.). In the original headers, they just seemed to require the programmer to include these ahead of time. But since we can't do that, I've used the version identifiers to select which one to include (it defaults to winsock2 if neither is present). Anyway, I'd feel better about it if someone who knew what they are doing could just check to make sure this is all kosher. It's my first shot at this, so please forgive any mistakes.
Ok, that didn't work so well. Just discovered that version statements don't affect other modules. I'm not really sure how to solve this problem... the only solution I can come up with at the moment is to default to using winsock2, and force the user to define WIN32_WINSOCK or somesuch on the compiler command line if they want to use winsock 1.
Indeed, it does look a bit of a mess. And at the moment, windows imports winsock, which in turn imports mswsock, which throws the warning. This isn't an ideal situation to be in. Perhaps better would be to either:
    • Remove the import of winsock from windows.d, and just expect the programmer to import one or the other
    • As you begin to suggest, default to one and have a version that one is supposed to set to use the other. To stop both from being imported, you could do something like (in winsock2.d, and something similar in winsock.d)
version (Win32_Winsock2) {
} else {
    pragma msg("To use win32.winsock2, please set version Win32_Winsock2");
IMO the default should be whichever's the minimum version Win95 supports, considering that Win95 is the default support level already. -- Stewart

Thanks for that; sorry I didn't notice the update here sooner. Is there any way to subscribe to changes on these pages?

I've cracked open MSDN, and found that Winsock2 was supported in Win95, but judging by, it wasn't included in Windows until Win98, so I'll default to winsock1 and have a version that can be set on the command line to enable winsock2.

Also, I'll fix the TIMEVAL comparison stuff. Update: Done. -- DanielKeep

I really think that Winsock2 should be the default, since it was supported in Win95. It was definitely included in Win95 B and C. It's possible that Winsock2 might not have been included in the original Win95 release, but any such computers with networks connections would be immediately wiped out by viruses if they've never been upgraded to Winsock2. We can be confident that there are no Win95 PCs that want to use Winsock1. Winsock1 is a 16-bit technology, I doubt that any D programs will ever use it. -- Don

Per the consensus, Winsock2 is now the default. -- Stewart

All afxres.h does is defines IDC_STATIC. In winuser.h it's conditioned out. What's the deal with it? -- StewartGordon
It looks like an MFC header to me, for compatibility with Visual C++. Delete it. - Don.

Don't use 'static if' for conditionally importing files. Doing so will confuse build. Although it's painful, I think a sequence of version() statements is required. -Don.

winsock.h and winsock2.h have identical code that compares two TIMEVAL objects. However, they've been translated in very different ways:
  • winsock2 has kept timercmp, changing the third parameter from an operator token to a function. Makes for rather wordy code.
  • winsock has replaced it with an opCmp function. Much nicer IMO and has other potential benefits.
-- Stewart

Done. I've only commented out the timercmp functions, though. I'm not sure what the stance on compatibility with the C headers is; someone who is looking for the timercmp function probably isn't going to think to try directly comparing TIMEVALs.
It isn't and can't be compatible with the C headers in the first place. In C, you're expected to do stuff like
timercmp(time1, time2, <)
which obviously doesn't translate directly into D since D doesn't have a preprocessor. It goes without saying that the D way is different, and that anyone who doesn't instantly guess it can look at the code. But a comment that mentions timercmp will certainly help these people.... -- Stewart
Now I see you've mentioned in a comment: "Still, perhaps these should be enabled under a version tag for compatibility's sake?" Straight to the point please - compatibility with what? -- Stewart

Do you think there is a need for a Win32_Compat version identifier? Perhaps it could define old functions that aren't or cannot be supported, so that at least users get some idea of what's changed instead of just a "symbol undefined"? Even better: rig it up so that these unsupported functions become templates that, when "called" using IFTI, they spit out a pragma(msg, ...) saying "Hey, this isn't supported. Use XXX instead.". What do you think? -- DanielKeep
So we'd have the Win16 functions that aren't even implemented in Win32, as well as the ones that are deprecated? Might be an idea for the future, but IMO it's a bit early to spend time on it while the translation itself is still in progress. And anyway, why go through contortions to have a pragma(msg)? That's exactly what deprecation is for. -- Stewart
Carrying on with it, what's the name Win32_Compat about? It sounds like an option for compatibility with Win32 - but Win32 already is the API we are binding up, and it would have to be compatible with itself to make sense. I've more thoughts, but it would be crossing a bridge before we get to it.... -- Stewart
I think this is philosophically wrong. The C headers have ancient 16-bit code to support. D doesn't. Any code that's worth converting to D, is also worth converting to Win32!. We should strip all the Win16 stuff from the headers, while we have the chance. -- Don
Thinking about it now, I agree with you. No point having 16-bit compatibility stuff for a language that's exclusively 32+-bit. -- Stewart

We could do with some clear meanings of the statuses. In particular, I feel that "compiles" should be used only once the module has been fully translated from a functional (as opposed to aesthetic) POV. That includes translating the Windows version conditionals into our system. -- StewartGordon
I originally used "compiles" to distinguish them from modules which would generate errors if you imported them, it was the most primitive level of usability (except for "fixme" which meant that it compiled only by commenting things out (especially bit fields)). By all means come up with a better scheme. -- Don.

I'm trying to think of one at the moment. But I suppose there are the following factors to consider:
    • whether the initial process of translating the header into a D file has been completed
    • whether the module is fully translated from a functional point of view, including versions
    • whether the code has been polished - types of constants given everywhere that they can be determined, code layout fully made to match our conventions
    • whether it compiles without error
    • whether bits of code have been identified that aren't straightforward to translate (or to determine whether they're necessary) and will need attention
    • whether it has been adequately tested
Hmm.... -- Stewart

How about:
Initial conversion, but with sections commented out -- fixme
Initial conversion with basic functionality -- compiles
Fully functional (including versioning, pragma(lib)) -- alpha
Polished -- beta
-- Don.

That's more or less the scheme I was beginning to think of, though you've beaten me to deciding on what to call them! -- Stewart

I'm now beginning to implement this scheme. This may take a while. Meanwhile, I'm going to asterisk old statuses. -- Stewart

I've made a file win32.core, which corresponds to #define {WIN32 LEAN AND MEAN}? #include "windows.h". It seems to me that this is the normal way of including windows in C projects, and I suspect that the full windows.h only exists for compatibility with 16-bit windows. I suggest we have a seperate module that includes the COM/RPC stuff, replacing Phobos' -- Don
I've had another idea about the variable-length structs.

At the moment we have

    DWORD            dwNumEntries;
    MIB_IPADDRROW[1] _table;

    MIB_IPADDRROW* table() { return _table.ptr; }
which suppresses the ABC altogether. But I now wonder if we should make it return an array with the correct bounds:
    DWORD         dwNumEntries;
    MIB_IPADDRROW _table;

    MIB_IPADDRROW* table() { return (&_table)[0..dwNumEntries]; }

I also thought of having a custom allocator, making such structs easy to allocate and at the same time be GCable.

    new(size_t len) {
        return new void[DWORD.sizeof + len * MIB_IPADDRROW.sizeof];

Unfortunately we can't set dwNumEntries automatically in the allocation code, since by the spec

No initialization of the memory is necessary, as code is automatically inserted after the call to new() to set the class instance members to their defaults and then the constructor (if any) is run.
So we'd just have to make sure the programmer knows that dwNumEntries must be set manually.

What do you people think to these ideas? -- Stewart

I think this falls into the category of improvements to the Windows API, which is definitely something we need to think about. -- Don

I suppose it's partly improvement and partly making it into something that makes sense in D. The API in its C form makes use of C's lack of ABC, so it seems a reasonable question whether the appropriate translation into D is to bypass ABC or to make use of it. -- Stewart

It would definitely be good to remove the most absurd things (eg, HMODULE should be replaced with HINSTANCE, since they are exactly the same), and tighten the type system where we can. But we do need to proceed with caution. -- Don

There's been a lot of debate on what to do with the type system - such as whether to get rid of the meaningless aliases. But if we're going to do anything like this, we would have to plan carefully. See also my posts on d.D:454 and d.D:15248. -- Stewart

Something that I think would be very useful for D would be to develop a standard wrapper over parts of the Windows API. All of the GUI frameworks that I've seen (in both D and C++) end up with lots of code that is the same, it would be great to factor some of the simple stuff into a seperate layer. -- Don

Hmm.... -- Stewart

I'm suggesting to change byte to ubyte in following declarations in wingdi.d:
COLORREF RGB(byte r, byte g, byte b)
COLORREF PALETTERGB(byte r, byte g, byte b)
-- SergKovrov?

They should be ubyte indeed. As you will see by looking either at the C headers or at what these functions do with their arguments. If you spot a mistake, by all means correct it! -- StewartGordon

How is the definition of EMRPOLYPOLYLINE supposed to make sense? From MinGW?:
typedef struct tagEMRPOLYPOLYLINE
    EMR     emr;  
    RECTL   rclBounds; 
    DWORD   nPolys; 
    DWORD   cptl; 
    DWORD   aPolyCounts[1]; 
    POINTL  aptl[1]; 
It's a one-element array followed by another. So although aPolyCounts is defined as "Array of point counts for each poly", there's only room for one point count before aptl begins. What do you reckon we're supposed to do with this? -- Stewart

Some WINE code contains information that shows how those values are used:
NB POINTS array doesn't start at pPolyPoly->apts it's actually pPolyPoly->aPolyCounts + pPolyPoly->nPolys
-- JamesRTwine

So why is aptl declared in this struct? Still, this doesn't answer the question of how we should adapt this for D without breaking it for people coming from C. -- Stewart

Recently several modules that were converted from MinGW? were replaced with "Copyright (C) Microsoft Corporation. All Rights Reserved." ones. See d3d9.d for example. IMHO, this contradicts the project policy, and will prevent it's integration into Phobos, Tango... What do you think? -- Vladimir

To be honest, I don't understand the problem why M$ should have any problems, if we translate their headers to D. They are forced by many institutions (like the EU) to reveal and open their interfaces anyway. We don't harm their IP in any way by this, we only build D interface files to interact with their OS. If they decide to sue us for that, I'm sure the EU are very interested in the case. Apart from that I see no reason to include the copyright from M$ anyway, this D interface files are written by us and not them. If parts are automatically translated the sources are the MinGW? headers not the M$ ones. Therefore we should include our own copyright. But I'm no lawyer and the german Urheberrecht (copyright) is slightly different than the US copyright. -- WeirdCat?

Possible ITypeInfo Bug in objbase.d

Some (I can't remember which) functions that take ITypeInfo*'s, asked for ItypeInfo**'s in the objbase.d file. I corrected my copy enough to make my code work.

Anyways, I was hoping that someone could check to make sure all the ones that say they take ITypeInfo**'s to be sure. I think most of them probably actually take ITypeInfo*'s.

adapted from DsourceTopic:2458 by dan.lewis

It looks like the d3d9 interfaces suffer from the same problem.

From Maybe wrong code in win32\d3d9.d by noob: I can confirm that and I don't think that is the only place in the code where it's wrong. What I've read and understood is that interfaces in D is always references and not pointers, so everywhere where it's an interface and a pointer (IName*) it should be just the name (IName) and where it's a pointer to a pointer (IName**) it should be just a pointer (IName*). The only interfaces I've checked with are IDirect3DDevice9 and IDirect3D9.

I think that NG:digitalmars.D/56630 refers to the same issue. -- JustinCalvarese, 2007/08/08

Is this going to be in Phobos?

The standard D distribution comes with a very incomplete windows module. I think it hurts the D's image. Phobos should come with no windows module or with a usable one (not necessarily complete, but usable). Is this project going to be incorporated into D distribution package?

I'm 100% your opinion. Slightly worse than that, the .lib-files for some windows dll's are very incomplete (for example ws2_32.lib and kernel32.lib are missing a lot of functions). So you have to convert them for yourself if you want to use them. Therefore I think we should include these files into the WindowsAPI project and respectively phobos too. I think the digitalmars.D newsgroup would be the right place to discuss this with Walter. Perhaps someone who is more fluent in english than me should propose that there. -- WeirdCat?

Yes, that is incomplete is the whole raison d'etre of this project. This stuff should go into when it's ready. As for the .libs, it's a known issue. AIUI there are two problems - getting hold of the files and being licensed to redistribute them. Only Walter can put them into the DMD package, but last time I knew he didn't have the files. This needs to change. Someone else here might have the files, but I'm not sure any such person has the licence. -- Stewart


I tried to compile a cut down version of winsamp.d But I got a compile error see below.

 C:\Test>dmd winsamp.d -I..\Win32 winsamp.def
 C:\dmd\bin\..\..\dmd\bin\link.exe winsamp,,,user32+kernel32,winsamp.def/noi;
 OPTLINK (R) for Win32  Release 7.50B1
 Copyright (C) Digital Mars 1989 - 2001  All Rights Reserved

winsamp.obj(winsamp) Error 42: Symbol Undefined _D5win327winuser13CreateWindowAFPaPakiiiiT5win325win nt6HANDLET5win325winnt6HANDLET5win325winnt6HANDLEPvZT5win325winnt6HANDLE --- errorlevel 1

The solution was to compile winuser.d to an obj file using:

 dmd winuser.d -I..\ -c

The compile this into a lib file using

 lib win32 winuser.obj

and finally link this into the winsamp

 >dmd winsamp.d -I..\Win32 win32\win32.lib

This is probably obvious to most people.
To build the win32.lib you can use the new makefile via "make" too (need a more advanced make like GNU make, the make from dm/bin/make.exe is to primitiv!), which creates a 2mb win32.lib with all the header files in it. To succeed at the current state you need to remove (or fix) the four files iprtrmib1.d, mswsock.d, vfw.d and winsock.d because they don't compile. -- WeirdCat?
Er what makefile? Am I missing something I downloaded revision #185 -- GilesBathgate?
Try the one with the name "makefile". :P -- WeirdCat?
%@!$%# Microsoft hiding file extentions and files which don't have one!

Talking of makefiles it would be handy if someone would like to convert my batch file into a makefile
Ive done it now


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: March 7, 2012 20:33 (diff))