Just for you, lucky Spanish user, GCC 3.0.4 for Windows NT (MinGW)

From Spain!

I cannot understand why you want this, or why I’m even going to do it.  At this point in GCC history the winnt-3.5 target had been dumped in favour of going all in with Cygwin.  So yeah, this does not either clearly configure, or compile.  But a little bit of mashing files, and I have it at least compiling some assembly that can be translated into an object file that a later version of MinGW can actually compile.

All I’ve built is the gcc driver, the cpp pre-processor, and the cc1 aka C backend.

D:\proj\gcc-3.0.4\gcc>xgcc -c -v hi.c
Using builtin specs.
Configured with:
Thread model: single
gcc version 3.0.4
 cc1 -lang-c -v -iprefix ../lib/gcc-lib/i386-winnt35/3.0.4/ -D__GNUC__=3 -D__GNUC_MINOR__=0 -D__GNUC_PATCHLEVEL__=4 -Dunix -DWIN32 -D_WIN32 -DWINNT -D_M_IX86=300 -D_X86_=1 -D__STDC__=0 -DALMOST_STDC -D_MSC_VER=800 -D__stdcall=__attribute__((__stdcall__)) -D__cdecl=__attribute__((__cdecl__)) -D_cdecl=__attribute__((__cdecl__)) -D__unix__ -D__WIN32__ -D_WIN32 -D__WINNT__ -D_M_IX86=300 -D_X86_=1 -D__STDC__=0 -D__ALMOST_STDC__ -D_MSC_VER=800 -D__stdcall=__attribute__((__stdcall__)) -D__cdecl=__attribute__((__cdecl__)) -D__cdecl__=__attribute__((__cdecl__)) -D__unix -D__WIN32 -D__WINNT -D__ALMOST_STDC -D__cdecl=__attribute__((__cdecl__)) -Asystem=unix -Asystem=winnt -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i386__ hi.c -quiet -dumpbase hi.c -version -o C:\Users\jason\AppData\Local\Temp\ccpflisr.s
GNU CPP version 3.0.4 (cpplib) (80386, BSD syntax)
GNU C version 3.0.4 (i386-winnt35)
        compiled by GNU C version 5.1.0.
ignoring nonexistent directory "../lib/gcc-lib/i386-winnt35/3.0.4/include"
ignoring nonexistent directory "../lib/gcc-lib/i386-winnt35/3.0.4/../../../../i386-winnt35/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/include"
ignoring nonexistent directory "NONE/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/lib/gcc-lib/i386-winnt35/3.0.4/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/lib/gcc-lib/i386-winnt35/3.0.4/../../../../i386-winnt35/include"
ignoring nonexistent directory "/usr/include"
#include "..." search starts here:
End of search list.
<command line>: warning: "__STDC__" redefined
<builtin>: warning: this is the location of the previous definition
<command line>: warning: "__STDC__" redefined
<command line>: warning: this is the location of the previous definition
hi.c: In function `main':
hi.c:3: warning: return type of `main' is not `int'
 as --traditional-format -o hi.o C:\Users\jason\AppData\Local\Temp\ccpflisr.s

D:\proj\gcc-3.0.4\gcc>gcc hi.o -o hi

Hello from GCC 3.0.4

So there you go, mysterious internet user!  Download my source dump with binaries in the tree because I’m lazy.


OpenNT – Windows NT 4.5

(This is a guest post from Tenox)

Just stumbled across this: someone has forked Windows NT 4.0 and created an open source version of it. But wait, forked what? Windows source code doesn’t live on Github. Is it ReactOS? No! Upon some digging, it was apparently born from the leaked source code of NT4.0, some W2K bits and 2003 WRK.

Enter NT version 4.5:

NT45Test-2015-04-27-18-20-37More screenshots here: http://www.opennt.net/projects/opennt/wiki/Screenshots

The main project site: http://www.opennt.net/

Looking at activity the project seems to be alive and well. There is some background information and discussion going on BetaArchive for those interested.

I wonder what Microsoft has to say about this 🙂

Loading NT 4.0 & Windows 2000 on Hyper-V

In this attempt to get NT 4.0 running on my machine, here is what I did. This holds true for 2008r2, and 2012 along with the Windows 10 preview.

old versions of Windows are not supported, but with a little bit of fun from PowerShell you can get them to work.

First make sure you run PowerShell as Administrator!

PS C:\WINDOWS\system32> get-vm

Name State CPUUsage(%) MemoryAssigned(M) Uptime Status
—- —– ———– —————– —— ——
NT40 Off 0 0 00:00:00 Operating normally
Windows 2000(wks) Off 0 0 00:00:00 Operating normally

As you can see here I have two virtual machines.  Both of them are ‘off’ since there is no memory assigned, nor is there any uptime.  It’s weird to me how they are “Operating normally’ since they aren’t running but I guess that’s a feature.  Make sure the VMs are powered off before trying to do this.

Restricting the CPU capabilities was the checkbox to enable in the first version of Hyper-V.  Now it’s hidden from the user, so you need to enable this in Power Shell.

First let’s check a VM:

PS C:\WINDOWS\system32> Get-VMProcessor NT40 | fl CompatibilityForOlderOperatingSystemsEnabled

CompatibilityForOlderOperatingSystemsEnabled : False

As you can see it’s disabled.  Now to enable it with:

PS C:\WINDOWS\system32> Set-VMProcessor NT40 CompatibilityForOlderOperatingSystemsEnabled $true

Now we can verify it’s turned on:

PS C:\WINDOWS\system32> Get-VMProcessor NT40 | fl CompatibilityForOlderOperatingSystemsEnabled

CompatibilityForOlderOperatingSystemsEnabled : True

And we are good to go.

NT 4.0 Service Pack 6 on Hyper-V / Windows 10 Technical Preview 9879

NT 4.0 Service Pack 6 on Hyper-V / Windows 10 Technical Preview 9879

Now for the networking part, remember to remove the existing network adapter, and add the ‘legacy’ network adapter.  On my PC there was an additional snag, which is that every time a VM reboots, or is powered on the legacy adapter will receive NO packets.  Go into the Hyper-V console, and disconnect the legacy adapter, and reconnect it, and network traffic will flow.

And additional note on installing Windows 2000.  You *MUST* change the HAL uppon instalation.  By default it’ll detect an ACPI system, but the driver ACPI.SYS will bluescreen the VM.  Hit F5 when it prompts about storage adapters, and select the ‘STANDARD PC’ HAL from the list.

8086tiny 1.25 has been out for a while

now, and I figured I should see if I can get it running on NT 4.0…

There was some minor issues with the way it handles for loops, but making them more C89 friendly was trivial.

8086tiny on NT 4.0

8086tiny on NT 4.0

You can download my project (source and binary) here.  The ‘killer’ feature is that it being built with Visual Studio 97 on NT 4, the needed Visual C++ LIBC DLL ought to be in place on anything modern these days.

You can always find the home page for 8086tiny, right here, at megalith.co.uk.  Code is maintained on github.

MSMQ 1.0

Building on my ‘has anyone ever used’ this feature of the NT 4.0 option pack‘, I thought it’d be interesting to build a simple MSMQ deployment.  MSMQ is another technology I never saw deployed, as everyone was instead far more interested in MTS.  So I thought I’d take a stab at MSMQ.

The only deployment guide I can find is here.

And I have to say, that it looks and feels a *LOT* of what became Active Directory.

So let’s look at a few things through the guide.

Top features of MSMQ are:

  • Connectionless messaging. With store-and-forward message queuing, applications are not affected by network fluctuations and do not have to establish sessions. Because MSMQ uses a sessionless model at the application level, the sender and receiver do not need to support the same protocol. MSMQ supports Internet Protocol (IP) and Internet Packet eXchange (IPX).
  • Network traffic prioritization. Message prioritization allows urgent or important traffic to preempt less important traffic so you can guarantee adequate response time for critical applications at the expense of less important applications.
  • Guaranteed delivery. Messages can be logged to a disk-based queue to provide guaranteed delivery.

Which for 1997 technology sounds pretty great!  But obviously what is the cost?  To deploy MSMQ you *NEED* the following:

  • Install a PEC (Primary Enterprise Controller).
  • Install a PSC (Primary Site Controller) at each additional site
  • Define site links and costs
  • Install MSMQ dependent clients and independent clients

Optionally you can install for greater redundancy and speed..

  • Install a BSC (Backup Site Controller) at each site, if required
  • Install MSMQ routing servers, if required
  • Install the connectors and transports, if required

As you may guess MSMQ needs a server infrastructure of it’s own.  I thought for my limited experiment, I would use a simple two site network, comprising of a Windows NT 4.0 PDC, a Windows NT 4.0 BDC and two Windows NT 4.0 workstations.

As MSMQ stores it’s topology database in SQL Server 6.5 service pack 3, I found out the hard way that It will not install correctly with SQL Server 7.  Nor will it work with sp1, and it’ll bomb with 2.  It must be SP3.  I’ve also found it works best with the ‘restricted’ cut down version specifically for MSMQ.  Which is on CD2 of the Enterprise edition of Windows NT 4.0 (I stuck a copy here).  Basically it’s 6.5 slip-streamed to SP3, with no books (don’t’ try to install the books!).  However I found it works best on the PDC, and installing it on a BDC you should set the SQL services to login as local system for the installation, then set them for a domain account.  I also had to change the security model to “Windows NT Integrated”.  I’m not sure if that is 100% a requirement, but the installer demanded it.


Setting SQL’s security to Integrated mode

With that out of the way, I ran setup from the option pack, selecting MSMQ.

Select MSMQ

Select MSMQ

And the install proceeds as normal installing the base components of IIS 4.0.

Select a MSMQ type

Select a MSMQ type

Then we get to decide what kind of Server this Server will become.  The first server I installed this on was the PDC, so I made it the PEC.  It installed without any further incident.

I installed the option pack on the BDC, which was located in a different network, and set it up as the PSC.  I then installed the workstation option pack on both of my workstations making them independent clients, and assigning them to their closest PEC/PSC.

MSMQ Enterprise

MSMQ Enterprise

As you can see the Enterprise view of MSMQ looks a LOT like the AD Sites and Computers view.  No doubt MSMQ was on the way to Cairo.. Although I’ve always thought Exchange would have been better served by SQL, having directory services being hosted on SQL would have made life a bit easier for doing backups and restores, making it less of a black box.  However the prospect of managing all those SQL servers.. I guess there is always trade offs.

MSMQ in action

MSMQ in action

This is a small ‘demo’ application where MSMQ can pass messages between a shared paintbrush application.  Very cool stuff.  And no doubt a missed opportunity to run something fun and subversive.  Although I was always the network admin so I never had to hide my traffic.

I’ve setup MSMQ in 2000 & 2003 networks, and it is not only far more simpler to deploy, but it relies on Active Directory to figure out it’s topology, and nominated MSMQ servers to forward traffic between sites.  I’m more surprised that AD doesn’t rely on MSMQ, but rather it seems it uses common technology.

Have you ever used the NNTP service that comes with NT 4.0?

and higher?  It was part of the Option Pack, and later incorporated into the OS starting with Windows 2000.

I’ve always seen people mistakenly install it, but I don’t think anyone ever really used it, as it cannot feed from other servers, and is really all around inept.  Then I stumbled onto this post, from 1998, which mentions that you can feed NT’s NNTP with a 3rd party program, and then he gives a simple example written in perl.

Now the program hinges on the NEWNEWS command.  Although I’m sure with a little perl knowhow it could work with the normal user list commands, as it would then need a database of what messages it has already transferred.  I was interested in taking a peek of MS NNTP in action, so I installed a copy of NT 4.0 in Qemu, redirected port 119 (which needs elevated privileges).  The next thing you need is a news server.  Once upon a time netnews was a feature of your ISP, and they would keep local news servers to reduce network loads.  But times have changed, and now Netflix and it’s cache boxes are the bandwidth kings, as people want to turn the internet into VOD.  But whatever.  Finding a news service requires some googling around, and the one I found that is the best deal (free), text groups only (yay!), and it’s online stores go back at least four years is Eternal September. Another contender is Aioe, which doesn’t require a user id.  Since I’m going with eternal september, I had to create a userid, get the password in the mail, and then I was able to do a group listing.

I made a small change to this section of the perl program:

#Open connection to Master and slave
$nntp = Net::NNTP->new($NNTPMASTER, Debug => $opt_debug ? 1 : 0) or die “no connection: $!”;
$nntps = Net::NNTP->new($NNTPSLAVE, Debug => $opt_debug ? 1 : 0) or die “no connection: $!”;

#$nntp->authinfo($usr,$pw) or die “Could not authenticate $usr”;

This lets me know if there was an error connecting to the servers, and of course inserting in the username/password.  Since we don’t have the newnews command at hand (I don’t see how to pay for it either..) I just did a simple one line change to grab a whole group.  Obviously you wouldn’t set this up on cron.

#Uncomment line 2 for an initial feed… after this, run as an “At” job every 24 hrs.
#$new = $nntp->newnews(time – 86400, lc $group);
#$new = $nntp->newnews(time – 31536000, lc $group); #initial feed – 1 YEAR
$new = $nntp->listgroup($group);
if(ref($new) && scalar(@$new))

But if my perl-fu was stronger I’d whip it up, but I suspect it wouldn’t be too hard to have the script maintain what is the last message it’s posted to NT.

Next create the groups on the NT side, and we are ready to run.  I foolishly tried a massive (well it seemed big) group comp.os.linux.advocacy, and after some 10,000 posts I just aborted it, and set the script to manually updates groups of my choice.  I remembered an ancient article about writing socket software on Windows, and the small group alt.fan.surak, which I figured would make a better test.  There is only one article and it’s spam, but what can you expect..



Even better, it worked!

The next step was to run perl directly from NT.  And to make this difficult, not only do I need an obsolete version of perl, but I need one with the optional network modules, specifically Net::NNTP.  This took a bit longer to find, but thankfully Jeffery Baker kept his build around!

There really wasn’t an install program, but rather adding the perl.exe into the path.  And it works, too!

Perl feeding MS NNTP

Perl feeding MS NNTP

So there we go, after all these years, 100’s of option pack installs later, and I’ve finally used it.

Running Microsoft Exchange from home.

Well thanks to my latest outage, I’ve gone back from having an Exchange server in the “cloud” (well really a server I rented), to a Virtual Server at home.

First my ‘plan’ is to get a VPS that I can run OpenVPN on.  From there I’m going to build a VM at home that will also run OpenVPN, and it will connect to the VPS.  I will then setup routing, so that the Exchange server can then communicate with the VPS’s internal interface, and the VPS can communicate directly with the exchange server.  I’ll then configure postfix to store & forward email to the Exchange server.  This way if the link drops, the VPS will just spool the mail.  Finally I’ll setup SpamAssasin to filter out the SPAM.

First you will need to have a tun0 interface in your VPS.  Almost everyone supports this these days so it shouldn’t be too hard… If you cannot get a tun0 interface, perhaps ppp0 with pptp..?

I followed these instructions on setting up OpenVPN on Debian 6.  Now granted, I’m using Debian 7, but the instructions are pretty much the same.  Basically you have to setup a CA (Certificate Authority), and then you generate a Server certificate, and a client certificate.  For my needs, I’m going to issue single certificates for everything(one) that connects into my VPN.  I also have a network at home that I want routed to the VPS, so this is included (

A simple server.conf looks like this:

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
dh dh1024.pem
ifconfig-pool-persist ipp.txt
client-config-dir ccd
keepalive 10 120
status openvpn-status.log
verb 3

And a the client configuration I’m using is this:

dev tun
proto udp
resolv-retry infinite
ca ca.crt
cert hong-kong-home.crt
key hong-kong-home.key
ns-cert-type server
verb 3

In the directory /etc/openvpn/ccd on the server, I have to ensure that I have a file called ‘homefw’ which is the common name of the client certificate.  It has to contain the following line to ensure that my home network is routed to the VPS.


Don’t forget to turn on ip forwarding on both the VPS, and the local ‘tunnel router’.  For Linux based stuff you need to make sure that “/proc/sys/net/ipv4/ip_forward ” is a 1.  You can just do a simple “echo 1 > /proc/sys/net/ipv4/ip_forward ” in “/etc/rc.local” or go through your distributions networking documentation to make sure you set it up ‘correctly’.

In OpenBSD I just simply uncomment the following line from /etc/sysctl.conf

net.inet.ip.forwarding=1 # 1=Permit forwarding (routing) of IPv4 packets

If you don’t have routing in place you’ll notice that you can only ping the tunnel interfaces, but not the IP’s on the LAN.  While this may be fine for a p2p or client setup it isn’t good enough if you want to route traffic.

I’m running VMWare ESXi 5 at home, and thankfully it does support Windows NT 4.0 Server out of the box.  I setup a Domain Controller running DNS & WINS.  The VMWare tools won’t work properly with some service pack (4 I think?) but I went all the way to 6, along with the rollup.  Until you load the service pack, the network adapter will *NOT* work.

I’m going with Exchange 5.5, so again I installed another NT 4.0 server, service packed it, and joined it with the domain controller.  Remember to install IIS, and the ASP update, as 5.5 OWA needs asp. Be sure to apply the latest service pack for Exchange, SP4 – in the case of Exchange 5.5 .

Now for routing I could go with dynamic routing, or static routing.  I chose static as I didn’t want to get too involved for this project, as I needed to get email flowing as quickly as possible.

route add mask -p

From Windows NT.

It is imperative no matter what version of Exchange you run, that you turn off the open relay “feature”.  A great step by step guide is available here on msexchange.org .

With the basic routing in place you should be able to talk to the Exchange servers’ SMTP engine.  You may want to setup either a local DNS and populate the VPS’s source address or put in some host entries for it.

# telnet 25
Connected to
Escape character is ‘^]’.
220 exchange.superglobalmegacorp.com ESMTP Server (Microsoft Exchange Internet Mail Service 5.5.2653.13) ready
250 OK

Now it would be insane to place an Exchange server directly onto the internet.  Plus when the VPN link is down, it’d be nice to have the VPS store email and forward it when it can.  So for this task I installed postfix.

For me the big changes in main.cf were:

mydestination = nodedeploy.superglobalmegacorp.com, localhost.superglobalmegacorp.com, , localhost
relayhost =
mynetworks = [::ffff:]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
relay_domains = superglobalmegacorp.com work.com
transport_maps = hash:/etc/postfix/transport
virtual_alias_domains = virtuallyfun.com
virtual_alias_maps = hash:/etc/postfix/virtual

This will permit my exchange server to relay out my VPS, and tell postfix that it’s OK to accept email for the various domains I have.

My transport database is very simple.  For the email accounts I’m using two domains, so I simply instruct postfix to forward emails destined to these domains to the exchange server

superglobalmegacorp.com smtp:
work.com smtp:

And for domains I couldn’t be bothered to create mailboxes for, instead I have their email setup to forward to an existing box using a virtual domain in the ‘virtual’ file.

abuse@virtuallyfun.com abuse@work.com
postmaster@virtuallyfun.com postmaster@work.com

Now due to the nature of postfix you need to generate database hashes for it to work, so my script to kick this off is:

postmap hash:/etc/postfix/transport
postmap /etc/postfix/virtual
postfix reload

Which isn’t too involved once you get the bits in the right place.

Assuming you’ve got your MX records setup on the outside, with any luck you should start seeing some mail flow through.  If not telnet to port 25 and start talking to your mail server.

One problem I have is that superglobalmegacorp.com is an old domain, and it’s lapsed a few times to different idiots who not only added to the ridiculous spam lists I’m on, but also spammed from it as well.  So to deal with SPAM, I went ahead and installed spamassassin, as described in this page.

As mentioned adding the two lines to master.cf got it going

smtp inet n – – – – smtpd -o content_filter=spamassassin -o syslog_name=postfix/submission
spamassassin unix – n n – – pipe
user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

And I did change the spamassasin local.cf

use_razor2 1
use_dcc 1
use_pyzor 1

As I do get a lot of spam.

I don’t think most people will care, but this is more so for me keeping my notes straight.  So yeah I run Exchange 5.5 at home (which I got on ebay for $25!) with Outlook 2003 on Windows XP x64.  It works well enough for me.

Restoring the MIPS Magnum in Qemu 1.6.0

As many of you Windows NT MIPS fans may know (apparently there are more than 3 of us now!) the MIPS Magnum target is broken in the current build of Qemu.  The problem lies in the firmware as it accesses unassigned memory.  Luckily I just received an email from Hervé that details how to fix this!

The good news is that the fix is VERY easy, all you need to do is comment out a single line in target-mips/op_helper.c

In the function mips_cpu_unassigned_access:

void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
bool is_write, bool is_exec, int unused,
unsigned size)
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;

if (is_exec) {
helper_raise_exception(env, EXCP_IBE);
} else {
helper_raise_exception(env, EXCP_DBE);

Simply comment out the line

helper_raise_exception(env, EXCP_DBE);

And you’ll be able to boot up the NT PROM.

MIPS Firmware

MIPS Firmware

Remember you’ll want to run it something like this:

qemu-system-mips64el -L /tmp -M magnum -m 64 -cdrom WindowsNT4.0-MIPS.iso -hda MIPS.disk -net nic -net user -global ds1225y.filename=nvram  -global ds1225y.size=8200

Where I’m keeping my NT PROM is /tmp (although that is probably a bad idea…)  But you’ll need the NVRam stuff to add extra space for the ethernet MAC address.  The clock is always trashed but at least it is doing something this time!

For the uninitiated, some installation notes can be found here.

Installing Windows NT 4.0 on Proxmox/VE



Ok, Ok I know 99% of the world won’t care, but here we go.  I just setup a Proxmox/VE server on a friends PC, and felt like installing a NT 4.0 Terminal server.. So after getting the ISO onto the server, I went through the setup to get a quick blue screen.  Much like Qemu, KVM won’t work out of the box, you have to first nudge the CPU level down to ‘pentium’ or 486, and for the install you have to disable the KVM (accelerated) version, and use the generic Qemu installer.

Also I would alter the config file, along with a global config to turn on the AMD PCNet network adapter.

In the  /usr/share/pve-manager/ext4/pvemanagerlib.js file, just go ahead and add in your NIC’s entries:

[‘rtl8139’, ‘Realtec RTL8139’],
[‘e1000’, ‘Intel E1000’],
[‘pcnet’, ‘AMD PcNet’],
[‘ne2k_pci’, ‘NE2k PCI’],
[‘virtio’, ‘VirtIO (paravirtualized)’]

And in the /etc/pve/nodes/proxmox/qemu-server directory, you will see stuff like 100.conf, and look for a line like this:

net0: rtl8139=56:65:DB:52:7F:F2,bridge=vmbr0

And change it to the AMD PCNet ..

net0: pcnet=56:65:DB:52:7F:F2,bridge=vmbr0

See, easy right?  Then you can mount up your ISO, and install!

Once you’ve installed, and applied service pack 6, you can then turn on KVM acceleration, although I’d leave the CPU level knocked down to a Pentium.


NT 4.0 Terminal Server on Proxmox/VE

NT 4.0 Terminal Server on Proxmox/VE

So far, so good, yay!

Aclock BSOD

This is a guest post by Tenox.

Do you remember the famous Windows NT Blue Screen Of Death? For years it was a source of jokes and bad reputation of Windows reliability.
There even was a Blue Screen Saver. Today we fortunately see much less of it, but it still is there, reminding us that Windows internally is in fact a text mode operating system. The 1989 NT Design Workbook tells us that in the early days of development there was an ANSI terminal emulator and bunch of command line utilities running in the text mode. Sadly all were removed in the retail version. The only true text mode application left around was autochk. Since the day Aclock was conceived I always wanted to run it on the NT text mode boot screen. In it’s twisted logic it actually makes a perfect sense.

So how do you actually output to the BSOD screen? Initially there was a lot hope in Windows NT Native Application, which can use NtDisplayString() function to display text before GUI takes over. Mark Russinovitch has written a sample Native Application with source code. Unfortunately I soon realized that NtDisplayString()does not allow for any control characters that would let me position the cursor or clear the screen. It doesn’t let much more than to display “Hello World” during Windows boot. This unfortunately wasn’t what I was hoping for. Out of lack of further ideas the project was shelved for nearly 10 years until I recently got some help from a real windows insider.

The new hope came from a HalDisplayString() and it’s helper functions HalQueryDisplayParameters() and HalSetDisplayParameters()which return screen resolution in characters and allow to position the text cursor. Exactly what I needed! However these functions are part of the NT Kernel and there was absolutely no hope of calling them from user mode, even a Native application.

So a device driver version of Aclock was conceived. Err WHAT? Yes a Windows Kernel Mode Device Driver version of Aclock. It sounds like craziest idea and most ridiculous waste of time ever. Worse than that, it definitely is! Despite that, development of the driver was actually surprisingly straight forward and the most difficulties I had was to do with setting up the right environment. It required Windows NT 4.0 SP6, an old version of NTDDK, SDK and Visual Studio. Once I had the project set up correctly, the only thing left to do was to figure out the kernel mode equivalents of some of the things I was getting for granted, for instance sleep(). My last surprise was rather unexpectedly difficult access to floating point in the driver. I was advised to avoid, so I have generated a pre computed tables of sin and cos values for every minute on the clock dial.



I must say that VMware Workstation Snapshots came very handy for launching and testing of the driver. It spared me from constant rebooting and re-launching the whole environment. I could load aclock and literarily click “back” like in a web browser.

Here is a link to the binary, source and project files.

Since running the driver on your own system will render it unbootable (you can always do a snapshot or use last known good configuration) I have build a minimal Windows NT Embedded (NTe) image that loads the driver on startup. It’s available as VMware machine, and a Qemu image.

Windows NT Embedded project


The next steps may involve porting AA-Lib to NTHAL. From there the possibilities are unlimited aalib-quake? 😉

Update:  Video

Aclock Windows NT BSOD Driver from Antoni Sawicki on Vimeo.