Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual CSharp 2005 Recipes (2006) [eng]

.pdf
Скачиваний:
48
Добавлен:
16.08.2013
Размер:
4.04 Mб
Скачать

138 C H A P T E R 4 T H R E A D S, P R O C E S S E S, A N D S Y N C H R O N I Z AT I O N

Console.WriteLine(ex);

}

// Wait to continue. Console.WriteLine(Environment.NewLine); Console.WriteLine("Main method complete. Press Enter."); Console.ReadLine();

}

}

}

4-16. Terminate a Process

Problem

You need to terminate a process such as an application or a service.

Solution

Obtain a Process object representing the operating system process you want to terminate. For Windows-based applications, call Process.CloseMainWindow to send a close message to the application’s main window. For Windows-based applications that ignore CloseMainWindow, or for non-Windows- based applications, call the Process.Kill method.

How It Works

If you start a new process from managed code using the Process class (discussed in recipe 4-15), you can terminate the process using the Process object that represents the new process. You can also obtain Process objects that refer to other currently running processes using the static methods of the Process class summarized in Table 4-4.

Table 4-4. Methods for Obtaining Process References

Method

Description

GetCurrentProcess

Returns a Process object representing the currently active process.

GetProcessById

Returns a Process object representing the process with the specified ID.

 

This is the process ID (PID) you can get using Windows Task Manager.

GetProcesses

Returns an array of Process objects representing all currently active

 

processes.

GetProcessesByName

Returns an array of Process objects representing all currently active

 

processes with a specified friendly name. The friendly name is the name

 

of the executable excluding file extension or path; for example, a friendly

 

name could be notepad or calc.

 

 

Once you have a Process object representing the process you want to terminate, you need to call either the CloseMainWindow method or the Kill method. The CloseMainWindow method posts a WM_CLOSE message to a Windows-based application’s main window. This method has the same effect as if the user had closed the main window using the system menu, and it gives the application the opportunity to perform its normal shutdown routine. CloseMainWindow will not terminate applications that

C H A P T E R 4 T H R E A D S, P R O C E S S E S, A N D S Y N C H R O N I Z AT I O N

139

do not have a main window or applications with a disabled main window—possibly because a modal dialog box is currently displayed. Under such circumstances, CloseMainWindow will return false.

CloseMainWindow returns true if the close message was successfully sent, but this does not guarantee that the process is actually terminated. For example, applications used to edit data will usually give the user the opportunity to save unsaved data if a close message is received. The user usually has the chance to cancel the close operation under such circumstances. This means CloseMainWindow will return true, but the application will still be running once the user cancels. You can use the Process.WaitForExit method to signal process termination and the Process.HasExited property to test whether a process has terminated. Alternatively, you can use the Kill method.

The Kill method simply terminates a process immediately; the user has no chance to stop the termination, and all unsaved data is lost. Kill is the only option for terminating Windows-based applications that do not respond to CloseMainWindow and for terminating non-Windows-based applications.

The Code

The following example starts a new instance of Notepad, waits 5 seconds, and then terminates the Notepad process. The example first tries to terminate the process using CloseMainWindow. If CloseMainWindow returns false, or the Notepad process is still running after CloseMainWindow is called, the example calls Kill and forces the Notepad process to terminate; you can force CloseMainWindow to return false by leaving the File Open dialog box open.

using System;

using System.Threading; using System.Diagnostics;

namespace Apress.VisualCSharpRecipes.Chapter04

{

class Recipe04_16

{

public static void Main()

{

// Create a new Process and run notepad.exe. using (Process process =

Process.Start("notepad.exe",@"c:\SomeFile.txt"))

{

//Wait for 5 seconds and terminate the notepad process. Console.WriteLine(

"Waiting 5 seconds before terminating notepad.exe."); Thread.Sleep(5000);

//Terminate notepad process.

Console.WriteLine("Terminating Notepad with CloseMainWindow.");

// Try to send a close message to the main window. if (!process.CloseMainWindow())

{

// Close message did not get sent - Kill Notepad. Console.WriteLine("CloseMainWindow returned false - " +

" terminating Notepad with Kill."); process.Kill();

}

else

{

//Close message sent successfully; wait for 2 seconds

//for termination confirmation before resorting to Kill.

140 C H A P T E R 4 T H R E A D S, P R O C E S S E S, A N D S Y N C H R O N I Z AT I O N

if (!process.WaitForExit(2000))

{

Console.WriteLine("CloseMainWindow failed to" +

" terminate - terminating Notepad with Kill."); process.Kill();

}

}

}

// Wait to continue.

Console.WriteLine("Main method complete. Press Enter."); Console.ReadLine();

}

}

}

4-17. Ensure That Only One Instance of an Application Can Execute Concurrently

Problem

You need to ensure that a user can have only one instance of an application running concurrently.

Solution

Create a named System.Threading.Mutex object, and have your application try to acquire ownership of it at start-up.

How It Works

The Mutex provides a mechanism for synchronizing the execution of threads across process boundaries and in addition provides a convenient mechanism through which to ensure that only a single instance of an application is running concurrently. By trying to acquire ownership of a named Mutex at start-up and exiting if the Mutex cannot be acquired, you can ensure that only one instance of your application is running.

The Code

This example uses a Mutex named MutexExample to ensure that only a single instance of the example can execute:

using System;

using System.Threading;

namespace Apress.VisualCSharpRecipes.Chapter04

{

class Recipe04_17

{

public static void Main()

{

C H A P T E R 4 T H R E A D S, P R O C E S S E S, A N D S Y N C H R O N I Z AT I O N

141

//A boolean that indicates whether this application has

//initial ownership of the Mutex.

bool ownsMutex;

//Attempt to create and take ownership of a Mutex named

//MutexExample.

using (Mutex mutex =

new Mutex(true, "MutexExample", out ownsMutex))

{

//If the application owns the Mutex it can continue to execute;

//otherwise, the application should exit.

if (ownsMutex)

{

Console.WriteLine("This application currently owns the" +

"mutex named MutexExample. Additional instances of" +

"this application will not run until you release" +

"the mutex by pressing Enter.");

Console.ReadLine();

// Release the mutex mutex.ReleaseMutex();

}

else

{

Console.WriteLine("Another instance of this application " +

"already owns the mutex named MutexExample. This" +

"instance of the application will terminate.");

}

}

// Wait to continue.

Console.WriteLine("Main method complete. Press Enter."); Console.ReadLine();

}

}

}

Note If you do not construct the Mutex in a using statement and encapsulate the body of your application in the body of the using block as shown in this example, in long-running applications the garbage collector may dispose of the Mutex if it is not referenced after initial creation. This will result in releasing the Mutex and allow additional instances of the application to execute concurrently. In these circumstances, you should include the statement System.GC.KeepAlive(mutex) to ensure the Mutex is not garbage collected. Thanks to Michael A. Covington for highlighting this possibility.

C H A P T E R 5

■ ■ ■

Files, Directories, and I/O

The Microsoft .NET Framework I/O classes fall into two basic categories. First are the classes that retrieve information from the file system and allow you to perform file system operations such as copying files and moving directories. Two examples include the FileInfo and the DirectoryInfo classes. The second, and possibly more important, category includes a broad range of classes that allow you to read and write data from all types of streams. Streams can correspond to binary or text files, a file in an isolated store, a network connection, or even a memory buffer. In all cases, the way you interact with a stream is the same. This chapter describes how to use the file system classes and a wide range of stream-based classes.

The recipes in this chapter describe how to do the following:

Retrieve or modify information about a file, directory, or a drive (recipes 5-1, 5-2, 5-4, 5-5, and 5-16)

Copy, move, and delete files and directories (recipe 5-3)

Show a directory tree in a Microsoft Windows-based application and use the common file dialog boxes (recipes 5-6 and 5-17)

Read and write text and binary files (recipes 5-7 and 5-8)

Create temporary files and files in a user-specific isolated store (recipes 5-15 and 5-18)

Read files asynchronously (recipe 5-9)

Search for specific files and test files for equality (recipes 5-10 and 5-11)

Work with strings that contain path information (recipes 5-12, 5-13, and 5-14)

Monitor the file system for changes (recipe 5-19)

Write to a COM port (recipe 5-20)

Generate a random filename (recipe 5-21)

Retrieve or modify the access control lists (ACLs) of a file or directory (recipe 5-22)

5-1. Retrieve Information About a File, Directory, or Drive

Problem

You need to retrieve information about a file, directory, or drive.

143

144 C H A P T E R 5 F I L E S, D I R E C TO R I E S, A N D I / O

Solution

Create a new System.IO.FileInfo, System.IO.DirectoryInfo, or System.IO.DriveInfo object, depending on the type of resource about which you need to retrieve information. Supply the path of the resource to the constructor, and then you will be able to retrieve information through the properties of the class.

How It Works

To create a FileInfo, DirectoryInfo, or DriveInfo object, you supply a relative or fully qualified path in the constructor. You can retrieve information through the corresponding object properties. Table 5-1 lists some of the key members that are found in these objects.

Table 5-1. Key Members for Files, Directories, and Drives

Member

Applies To

Description

Exists

FileInfo and

Returns true or false, depending on whether

 

DirectoryInfo

a file or a directory exists at the specified

 

 

location.

Attributes

FileInfo and

Returns one or more values

 

DirectoryInfo

from the System.IO.FileAttributes

 

 

enumeration, which represents the

 

 

attributes of the file or the directory.

CreationTime, LastAccessTime,

FileInfo and

Return System.DateTime

and LastWriteTime

DirectoryInfo

instances that describe when

 

 

a file or a directory was created, last

 

 

accessed, and last updated, respectively.

FullName, Name, and Extension

FileInfo and

Return a string that represents the fully

 

DirectoryInfo

qualified name, the directory, or the

 

 

filename (with extension), and the

 

 

extension on its own.

IsReadOnly

FileInfo

Returns true or false, depending on

 

 

whether a file is read-only.

Length

FileInfo

Returns the file size as a number of bytes.

DirectoryName and Directory

FileInfo

DirectoryName returns the name of the

 

 

parent directory as a string. Directory

 

 

returns a full DirectoryInfo object that

 

 

represents the parent directory and allows

 

 

you to retrieve more information about it.

Parent and Root

DirectoryInfo

Return a DirectoryInfo object that

 

 

represents the parent or root directory.

CreateSubdirectory

DirectoryInfo

Creates a directory with the specified name

 

 

in the directory represented by the

 

 

DirectoryInfo object. It also returns a new

 

 

DirectoryInfo object that represents the

 

 

subdirectory.

GetDirectories

DirectoryInfo

Returns an array of DirectoryInfo objects,

 

 

with one element for each subdirectory

 

 

contained in this directory.

GetFiles

DirectoryInfo

Returns an array of FileInfo objects, with

 

 

one element for each file contained in this

 

 

directory.

C H A P T E R 5 F I L E S, D I R E C TO R I E S, A N D I / O

145

Member

Applies To

Description

DriveType

DriveInfo

Returns a DriveType enumeration value that

 

 

represents the type of the specified drive;

 

 

for example, Fixed or CD Rom.

AvailableFreeSpace

DriveInfo

Returns a long that represents the free space

 

 

available in the drive.

GetDrives

DriveInfo

Returns an array of DriveInfo objects that

 

 

represents the logical drives in the

 

 

computer.

 

 

 

The following are a few points to note while working with these objects:

FileInfo and DirectoryInfo classes derive from the abstract FileSystemInfo class, which defines common methods like CreationTime, Exists, and so on. The DriveInfo class does not inherit from this base class, so it does not provide some of the common members available in the other two classes.

The full set of properties FileInfo and DirectoryInfo objects expose is read the first time you interrogate any property. If the file or directory changes after this point, you must call the Refresh method to update the properties. However, this is not the case for DriveInfo; each property access asks the file system for an up-to-date value.

You will not encounter an error if you specify a path that does not correspond to an existing file, directory, or drive. Instead, you will receive an object that represents an entity that does not exist—its Exists (or IsReady property for DriveInfo) property will be false. You can use this object to manipulate the entity. However, if you attempt to read most other properties, exceptions like FileNotFoundException, DirectoryNotFoundException, and so on will be thrown.

The Code

The following console application takes a file path from a command-line argument, and then displays information about the file, the containing directory, and the drive.

using System; using System.IO;

namespace Apress.VisualCSharpRecipes.Chapter05

{

static class Recipe05_01

{

static void Main(string[] args)

{

if (args.Length == 0)

{

Console.WriteLine("Please supply a filename."); return;

}

// Display file information.

FileInfo file = new FileInfo(args[0]);

Console.WriteLine("Checking file: " + file.Name);

Console.WriteLine("File exists: " + file.Exists.ToString());

146 C H A P T E R 5 F I L E S, D I R E C TO R I E S, A N D I / O

if (file.Exists)

{

Console.Write("File created: "); Console.WriteLine(file.CreationTime.ToString()); Console.Write("File last updated: "); Console.WriteLine(file.LastWriteTime.ToString()); Console.Write("File last accessed: "); Console.WriteLine(file.LastAccessTime.ToString()); Console.Write("File size (bytes): "); Console.WriteLine(file.Length.ToString()); Console.Write("File attribute list: "); Console.WriteLine(file.Attributes.ToString());

}

Console.WriteLine();

// Display directory information. DirectoryInfo dir = file.Directory;

Console.WriteLine("Checking directory: " + dir.Name);

Console.WriteLine("In directory: " + dir.Parent.Name);

Console.Write("Directory exists: ");

Console.WriteLine(dir.Exists.ToString());

if (dir.Exists)

{

Console.Write("Directory created: "); Console.WriteLine(dir.CreationTime.ToString()); Console.Write("Directory last updated: "); Console.WriteLine(dir.LastWriteTime.ToString()); Console.Write("Directory last accessed: "); Console.WriteLine(dir.LastAccessTime.ToString()); Console.Write("Directory attribute list: "); Console.WriteLine(dir.Attributes.ToString()); Console.WriteLine("Directory contains: " +

dir.GetFiles().Length.ToString() + " files");

}

Console.WriteLine();

// Display drive information.

DriveInfo drv = new DriveInfo(file.FullName);

Console.Write("Drive: ");

Console.WriteLine(drv.Name);

if (drv.IsReady)

{

Console.Write("Drive type: "); Console.WriteLine(drv.DriveType.ToString()); Console.Write("Drive format: "); Console.WriteLine(drv.DriveFormat.ToString()); Console.Write("Drive free space: "); Console.WriteLine(drv.AvailableFreeSpace.ToString());

}

// Wait to continue. Console.WriteLine(Environment.NewLine); Console.WriteLine("Main method complete. Press Enter.");

C H A P T E R 5 F I L E S, D I R E C TO R I E S, A N D I / O

147

Console.ReadLine();

}

}

}

Usage

If you execute the command Recipe05-01.exe c:\windows\win.ini, you might expect the following output:

Checking file: win.ini

File exists: True

File created: 31.Mar.2003 5:30:00 PM

File last updated: 24.Sep.2005 11:11:13 PM

File last accessed: 10.Nov.2005 9:41:05 PM

File size (bytes): 658

File attribute list: Archive

Checking directory: windows

In directory: c:\

Directory exists: True

Directory created: 04.Jun.2005 4:47:56 PM

Directory last updated: 01.Nov.2005 10:09:45 AM

Directory last accessed: 11.Nov.2005 6:24:59 AM

Directory attribute list: Directory

Directory contains: 134 files

Drive: c:\

Drive type: Fixed

Drive format: NTFS

Drive free space: 14045097984

Note Instead of using the instance methods of the FileInfo and DirectoryInfo classes, you can use the static File and Directory classes (note that a class corresponding to the DriveInfo class does not exist). The File and Directory methods expose most of the same functionality, but they require you to submit the filename or path with every method invocation. In cases where you need to perform multiple operations with the same file or directory, using the FileInfo and DirectoryInfo classes will be faster, because they will perform security checks only once. Also note that you could obtain the list of all logical drives in the computer by using the static

DriveInfo.GetDrives method.

5-2. Set File and Directory Attributes

Problem

You need to test or modify file or directory attributes.

Solution

Create a System.IO.FileInfo object for a file or a System.IO.DirectoryInfo object for a directory and use the bitwise AND (&) and OR (|) arithmetic operators to modify the value of the Attributes property.

Соседние файлы в предмете Программирование на C++