2

I am wondering if it is both possible and how one would write an opensource version of the Windows API.

What I mean by this is, say you #include <Windows.h> in your C++ application. Then you make a call to ::CreateProcess(...). Now if you know what that function is supposed to do, what the function signature is and you implemented it yourself in a library that was cross platform could you then swap out the main Windows libraries with your custom one and run it on a different OS? The idea being that if you completely implemented the Windows API in a cross platform library, that you could run any Visual C++ application on a non-Windows platform.

6
  • 10
    yes - winehq.org – GrandmasterB Apr 19 '16 at 19:52
  • 3
    But you have heard of ReactOS? See reactos.org – Doc Brown Apr 19 '16 at 20:42
  • @DocBrown whoa reactos looks legit. Not quite the answer I wanted but I'm going to have to play with that. – tt9 Apr 19 '16 at 20:50
  • A lot depends on how much you expect to interact with the host OS. Is it just launching, and you're handling absolutely everything in a walled garden separate from the host, or do you expect deep integration with the host OS. (Which @DeadMG's answer assumes.) – Gort the Robot Apr 19 '16 at 21:13
  • @GrandmasterB Funny, I was about to use Wine as a "no" example. The Wine project has always been pretty clear about the severe limitations of what their compatibility layer can provide. – Mason Wheeler Apr 19 '16 at 21:23
4

Could someone write an opensource version of the Windows API?

Yes, but you are asking the wrong question!

Okay, after that teaser ;-) let's step back a bit.

The answer to the question "can someone write X" is almost always "Yes". Unless it is "No". Well, okay, that's not terribly helpful. Obviously, the answer to a Yes/No question is either Yes or No.

What I mean by that: there are some fundamental limits to computability. The most famous one is Alan Turing's Halting Problem. We have a rather simple mathematical function on the natural numbers. It's not quite as simple as addition, but pretty close: H(p, i) = 1 IFF program p halts on input i, 0 otherwise. That's clearly a function, and it's clearly within the natural numbers (we know that any sort of input, as well as programs themselves can be encoded as natural numbers, in fact, our modern computers show that they can actually be encoded using just the numbers 0 and 1). Yet, as Alan Turing proved, it is impossible to write a program which computes this function. Rice's Theorem is in a similar vein. There are lots of other similar results, most of which reduce or can be proven with one of those: Dead Code Elimination (impossible, equivalent to the HP), Class Hierarchy Analysis (HP), Escape Analysis (HP), and so on.

Basically, whenever you want to write a program to figure out something non-trivial about a program without running the program, that's impossible.

So, for those types of questions, the answer to "can someone write X" is always No. And that's a mathematical "No", not a "we could theoretically do it, but it's too hard/expensive/slow etc.". It's simply plain impossible. Period.

For pretty much all other questions the answer to "can someone write X" is always "Yes". In particular, in this case, you are not trying to statically analyze a program, so after what I said above, the answer should be "Yes, you can."

What you want to build could be called an abstraction layer, emulator, virtual machine (in the theoretic sense, not the "Java" sense), interpreter, adapter, translation layer, compatibility layer, or something like that (depending on how you look at it, and how you actually go about implementing it), and it is perfectly possible to do that.

In fact, all of this goes again back to Alan Turing, Alonzo Church and the very beginnings of computing. Alan Turing proved that there exist Universal Turing Machines that can take as an input the description of any Turing Machine and perform the computation of that Turing Machine. This is essentially the very first instance of an interpreter and the very first instance of a stored program computer, both before the very first actual interpreters and computers were built. Later, when the question arose whether Turing's Universal Machine or Church's λ-calculus were more powerful, less powerful, or equally powerful, it was proven that a Universal Turing Machine can compute anything λ-calculus can, by simply emulating λ-calculus, and λ-calculus can compute anything a UTM can, by emulating a UTM. The same thing was proven about other models of computation, such as μ-recursive functions, the SK combinator calculus, and so on.

In fact, for every model of computation (ignoring models that are purposely restricted, such as finite state machines) found so far, we have found that it can emulate all other models and can be emulated by all other models. This has led to the famous Church-Turing-Thesis: all models of computation are equally powerful. This includes even such physically complex things as Quantum Computers, and even physically impossible things such as Non-Deterministic Turing Machines.

So, what does all of this have to do with your question? Well, think of it this way: the Win32 API is kind-of like an abstract machine (again, in the more abstract sense, not in the "bytecode interpreter loop with garbage collection"). The POSIX API is also such a machine. And, as we have seen in history over and over again, one machine can emulate another machine.

This means that the answer to your question is "Yes, it's possible".

In fact, if you think about it, there already are different implementations of the Win32 API on different platforms: on 16-Bit DOS (Windows 3.x), 32-Bit Windows (Windows 9x/ME), and Windows NT. We can argue that WoW64 is a fourth implementation. In fact, we can argue that WoW64 is two implementations, since WoW64 on AMD64 works very different from WoW64 on IA-64.

However, like I said at the beginning: it's the wrong question!

The question you really need to ask is "How hard is it?" And I mean that both in the complexity-theoretic sense of the word and how much work you need to put into it, i.e. how complex the mapping between the two APIs is.

[Interestingly, this also applies the other way around to the "impossible" programs I mentioned above. Clearly, compilers do perform all kinds of static analysis on programs, including Dead Code Analysis or Escape Analysis. It's just that it is impossible to always do this. IOW, while there are infinitely many programs for which you can clearly determine whether something is Dead Code or not, there are also infinitely programs for which you simply cannot decide algorithmically one way or the other, and thus you have to include that code because otherwise the program might break.]

Again, let's look at the examples from above: yes, a Universal Turing Machine can emulate a Non-Deterministic Turing Machine, but the emulation overhead is exponential(!!!). And a Quantum Computer cannot compute more things than a Classical Computer, but it can compute some things much faster.

For the "mapping complexity", let's take C++ and C as examples: C can compute anything C++ can, and C++ can be mapped to the constructs of C. However, sometimes, that mapping is very direct (non-overladed C++ functions can be encoded directly as C functions), sometimes there is a little complexity involved (overladed C++ functions have to be encoded as multiple differently-named C functions, aka name mangling), and sometimes the mapping is completely non-obvious (e.g. the mapping of objects, classes, virtual member functions, and inheritance into C structs, vtables and dispatch functions).

That is, for example, the problem with Wine: they emphatically do not want to be an emulator (it's even in their name, Wine is not (an) Emulator), they want to rather provide a fairly simple 1:1 API translation layer. And as it turns out, this is possible for a large portion of the API, but impossible for some parts of the API that just cannot easily be mapped to POSIX. That does not mean that they cannot be mapped at all, it just means that within the design constraints the Wine team has set themselves, as well as the financial, resource and manpower constraints that are imposed on them by this pesky thing we call "the real world", there is no easy way to do it.

If you wanted to go about it a different way, i.e. allowing more complex translations and biting the bullet to do some emulation as well, you could go much further than Wine. The Mono team, for example, has implemented some .NET APIs in a portable fashion despite the fact that they are actually pretty tightly coupled to Win32. OTOH, they opted to not implement some other APIs because of their tight coupling (e.g. WinForms).

The way that this problem is typically approached is from both ends: translate the stuff that is easy to translate, re-write the stuff that isn't. There are some companies that have "ported" their applications to Linux by targeting Wine, and simultaneously joining the development of Wine and contributing patches to translate more functionality and at the same time re-writing those parts of their applications that use functionality that cannot be translated easily.

So, to answer your question again:

Could someone write an opensource version of the Windows API?

Yes, but the more complete and faithful you are going to make it, it's either going to be slower or more complex. In particular, if you try to map it to another high-level API that makes different trade-offs than Win32. (Otherwise you end up with something like ReactOS which maps the Win32 API to nothing more than a naked CPU, which makes it fast, because you don't have to have complex mappings in place, but much more code to implement, because you don't get to use the simple mappings.)

0

Not... really. You can implement most APIs that way but some of them fundamentally expose the model used by the operating system. For example, consider fork(), which basically has no possible Windows implementation.

In the general case, you can do, but for specific APIs, it may be that the underlying OS such as Linux simply does not offer that feature.

6
  • 1
    OK, fork would not work *nix --> Windows, but can you think of an example that would not work Windows --> *nix. – Mike Apr 19 '16 at 20:41
  • 1
    If its not possible to implement fork() on Windows, what of the much-ballyhooed "Ubuntu on Windows 10" feature, which was reportedly created by implementing all of the basic Linux system calls on top of Windows? Seems to me that would simply not work at all if they didn't have a working fork()... – Mason Wheeler Apr 19 '16 at 21:25
  • I believe you can't fork() Windows processes from the bash shell. I think this answer is weak, because technically you can re-implement everything if you wall yourself off from the host OS and build from first principles. In the case of fork(), this would mean creating your own scheduler. – Gort the Robot Apr 19 '16 at 21:47
  • 1
    Technically you can, but fuck actually doing that. Just spin up a VM instead. – DeadMG Apr 19 '16 at 21:52
  • 1
    if fork(0 can't be implemented on windows, and you're making an open source version of the windows api on windows, what does it matter? – Bryan Oakley Apr 20 '16 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.