It is possible, though generally undesirable, to invoke unmanaged
code from within C#. The .NET
platform invoke
facility
(P/Invoke
) was originally
intended only to provide access to the Windows API, but you can use
it to expose functions in any DLL.
To see how this works, let’s revisit Example 21-3 from Chapter 21. You will
recall that you used the
Stream
class to rename
files by invoking the MoveTo( )
method:
file.MoveTo(fullName + ".bak");
You can accomplish the same thing by using Windows’
kernal32.dll
and invoking the
MoveFiles
method. To do so, you need to declare
the method as a static
extern
and you need to use the DllImport
attribute:
[DllImport("kernel32.dll", EntryPoint="MoveFile", ExactSpelling=false, CharSet=CharSet.Unicode, SetLastError=true)] static extern bool MoveFile( string sourceFile, string destinationFile);
The
DllImportAttribute
class is used to indicate that an
unmanaged method will be invoked through P/Invoke
.
The parameters are:
The rest of the code is virtually unchanged, except for the
invocation of the MoveFile( )
method itself. Notice that
MoveFile( )
is declared to be a static method of
the class, so you use static method semantics:
Tester.MoveFile(file.FullName,file.FullName + ".bak");
You pass in the original filename and the new name and the file is
moved, just as it was when calling file.MoveTo( )
.
In this example, there is no advantage—and actually
considerable disadvantage—to using P/Invoke
.
You have left managed code, and the result is not object-oriented.
P/Invoke
really only makes sense when you
absolutely, positively need to invoke a method for which there is no
reasonable substitute within managed code. Example 22-10 shows the complete source code for using
P/Invoke
to move the files.
Example 22-10. Using P/Invoke to call a Win32 API method
namespace Programming_CSharp { using System; using System.IO; using System.Runtime.InteropServices; class Tester { // declare the WinAPI method you wish to P/Invoke [DllImport("kernel32.dll", EntryPoint="MoveFile", ExactSpelling=false, CharSet=CharSet.Unicode, SetLastError=true)] static extern bool MoveFile( string sourceFile, string destinationFile); public static void Main( ) { // make an instance and run it Tester t = new Tester( ); string theDirectory = @"c: estmedia"; DirectoryInfo dir = new DirectoryInfo(theDirectory); t.ExploreDirectory(dir); } // Set it running with a directory name private void ExploreDirectory(DirectoryInfo dir) { // make a new subdirectory string newDirectory = "newTest"; DirectoryInfo newSubDir = dir.CreateSubdirectory(newDirectory); // get all the files in the directory and // copy them to the new directory FileInfo[] filesInDir = dir.GetFiles( ); foreach (FileInfo file in filesInDir) { string fullName = newSubDir.FullName + "\" + file.Name; file.CopyTo(fullName); Console.WriteLine("{0} copied to newTest", file.FullName); } // get a collection of the files copied in filesInDir = newSubDir.GetFiles( ); // delete some and rename others int counter = 0; foreach (FileInfo file in filesInDir) { string fullName = file.FullName; if (counter++ %2 == 0) { // P/Invoke the Win API Tester.MoveFile(fullName, fullName + ".bak"); Console.WriteLine("{0} renamed to {1}", fullName,file.FullName); } else { file.Delete( ); Console.WriteLine("{0} deleted.", fullName); } } // delete the subdirectory newSubDir.Delete(true); } } } Output (excerpt): c: estmedia ewTest ecycle.wav renamed to c: estmedia ewTest ecycle.wav c: estmedia ewTest ingin.wav renamed to c: estmedia ewTest ingin.wav
3.15.168.211