Jak cię złapią, to znaczy, że oszukiwałeś. Jak nie, to znaczy, że posłużyłeś się odpowiednią taktyką.
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: EntryPoint Indicates the name of the DLL entry point (the method) to be called. ExactSpelling page 503 Programming C# Setting this to false allows matching of the entry point name without case sensitivity. CharSet Indicates how the string arguments to the method should be marshaled. SetLastError Setting this to true allows you to call GetLastError to check if an error occurred when invoking this method. 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:\test\media"; 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 = page 504 Programming C# 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:\test\media\newTest\recycle.wav renamed to c:\test\media\newTest\recycle.wav c:\test\media\newTest\ringin.wav renamed to c:\test\media\newTest\ringin.wav 22.5 Pointers Until now you've seen no code using C/C++ style pointers. Only here, in the final paragraphs of the final pages of the book, does this topic arise, even though pointers are central to the C family of languages. In C#, pointers are relegated to unusual and advanced programming; typically they are used only when interoperating with COM. C# supports the usual C pointer operators, listed in Table 22-1. Table 22-1, C# pointer operators Operator Meaning page 505 Programming C# & The address-of operator returns a pointer to the address of a value. * The dereference operator returns the value at the address of a pointer. -> The member access operator is used to access the members of a type. The use of pointers is almost never required, and is nearly always discouraged. When you do use pointers, you must mark your code with the C# unsafe modifier. The code is marked unsafe because with pointers you can manipulate memory locations directly, a feat otherwise impossible within a C# program. In unsafe code you can directly access memory, perform conversions between pointers and integral types, take the address of variables, and so forth. In exchange, you give up garbage collection and protection against uninitialized variables, dangling pointers, and accessing memory beyond the bounds of an array. In essence, unsafe code creates an island of C++-code within your otherwise safe C# application. As an example of when this might be useful, you'll read a file to the console by invoking two Win32 API calls: CreateFile and ReadFile. ReadFile takes, as its second parameter, a pointer to a buffer. The declaration of the two imported methods is not unlike those shown in Example 22-11. Example 22-11. Declaring Win32 API methods for import into a C# program [DllImport("kernel32", SetLastError=true)] static extern unsafe int CreateFile( string filename, uint desiredAccess, uint shareMode, uint attributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile); [DllImport("kernel32", SetLastError=true)] static extern unsafe bool ReadFile( int hFile, void* lpBuffer, int nBytesToRead, int* nBytesRead, int overlapped);
|
Wątki
|