views:

203

answers:

3

Everybody who used P/Invoke of Windows API knows a long list of declarations of static functions with attributes like

 [DllImport ("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

The declaration of structures copied from Windows headers like WinNT.h or from web sites like www.pinvoke.net take also a lot of place in our programs.

Why we all have to spend our time for this? Why Microsoft not give us a simple way to include a line like in old unmanaged programs

#include <windows.h>

and we would be have access to a static class Native with all or the most Windows functions and structures inside?

UPDATED based on some answers:

It you will be honest with yourself, which part of your .NET programs are running not under Windows? 5%? 1%? If you use WMI, Process, Registry or ServiceProcess.ServiceBase classes etc. in .NET is your program so “platform independent” and more “compatible” if you not use native API? Has Thread.ApartmentState everywhere sense out of Windows?

Usage of SafeHandle or try {…} finally is of cause required. I would be happy to have a standard definition of Native API in any of these forms.

I know that some structures in windows.h have different versions 32/64 or XP/Vista etc. I think it would be enough to have also different version of Native structures like MIB_IPADDRROW_XP and MIB_IPADDRROW_W2K or IMAGE_NT_HEADERS32 and IMAGE_NT_HEADERS64 (see the same names in windows headers).

One should of cause use managed .NET classes and methods if there are exist. It’s a pity, but the implementation of some the most powerful features of Windows come in managed .NET too late and a lot of there are accessed till now only in unmanaged world. 10 year ago at one of the first Microsoft conference about .NET I asked about my favor Memory Mapped Files. Only .NET 4 has now MemoryMappedFile class implemented (see http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx). The same problems exist permanently if one writes utilities for administrative purpose. For example, opening file with CreateFile and Flag FILE_FLAG_BACKUP_SEMANTICS or RegCreateKeyEx with REG_OPTION_BACKUP_RESTORE or REG_OPTION_CREATE_LINK. Hard Links and Junctions (see http://msdn.microsoft.com/en-us/library/aa365006(v=VS.85).aspx) are next examples. One more example: working with Job Objects instead of Process (see http://msdn.microsoft.com/en-us/library/ms684161(VS.85).aspx and http://www.microsoft.com/msj/0399/jobkernelobj/jobkernelobj.aspx). If you want to start a process and wait not till this process, but also untill all it’s child processes be ended, job is very useful. One can use CreateJobObject and AssignProcessToJobObject and then use TerminateJobObject or WaitHandle like .NET version of (WaitForSingleObject).

Only in .NET 4.0 System.IntPtr und System.UIntPtr classes supports Add and Subtract methods.

I can continue the examples, but I hope you understand what I mean. So I want to write a program in .NET because of a lot of advantages but I can do this not always without usage of native API. Moreover, there are sometimes customer's requirement to the language of software implementation and I choose the required way.

UPDATED 2: Microsoft improved the interoperability with COM in .NET 4.0, but not with C-like Windows API. I see some ways to makes working with P/Invoke easier. What way to do this you see? I suggest three directions which I see:

  1. One makes an assembly with declaration of all (or the most important) not yet fully implemented in .NET Windows API. This assemble can has only (or almost only) metadata of static Native class with static functions and corresponding classes / structures. This assembly can be placed in GAC and everybody could use it. (This way I tested. It works very well.)
  2. One implements a collection of snippets with declaration and samples of using of different native Windows API.
  3. One start an open source project on www.codeplex.com where one create .NET classes and extension methods to some most important native Windows API which are not yet implemented in .NET.

I am sure that exist more ways to make easier for developer the usage of native Windows API. Other suggestions are welcome.

+2  A: 

One view is that PInvoke is a compatibility crutch. You should be using 100% .Net libraries and functions, not "legacy" Win32 calls.

Yann Ramin
For some reason whenever I need something special done, which happens quite often, I end up using "legacy" Win32 calls to make the magic happen. While I am writing this I am figuring out how to make my WPF window sticky like winamp... wish .net libraries did that for me.
m0s
+6  A: 

I don't know why MSFT made that decision, but here are a few reasons why I think the decision was the correct one:

  • The Windows SDK header files (windows.h et al) make extensive use of conditional compilation based on things like the target Windows version and architecture to determine what functions get declared and how data structures are laid out. None of this would be possible in any of the .NET languages, as one does not target Windows versions but rather framework versions, with the resulting binaries able to run natively on 32- and 64-bit architectures across many versions and editions of Windows

  • Many Windows API calls and data structures cannot be fully expressed via P/Invoke. One that comes immediately to mind is DeviceIoControl. Another are the many so-called 'variable length' structures, containing arrays with an unknown (at compile time) number of elements in them

  • P/Invoke has evolved over time, particularly in the way handles are exposed (IntPtr in early versions of the framework; SafeHandle classes later); if MSFT maintained a single static class with most or all Win32 API functions, they would also be obligated to maintain compatibility with previous versions of this class, locking themselves in to however P/Invoke was implemented originally

  • Even MSFT themselves do not maintain a single Native class in the framework internals. Now that the .NET Framework 3.5 source code is available, you can see for yourself how ad-hoc use of P/Invoke is, even within the very framework we are supposed to use in lieu of P/Invoke. For example, System.Net and System.IO have their own separate P/Invoke declarations.

  • The .NET Framework and managed code were designed from the beginning as a new way of building software for Windows. How stupid would it be to provide this new way while at the same time requiring use of the old way for many tasks?

I say this as someone who makes extensive use of P/Invoke for things like IOCTLs and volume-level I/O operations. The more I use P/Invoke, the more I hate it. It's hard to work with, error prone, and slow. Every time I use P/Invoke, it's because I've exhausted all other options. If you find yourself with a problem whose solution requires a lot of direct Windows API calls, you probably:

a) Are missing some feature within the Framework that will do what you want

b) Are taking the wrong approach to solving the problem, particularly if you are used to the native Windows API and still think in those terms

c) Should write your low-level code in C++/CLI, and expose chunky higher-level interfaces for your .NET code to consume

anelson
I don't think I've ever managed to write a .Net program without P/Invoke.
Gabe
You have my sympathies then ;)
anelson
Sorry, but you are wrong with `DeviceIoControl`. You can of cause use `DeviceIoControl` function for direct communication with device drivers. If you want I can post you a working example and you can see this yourself. But there are misunderstanding in what I want with my question. Please read "UPDATED 2" of the question.
Oleg
I did not claim `DevioceIoControl` could not be used with P/Invoke, but I do claim that you cannot produce a single `DeviceIoControl` P/Invoke declaration that will work for all of the various input and output data structures without manually invoking the marshaller.I have successfully P/Invoke'd `DeviceIoControl` for a number of very complex data structures, but simply declaring the input and output buffers as `IntPtr` leaves you to manually marshal the input and output. Sure, you could create a wrapper class that did more, but that was not the original point.
anelson
I would just add that I am not suggesting there is no value in using P/Invoke, or the framework is so complete the P/Invoke is never necessary.It sounds like you and I do similar low-level stuff with C#, so we need P/Invoke all the time. However, I bet at least 80% of .NET programmers (probably more) never need to P/Invoke a method, so MSFT would be undertaking the effort of improving P/Invoke for the 20% of us (probably less) that need it.An open-source P/Invoke project with already-tested declarations for all my favorite Win32 API calls would be great. If it existed, I would use it.
anelson
A: 

I'm sure the thought crossed your minds but I think there should be an open source project that did this. Rather than waiting on Microsoft to do this, we can collect all of the knowledge that people who've actually used P/Invoke day in day out so that others don't have to reinvent the wheel.

Keep collecting the API as people use them, need them.

Any volunteers? :)

pinvoke.net doesn't count - it's not readily pluggable to your solution.

Jiho Han