11 ms·
Microsoft Opens Up Old Win32 APIs to C# and Rust
- rkagerer 6y agoThis may be several years late but is nonetheless great news!
- logbiscuitswave 6y agoClickbait title isn’t really accurate. You’ve always had this ability by using P/Invokes, but it’s never been easy. It requires a lot of domain knowledge (or copy-pasta that may cause other problems) to actually get it to work. It’s also very easy to get wrong and cause big memory leaks in the unmanaged heap. Over the years I’ve managed to get pretty good at P/Invokes to the point where I don’t bat an eye when I need to do some interop with native code. That doesn’t mean I don’t sometimes run into a particularly finicky API that requires digging deep into stuff like GC pinning, structure packing, fixed pointers, or other challenges that will grind things to a halt while I debug what’s happening. At least I’ve come to the point where I can look at unexpected API behavior and have a good intuition for what I need to do. It sucks, a lot. I’m really glad that there’s finally an official and reusable abstraction to make this simpler in the future.
- kerng 6y agoI do remember depending on the site pinvoke.net quite a bit in the past - but yeah this was always possible with C#. It was even what made J++ (Microsoft's Java, before it became C#) unique compared to Sun's version in the 90s, as it allowed this kind of tight Windows integration also if I recall correctly.
- sedatk 6y agoDidn’t JNI allow that kind of integration?
- DaiPlusPlus 6y agoI think it was because MS’ Java’s standard libraries included Java wrappers over Win32 already, so programming beginners in Java can make “real”-looking Windows desktop GUI applications without knowing any C or at least knowing how to read *.h files and translate them to Java.
- josefx 6y agoMicrosoft had RNI which was comparable to JNI and could be used to write native code. It also had J/Direct which could be used to bind existing native code to a Java method declared native with only a comment, the closest to that for standard Java that I know of is JNA and apparently that wasn't around until 2007?
- int_19h 6y agoJNI is a bit different - you have to write code in C or C++ that wraps native APIs you want to call, in a certain very specific way that then makes it possible to call it via methods declared as "native" in Java. P/Invoke does not require such a layer - you simply declare enums, structs, and functions from the native API directly in your C# code, and then you can call them. For those familiar with Python, the Java way is more like writing a Python extension module in C, and the C# way is more like using ctypes (but way faster). Java has some third party libraries that are basically P/Invoke equivalent; JNA is probably the most used one.
- sn_master 6y agoIt was also possible in VB6, planet-source-code was the best source for that..
- buckminster 6y agoYou could even call the win32 api from 16-bit VB3 by going through the wow thunking api. It worked well but the declarations were quite hairy.
- sn_master 6y agoyup, you could even have multi-threads, hide inside other processes and run from there and all the C++ fun stuff..
- sandermvanvliet 6y agoMy approach has always been to create a separate dll (written in C++) that wraps all the complicated stuff and has only a few calling points exposed which were P/Invoked from the C# side. Haven’t had to do much of this but that definitely saved me from doing a lot of clunky stuff in the C# app
- yread 6y agoP/Invoke is not that bad - you basically just copy the c header declaration and adjust a bit. It starts to be interesting strings or large memory where you want to avoid copying it too much. Doing it cross-platform is a bit of pain (basically copy everything and point it to different library - .dll vs .so) it would be nice if there was a better way. I still haven't figured out how to get unicode strings to work cross platform though.
- int_19h 6y agoOne trick is to avoid smart marshaling (for C# strings, arrays etc), and use "unsafe" and raw pointers. This way, all your types are what CLR calls blittable - i.e. their representation is the same in native and managed - and the behavior is straightforward and predictable, as no copying or implicit conversions occur. This is particularly useful for cases when you have something like a struct containing a pointer to a struct containing a string, and when ownership of memory is unclear. Of course, the downside is that you have to do all the marshaling yourself then. E.g. for strings, you use the appropriate System.String constructor to create one from a raw pointer - it has overloads for null-terminated string pointers as well as pointer + length, and you can specify encoding too. Or, to pass the string to native, you pin it using "fixed" to obtain a pointer.
- skeletonjelly 6y agoVery interesting! Do you have a link or quick example you could please share?
- int_19h 6y agoIf you have any specific Win32 API in mind, I could write up a snippet to invoke it in this manner.
- spaetzleesser 6y agoI am pretty good about writing P/Invokes but I have no way of proving that what I did won’t create some memory overwrite or leak. Too many moving parts between C# and C++. Nowadays I find it better to write a layer in managed C++. This seems much safer and in a sense is more straightforward.
- munchbunny 6y agoAgreed, given the choice between P/Invoke and managed C++, managed C++ often has fewer footguns, despite being rooted in C++. You have the compiler checking your usage of the native API, and you have the compiler generating .NET interfaces which your managed code can invoke directly.
- mlazos 6y agoFor me I had a single mixed managed/native DLL which made my life a lot easier when dealing with interop. The documentation for C++/CLI was really good IMO. I wasn’t marshaling particularly complex types though so had pretty simple pinning scenarios.
- simplicio 6y agoThe first two paragraphs are wrong, aren't they? My understanding is that the "32" in Win32 was originally to distinguish 32 bit from 16 bit API calls, but now its just the generic name for the Windows API. The article makes it sound like the change is only of interest if you're compiling 32-bit applications.
- jarjoura 6y agoWin32 is the consistent branding Microsoft has used to describe its C/C++ API for the last 20 years. It's many things though, GDI, User32, NT, DirectX, etc.
- OnlyOneCannolo 6y agoIt's an error of omission in that Win32 also refers to the 64-bit versions. The Windows API includes but is not limited to Win32. https://docs.microsoft.com/en-us/windows/win32/ https://docs.microsoft.com/en-us/windows/win32/
- simplicio 6y agoYea, that was my understanding. But its not an error of omission, the article specifically stresses its the API for 32 bits twice in the first two sentences of the article.
- OnlyOneCannolo 6y agoThey're wrong because they didn't realize they left something out of a partially true statement. That's an error of omission.
- jarjoura 6y agoThere is a performance penalty when accessing APIs over WinMD and that is acceptable when you're only using them sparingly. I'd be curious how using Win32 APIs over WinMD performs instead of using PInvoke or FFI. Edit: Here is the actual project if anyone is interested in following along. https://github.com/microsoft/win32metadata/ https://github.com/microsoft/win32metadata/
- WalterGR 6y ago> There is a performance penalty when accessing APIs over WinMD Specifically when using WinMD? Why? Or do you mean vs. calling the APIs directly via C code, or vs. using in-language techniques such as P/Invoke?
- int_19h 6y agoIt only uses WinMD as the format for metadata input for code generation. The output for C# is still a bunch of P/Invoke declarations (using Roslyn source generators). By the way, .NET is also retiring the ability to use WinMD directly via runtime projection, in favor of code generation: https://github.com/microsoft/CsWinRT https://github.com/microsoft/CsWinRT
- deleted 6y ago[deleted]
- userbinator 6y agoIt's funny to see MS do this after all those years of messing around with various other bloaty UI frameworks... and further reaffirms my decision to stay with pure Win32. Perhaps MS is encouraging developers to native UI after all.
- int_19h 6y agoWinRT is not going anywhere. What more, it's usable from classic Win32 apps these days. https://github.com/microsoft/ProjectReunion https://github.com/microsoft/ProjectReunion
- userbinator 6y agoThe software may collect information about you and your use of the software and send it to Microsoft. The "new Microsoft" is still there for sure...
- 29athrowaway 6y agoFor widgets and windows... I prefer to use GTK, which has a much easier learning curve, and works on multiple platforms, and works well with HiDPI. Win32 uses hungarian notation, which is not common these days. The thing was designed for a time in which programming tools had almost no autocompletion and were slightly better than a text editor.
- quelsolaar 6y agoThis is awesome news. We need platforms to be language agnostic. The best way to do this it to make it possible to query the entire API so that you can automate the warping of other languages. Apples Coca APIs can be queried, and at one point i considered writing a C API generator. My guess it would take a week or two, but at the time I was busy and spending 2 weeks in XCode, wasn't really my idea of good time. Some one should do it.
- unnouinceput 6y agoMicrosoft should bite the bullet and simply create another operating system, created from scratch. They have the experience and the know how to avoid all the mistakes. Offer them in parallel, keep a virtual machine (an Wine equivalent if you want) that would run Windows programs and overall simplify the API's while only the new one would receive new developing. And in 10 years Windows would be history. I know it won't happen but once can only dream though.
- Philadelphia 6y agoThey tried https://en.wikipedia.org/wiki/Midori_%28operating_system%29 https://en.wikipedia.org/wiki/Midori_%28operating_system%29
- masterofmisc 6y agoI would love to know why Midori failed and the reasons why they decided to discontinue it. It would be a great war story to read (if a Microsoft employee was allowed to write it up). I love the idea of starting a new modern OS written from the ground up with security and safety in mind sound. However, it looks like Microsoft took a different direction with WindowsX. Instead, it looks like they have taken a bold leap and hacked out all of the Win32 guts from Windows to make it a Chromebook competitor. And the talk on the town is, further down the line, they will re-add Win32 back in as a virtualised service (i guess kinda like WSL2) so its completely sandboxed from the rest of the OS.