|
Chapter 10Win32 Modules on Windows NT
CONTENTS
In the previous chapter I covered details on getting and installing Perl for Windows NT. In this chapter I cover the methods and functions of some of the Win32 modules that come with the NT Perl package. Although this chapter covers details of how to make calls into the Windows 32 bit API, I do not go into the details of how the module itself works as it interacts with the API. Dealing with that topic would be well beyond the scope of this book. To get a good understanding of how to program an NT application, check out Jason Loveman's Moving to Windows NT Programming, Sams Publishing. This book may seem a bit dated at first, but it provides an excellent tutorial on how to get going from a Windows 3.x environment to NT. The other book that is a must-have is The Win32 API Desktop Reference by Jim McCord, also from Sams Publishing. This book is a comprehensive reference manual with a bit of instruction on how to program without the benefit of the Microsoft Foundation Classes.
The Win32 ModuleThe Win32 module contains extensions for working specifically with the Windows NT system. Here are some miscellaneous functions that exist only under the Windows NT hierarchy-you'll find them quite useful when writing Perl scripts under NT:
Spawning ProcessesThe Win32::Spawn command is used to start a process. The syntax for this command is Win32::Spawn( $command, $args, $pid); A new process is started and runs the command in $command. Any command-line arguments passed into the process are specified in $args. The process ID is returned in $pid. Starting System ShutdownThe Win32::InitiateSystemShutdown command is used to shut down a machine. The syntax for this command is Win32::InitiateSystemShutdown ( The machine name is specified in $machine, and a NULL value identifies the current machine. The $message value is sent to all the users logged into the machine at this time. The $timeout value is used to notify users of imminent shutdown. The $forceClose value is set to 1 if you want the system to close all open files without prompting the user. (This is useful during off times when the user might not be at his or her desk.) The machine will reboot if $reboot is set to true. Aborting System ShutdownThe Win32::AbortSystemShutdown command attempts to stop the shutdown process on a given machine. The syntax for this command is Win32::AbortSystemShutdown ($machine); The abort request might not always work because the $timeout may happen before you get this command going. (I could not stop the shutdown/reboot process even with a very long timeout.) Stopping a shutdown process in the middle may leave your system in an indeterminate state. Once you get the ball rolling on a shutdown, let it go through all the way. However, if you must stop an accidental shutdown command, this command can be a valuable resource. Several modules exist under the Win32:: extensions to enable you to work with processes, interprocess communications networks, and user resources. I cover these modules as well. One thing to keep in mind is that this code is in test mode at this time, and improvements will be made as the code develops. Also, these extensions are almost always NT-specific and might not work on Windows 95. This means that the code you write with these modules will not be portable to platforms other than Windows NT systems. Listing 10.1 illustrates how to use some of the functions in the Win32 module. Listing 10.1. Using the Win32 modules. 1 use Win32; The Process Module ExtensionsThe Win32::Process module extensions enable you to create different processes and start applications using Perl scripts. The Create function lets you create a Process object that will run an application. The syntax for this call is Create( $pObject, $pObject is the returned reference to an object from this Create call. The Create function is the constructor for the Process class. Subsequent methods are called using this object as a reference. $ApplicationName is the full pathname of the application you want to run in this Process object. The path can be specified using forward slashes or back slashes. For example, to fire up C:\dos\winzip.exe on a system, you can use either one of these two pathnames: "c:/dos/winzip.exe" $CommandLine is the list of arguments passed at the command line to the application in $ApplicationName. The new application will inherit any open file handles if $InheritHandles is set to 1. If you do not want the called application to inherit file handles, set $InheritHandles to 0. The $CurrentDir variable is set to the working directory for executable programs. The $CreateOptions variable can take a combination of the following values:
Once the Process object has been created, you can apply methods to it. The following methods exist for the Win32::Process object.
The Kill MethodThis method kills the process associated with the Process object. The syntax for this method is Kill( $ExitCode). The $ExitCode is the value of the code that the process should return. The Resume and Suspend MethodsThe Suspend() method stops a process from executing. To restart the thread, call the Resume() method. The Resume call can be used to resume a process that was created with the CREATE_SUSPENDED flag. The GetExitCode() FunctionThe GetExitCode() function forces the pObject to terminate with its exit code set to the value of $ExitCode. The syntax for this function is GetExitCode( $ExitCode ); You can use GetExitCode to find out how or if a process has exited. The Wait($Timeout) FunctionThe calling process can wait for a process to terminate with the Wait function. The syntax for this call is Wait($Timeout) The $Timeout variable is set to the number of milliseconds to wait for the process to end. If the process wants to wait forever, use the keyword INFINITE for $Timeout. The returned value of Wait() is FALSE if it times out and the error code in $! is set to WAIT_FAILED. A returned value of TRUE indicates that the process terminated before the $Timeout value. Class PriorityThe GetPriorityClass and SetPriorityClass methods provide control over the priority of the process. The priority class of the process can be retrieved with a call to this method: GetPriorityClass($Priority ) The returned value of $Priority is set to the priority class of the object this method is being called on. SetPriorityClass($Priority ) is the opposite of the GetPriorityClass() function. The $Priority variable is set to the priority to set the Process to. The value can be set to one of the following:
Listing 10.2 shows you how to use the Win32::Process module. Listing 10.2. Using the Win32::Process module. 1 use Win32; The Win32::Semaphore UtilitiesThe Win32::Semaphore lets a Perl script access the semaphore facility in Windows NT. The Create call in a Semaphore module lets you create a semaphore object. The semaphore in an NT machine works in the same manner as in UNIX. For more information on how to use semaphores, see Chapter 13, "Messaging Facilities: The System V Ipc Functions." The syntax for the Create function is Create ($semaphoreObj,$initialCount,$maxCount,$name); The returned value from the Create call is placed to what the $semaphoreObj references. The $initialCount variable is used to set the initial count of the semaphore object. The maximum count of the semaphore is set in $maxCount. The semaphore can be identified in the NT system by the value in $name. The DESTROY method removes a semaphore object specified in the argument to itself. The syntax is DESTROY( $SemaphoreObj ); The DESTROY method is automatically called by Perl when the $SemaphoreObject scalar goes out of scope. The Wait( $TimeOut ) function is used to wait for a timeout for the value in $TimeOut. The value in $Timeout is specified in milliseconds. The Wait method makes the calling process wait on the semaphore. If the Semaphore is not released in $TimeOut milliseconds, the call returns, and the return value should be checked. For no timeout value, use the predefined constant INFINITE. Once you are done with a semaphore, you should release it to let other processes access it. To release a semaphore, you have to make a call to Release( $ReleaseCount, $lastCount); The value in $ReleaseCount is incremented by the call to Release. The Release method releases a semaphore after it increments the count. The $LastCount variable contains the last value. Listing 10.3 illustrates how to use the Semaphore module in NT. Note how the ErrorMsg subroutine displays the readable message from the GetLastError() call. Listing 10.3. Using the Win32::Semaphore object. 1 use Win32::Semaphore; Using Mutex with Win32::MutexThe Win32::Mutex module is used to create, destroy, and work with Mutexes in the NT system. A Mutex is used to provide mutually exclusive access to a resource. Processes vie to own a Mutex, and only one process can own a Mutex at one time. A process controlling a Mutex can then work exclusively on a shared resource such as a file or device. Mutexes differ from semaphores in that Mutexes are available only in kernel-mode processes and not for user-mode processes. Refer to Jason Loveman's book, Moving into Windows NT Programming, for some good examples on how to use Mutexes. To create a Mutex, you have to call the Create function for the object. The first parameter into the Create call is assigned a reference to the Mutex object. The syntax for the Create call is Win32::Mutex::Create($mutexObject, $owner, $mutexName ) The $mutexObject is assigned a reference to the new Mutex object. The value in the $owner variable can be 1 or 0. If it is 1, the calling process will be assigned the initial ownership at the time of creation. If it is 0, the Mutex will be created as available. The name of the Mutex will be in $mutexName. Create creates a Mutex object and returns the reference in $MutexObj. If the $InitialOwner flag is set (nonzero), the process calling the Create function has immediate ownership of the Mutex. Otherwise, the Mutex is available. $Name can be used by other processes in Win32::Mutex::Opencall to create an object to reference an already created Mutex. To open a Mutex, use the Open call to get the Mutex object. The syntax for the Open call is Win32::Mutex::Open($mObject,$mutexName); The $mObject variable is assigned a reference to a Mutex object with the name value in $mutexName. The Mutex specified in $mutexName must already have been created or else a NULL value is returned in $mObject. The Release() method on a Mutex object releases a Mutex object back to the system for use by other processes. The Mutex object is destroyed when it goes out of scope in the Perl program because the default DESTROY method of the Mutex object frees the system resources used by the Mutex. The Wait() function for the Mutex object is used to wait for ownership of a Mutex. The syntax of this function is Wait( $TimeOut ); The $TimeOut variable is specified in milliseconds. The value can be set to INFINITE for waiting indefinitely. The Wait() function returns a false value if the function timed out or returns true if the Mutex has become available. Here's a fragment of code that shows how to use a Mutex: # Using Win32::ChangeNotificationThe Win32::ChangeNotification module is used for notifying a Perl application or process when a branch in the specific file system tree has been modified. The module relies on the FindFirst() call in the Win32 API, and this is the way to create the object. The syntax is Win32::ChangeNotification::FindFirst( The $cObject variable is set to the new ChangeNotification object created. $pathName is the path to the directory that you want to monitor. $watchSubTree function can be set to 0 or 1. If set to 0, any subdirectories of the path are not modified. If set to 1, the monitor process looks at the subtree, too. The $filter variable specifies the conditions on which the program notifies. The value in $filter can be set to a value that is a combination of the following constants:
Other methods for this module include the following:
When the ChangeNotification object goes out of scope, the object's DESTROY method is called by Perl. The DESTROY method closes any outstanding notification. Listing 10.4 shows how to use the ChangeNotification object. Listing 10.4. Using the ChangeNotification object. 1 use Win32; The Win32::Eventlog ModuleThe Windows NT system tracks events in the system using an event logging facility. Perl scripts can read, modify, and extract information from log records. This feature is a very powerful tool to use when generating status reports about a system. Before you use Win32::Eventlog, you have to open an event log and associate a Win32::Eventlog object with it. Here's the call to do this: Open Win32::EventLog($EventObj, $sourceName, [$serverName]); On returning from this function, the $EventObj variable will be set to a reference to an EventLog object. The name of the source for the events that will be set is $sourceName. The $ServerName variable is optional and, if omitted or explicitly set to NULL, will be set to the local machine. You can even create your own backups by using the Backup method on the $EventObj object. The file is created and the events in the current event log in the $EventObj object are written to. Any previously written file will be overwritten if a file with the same name already exists. The syntax for this command is Backup( $filename ); where $filename is the string of the file to which to write the event log. Reading EventsTo read events in a backup or event log, you have to use the Read() method on the $EventObject. The syntax for the Read() method is Read($readFlags,$recordOffset,%EventInfo); The $readFlags variable is set to specify how to read the events. The $recordNumber variable is set to the index (starting from 1, not 0). The hash %EventInfo is set to the returned event's value. $readFlag can be set to a combination of these values:
Reporting the Contents of an EventTo get a report of what you have just read, you can use the Report() method. The syntax for this call is Report($eventType, %EventInfo ); $eventType is the type of event and %EventInfo is the returned value of an %EVENTINFO hash, which is usually the value returned from a Read() call. The options for $eventType are
%EventInfo hash can be parsed with the following keys:
Three other functions also exist to get more information about the position of events in a file. The returned values of these functions can be used to specify what event record you are going to process data from. Keep in mind that records are indexed by starting at 1 and not 0.
The Win32::Registry ModuleThe Win32::Registry module lets you work with the Windows NT Registry model. The way to start working with the model is to first create a Win32::Registry object with the open() call for a key. The syntax for the open call is Win32::Registry::Open($RegistryObj,$key ) $RegistryObj returns a reference to a reference object for the predefined key specified in $key. If the specified key does not exist, it is not created. $key can only hold any already opened key. When the Registry module is loaded, four Registry objects are created in the main:: namespace. These predefined Registry objects can be referred to by the generic names within Windows NT:
To create a new key, you have to use the Create() call. Here's the syntax for the Create() call: Win32::Registry::Create($RegistryObj,$key ) where $RegistryObj returns a reference to a Registry object. The $key variable contains the name of a key. If the key exists, then the create function will open it; otherwise, it will create a new key and return a reference to it. The user must have the security privileges to create a key. Once you have a key in an object, you can get its value with the QueryValue method. The syntax for the QueryValue method is $regObject->QueryValue($subKey,$valueRef); Given the name of the subkey of the regObject in $subKey, the QueryValue function sets the value of the variable at $valueRef. To get more information about a key, you can use the QueryKey method with this calling syntax: $regObject->QueryKey ($keyClass, $numSubkeys, $numValues); All three arguments to this function are set to a value when the function returns. On returning, $keyClass is set to a string specifying the class of the key. The $numSubKeys contains the number of subkeys, and the $numValues variable contains the number of values for the current key. Keys can have more than one value associated with them. To get these values from a key, call the GetValues() method. The syntax for this call is $regObject->GetValues(\%Values); The %Values hash is set to the values in the $regObject key. The hash %Values will be keyed by deriving a value from the name and type of the object to get a key of the form {$name,$type,$data}. The GetKeys(\@Subkeys) function returns a list of names of subkeys for a given key in the array @Subkeys. To get a list of subkeys for an object, the call will be of this form: $regObject->GetValues(\@subkeys); You can save the current key status (called hive) with a call to the Save() method for a Registry object. The syntax for this method is $regObject->Save( $filename); where $filename is the name of the file to save to. To load the information about a subkey from a file on disk, you can use the Load method. The syntax for this call is $regObject->Load( $subkey, $filename); The $subkey is the subkey to load the file into from the filename specified in $filename. You can delete keys or their values. The function to delete a key is DeleteKey($keyname). To delete a value, use DeleteValue($keyname);. Here are some examples of these functions: $regObject->DeleteKey($keyname); The Win32::NetAdmin ModuleThe Win32::NetAdmin module is useful for working with users and user groups on an NT machine. Normally you would perform this operation at the main console using the windowing interface in NT. However, addition and deletion of users on multiple machines would tax the system administrator's time too much. A Perl script can list the attributes of a user or group and perhaps be able to do this automatically and remotely on a network. This section covers some of the functions available from within Perl.
Adding a UserTo add a user using the Win32::NetAdmin module, you can call the UserCreate() function. The syntax for this function is UserCreate($server, The $server variable is the name of the server. It may be NULL to specify the local server. The $userName variable is the login name of the new user. $groupName is the name of the group. The $comment variable is a string that will have the attributes field of that group when the function returns. The user's password and the time before it expires is in the variables $password and $PasswordAge, respectively. The home directory of the user is set in the $homeDir argument. The comment variable contains appropriate information about the user. The $scriptPath variable is the Uniform Naming Convention (Unc) pathname of the login script for that user. The $privilege variable controls the privileges of the new user. This variable can be set to one of these values: USER_PRIV_MASK to set for all users USER_PRIV_GUEST to set for all guest users USER_PRIV_USER to set for all normal users USER_PRIV_ADMIN to set for the administrative accounts Here are the defined values the $flag option can take:
Please refer to the Windows NT reference manual for more information about these flags. Most of the flags are descriptive enough to indicate the functions they provide. To delete a user from the system, call the UserDelete($server, $user) function. $server is the name of the server and can be NULL for the local machine. $user is the name of the user to delete. It's probably a good idea to know the attributes of a user before you delete the account. To get the attributes of a user, you have to use this call: UserGetAttributes( You can reset these values to different ones and modify an account's attribute with the UserSetAttributes call. The parameters passed into the function are the same as the UserGetAttributes() function. Listing 10.5 obtains listing information about a user. Listing 10.5. Using the NetAdmin module. use Win32::NetAdmin; To delete a user, you can use the UserDelete function. Here's the syntax: use Win32::NetAdmin; Creating or Deleting a GroupTo create a group, you can make one of these calls: LocalGroupCreate($server, $group, $comment); $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. The $comment field is a string placed in the attributes field of that group. To delete a group, you have to specify the name of the group in one of the following functions: LocalGroupDelete($server, $group); $server is the name of the server. It may be NULL to specify the local server. The $groupName is the name of the group you are about to delete. Comments About a GroupGiven a group name, you can get its attributes with a call to one of these functions: LocalGroupGetAttributes($server, $groupName, $comment); $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. The $comment field is a string that will have the attributes field of that group when the function returns. You can set the values of these comments using the following functions: LocalGroupSetAttributes($server, $groupName, $comment); Adding Users to a GroupTo add one or more users to a group, you can use one of these two functions: LocalGroupAddUsers($server, $groupName, $users); $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. The @user array is a list of strings of user names to add. Each string does not have to be case-sensitive in NT. The function returns true if all the users were added and false if there was an error. To add just one user name, make a list with one item in it. Removing Users from a GroupTo remove one or more users from a group, you can use one of two functions: LocalGroupDelUsers($server, $groupName, @users); $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. @user is a list of strings of user names to remove. Each string does not have to be case sensitive in NT. The function returns true if all the users were removed and false if there was an error. To delete just one user, make a list with one item in it. Checking Group MembershipTo check if a user belongs to a group, you can use one of two functions: LocalGroupIsMember($server, $groupName,$user); $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. $user is the string of the user name to check. The string does not have to be case-sensitive in NT. Each function returns true if the user is part of the group and false if the user is not part of the group. Listing Group MembersThere are two functions to list the members in a given group: LocalGroupGetMembers($server, $groupName, \@userArray) $server is the name of the server. It may be NULL to specify the local server. $groupName is the name of the group. The local members of this group are those that are local to this host. The userArray is a reference to an array of user names. The function will fill the $userArray with the members of $groupName. The GetDomainController() function returns the name of the server's domain controller. The syntax for this call is GetDomainController($server,$domain,$returnedName); $server is the name of the server. It may be NULL to specify the local server. $domain is the name of the domain you are querying. $returnedName is the name of the controller as a string. Using the Win32::Service ModuleThe Win32::Service module is used to start and stop services on an NT system. You should be a privileged user (such as Administrator) for the functions in this module to work. The Win32::Service::StartService() function starts a named service on a host. The syntax for this function is StartService($hostname, $servicename ); The name of the host at which to start the service is specified in $hostname. The value can be set to NULL for the local host. Be careful how you specify the host name, because any name resolution will generate a call to the DNS name server. If the name server relies on the service you just happen to be starting, whoops, your program may hang for a long time. $servicename is a string specifying the name of the NT service to start. This service you are attempting to start must be registered with the NT Service Control Manager. To stop a service, you can call the StopService() command. This command uses a syntax similar to StartService: StopService($hostname, $servicename ) The name of the host and service to stop are specified in the same manner as the StartService function. You can get the status of a service on a host by calling the GetStatus() function. The syntax for this call is GetStatus($hostname, $servicename, $status ); The name of the host at which to start the service is specified in $hostname. The value can be set to NULL for the local host. The name of the service is specified in $serviceName. The returned value of the status is a hash set in $status when the function returns. The keys of this hash are
For more information on the values of these items, check out the members of the SERVICE_STATUS struct in the Windows NT reference manual. A service can be paused and restarted using these functions: PauseService($hostname ,$servicename ); The $hostname and $servicename values are set the same as with other related functions. To get a list of all the services available on a host, you can use the EnumServices() function. The syntax for this function is EnumServices($hostname,\@list); The $hostname is specified the same as it is for StartService. The $list variable should be a reference to a list of service names: # Print out all services on this host Using the Win32::NetResource ModuleThe Win32::NetResource module is used to work with network resource objects in the NT system. Using these functions, you can get and set network resources while logged in as the administrator. Use the GetSharedResources function to get a list of shared resources. The syntax of this function is GetSharedResources(\@Resources,$dwType); The $dwType word specifies the type of resource to get. It can take one of these values:
@Resources is a list of references to hashes. Each hash in the list is of the type %NETRESOURCE. Each %NETRESOURCE item has the following keys:
The first item in the %NETSOURCE hash is the scope of what the resource affects. The scope of a resource can be one of the following values:
The type of resource is the same as specified in $dwType. The display type item in %NETSOURCE is the third item in the hash. It contains more information about how the object is displayed in NT. Here are the possible values:
To make a new connection, you can use the AddConnection function. The syntax for this function is AddConnection($resource,$Password,$UserName,$Flags) $resource is a reference to a %NETRESOURCE hash with the connection to make. The user name and password are provided by the user making the connection to the resources. $Flag is set to 1 if the connection has to be recorded on disk for all future logins. To break off the connection, use the CancelConnection function call. The syntax for this function call is CancelConnection($Name,$Connection,$Force); $Name is set to the name of the local device the resource is connected to. $Connection is set to the type of connection: 1 for persistent connections and 0 for nonpersistent connections. If $Force is set to 1, the connection is broken regardless of any errors that may require a delay. To see if there were any errors after a command, you can call the WNetGetLastError() function. The syntax for this function is WNetGetLastError($ErrorCode,$Description,$Name); All three arguments into this function call return a piece of information about the last error. $ErrorCode is set to the error code number, $Description contains a description of the error, and $Name is set to the name of the error. This function gets the Extended Network Error. This is only applicable if Win32::GetLastError() returns ERROR_EXTENDED_ERROR. The GetError method returns the last error for a Win32::NetResource call. The syntax for this function is GetError( $ErrorCode ); The Unc name for a local path can be derived from a local path with the GetUncName() function. The syntax for this function is GetUncName( $UncName, $LocalPath ); $UncName is set to the Unc name of the network connection. $LocalPath is the local path. To add a new share object, call the NetShareAdd function. The syntax for this function is NetShareAdd(\%SHARE,$parm_err,$servername ) %SHARE_INFO is a hash describing the share. The ShareInfo hash is used to pass information to the NetResource functions about the share objects. The keys for this hash are
The $parm_err variable is set upon returning from the function to an error value, if any. $servername is the name of the server. To offer a disk resource for sharing on the network, call the NetShareCheck() function. The syntax for this function is NetShareCheck($device,$type,$servername) $device is the name of the device to be checked for shared access. The type of share is returned in $type. The value in $type is only valid if the function returns a nonzero value. $servername is the name of the server. Use the NetShareDel function to remove a share from a machine's list of shares. The syntax for this function is NetShareDel( $netname, $servername ); The name of the share to delete is $netname, and the machine offering the share is listed in $servername. To get the %SHARE_INFO information structure, you can use the NetShareGetInfo() function. The syntax of this function is NetShareGetInfo( $netname, \%SHARE,$servername); The name of the share to get information for is named in $netname, and the machine offering the share is listed in $servername. The \%SHARE is a reference to the SHARE_INFO hash describing the share. Once you have the information, you can set its values with the NetShareSetInfo() function. The syntax is NetShareSetInfo( $netname,\%SHARE,$parm_err,$servername); The name of the share to get information for is named in $netname, and the machine offering the share is listed in $servername. The \%SHARE is a reference to the SHARE_INFO hash describing the share. Handling Input from Multiple SourcesThe Win32::Ipc module is useful when waiting for input from different types of input. In Perl on a UNIX system, you can wait on multiple sources using the select(2) call, but the select() operation excludes semaphores and messages. On an NT system you can use the Win32::Ipc module to wait on sources such as a Mutex, ChangeNotification, Semaphore, or even another process. The syntax for this call is WaitForMultipleObjects(@list , $WaitAll ,$TimeOut ); @list is a list of objects to wait for. The $WaitAll variable is set to 1 if the function has to return when all the objects have input. If $WaitAll is set to 0, the function returns when there is input for the first available object. The timeout value is given as milliseconds in $TimeOut. Here's an example of how to wait for more than one input. There are two semaphores and one Mutex to wait for in Listing 10.6. Listing 10.6. Handling input from more than one source. 1 use Win32::Mutex; SummaryThis chapter has provided enough information on how to use Win32:: and its extension modules to access Windows NT system facilities. Some of these functions may change over time and as development progresses. However, you have enough information now to write system administration applications with the Win32 version of Perl for NT.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
With any suggestions or questions please feel free to contact us |