In working with PInvoke, I found it utterly tedious having to write those structures as arguments to pass into the function calls. Particularly, since I myself am not a Win32 developer. I decided to start an article focused on some shortcuts (good or bad) one can use to speed up the whole process. Here are just some things to make the job a little easier (if you didn't already know). This article is intended to serve as a journal of findings and as such will remain a living document. If there are any quick tricks you know as a reader, please inform me so I can update it. :-)
In Win32, the
CreateFile function is used as a general access method to open files, named pipes, directories, communication resources, physical disks, volumes, the console buffer, tape drives, or mail slots. Here is the basic signature for the function:
Most of the samples I have seen take the approach of creating constants to represent the various values associated with the parameters:
creationdisposition. You can however use the
enum to represent
enum to represent creation-disposition and the
enum to represent
fileshare. You would simply have to manually marshal the
enums as integers. Since
enums in .NET represent integer type constants, this should not be a problem. Here is how the declaration of
CreateFile would look:
static extern IntPtr CreateFile(
securityattributes to illustrate that (if you are not planning to use it, you can simple map it as an
int and pass 0 rather than create the entire structure just to pass it in).
With the above function declared, you can call
CreateFile from your code much easier:
IntPtr ptr= CreateFile("text.txt",FileAccess.ReadWrite,
The above code will return a handle that can be used to access the object.
If you specified "COM1" as the filename above (you would have to change some of the parameters), you would get back a handle to the COM port 1. Trying to do this with the
File factory provided by .NET as follows:
FileStream fs = File.Create("COM1");
will not work.
CreateFile however does not return a
FileStream; rather you get back a Handle which you must the pass in subsequent calls to other IO functions like
CreateFileMapping. In the case of serial communication, the standard practice is to use the read and write Win32 functions to read from and write to the port. Here is the definition for
Fortunately, you do not have to do this. Although .NET does not allow you to directly open devices, (the example I showed above), it does let you create filestreams from Windows handles (yeah!), so you could access the stream associated with the device like this:
IntPtr ptr= CreateFile("COM1",
FileStream fs = new FileStream(ptr,FileAccess.ReadWrite);
File class allows you to get an instance to a
FileStream from the handle of a file, you can open a file using standard Win32 mechanism, use its handle to create a
FileStream, and write to it using all the standard .NET mechanisms. It's not much to write home about when you're just working with files, but with some imagination you can achieve the equivalent of:
FileStream fs = File.Open("//./device",FileMode.open);
Something that is not yet implemented in .NET. Using this in tandem with
DeviceIOControl can bring .NET pretty close to the AssemblyZone.
For quick access to cross platform multimedia functionality such as playing all waveform audio, capturing video & audio, etc., use the multimedia library winmm.dll. It gives very low level access to everything without having to redistribute DirectX. In fact, you can you the
mciSendString() function and just send text based messages directly to the multimedia device drivers. Please see the article below for a more detailed description of this:
Using MCI to control multimedia.