Other Capabilities of the CreateFile Function

The CreateFile function is universal. This is because of the concept of a device adopted in the Windows operating system. In one of examples provided in Chapter 11 (see Listing 11.4), I used the CreateFile function for console output. Now, consider another example that demonstrates the principles of working with mailslots.

Mailslot

This device allows information to be exchanged between processes within the framework of a local area network, not only within a single computer. The only problem is that the mailslot volume doesn't exceed 64 KB. Nevertheless, after considering the mechanism of transmitting data using mailslots, you'll understand that the mailslot size isn't important because under the condition of bidirectional transmission, it is possible to transfer information in sequential blocks. The main idea of the mailslot mechanism is as follows :

  • Every process can create a mailslot using the CreateMailslot function. If this function completes successfully, the process gets the mailslot descriptor and the possibility of reading data from it using the ReadFile function (as if it were a file). The process that has created the mailslot is called the server.

  • After the mailslot is created, any process can connect to it ( open the mailslot) using the CreateFile function and write a portion of data there using the WriteFile function.

  • The mailslot is closed when the process that generated it terminates or when all duplicates of the mailslot handle are closed using the CloseHandle function.

  • When working with the mailslot, the following conventions about the mailslot name should be observed .

    • In general, when creating a mailslot, the \\.\mailsiot\[ path ] name name is used. Here, name is the mailslot name, and path is the path that can consist of the names of several directories separated by a slash. Note that these directories have nothing in common with the directories existing on the disk.

    • When a mailslot is opened for reading, the name used when creating it must be used. For example, if the texts mailslot was created that is, the \\. \mailsiot\texts full name was used then the same string must be used when opening the mailslot for reading.

    • If it is necessary to open the mailslot for writing and this mailslot is located on another computer of the local area network, then the following string must be used: \\ ComputerName \mailslot\[ path ] name . Here, ComputerName is the network name of the required computer.

    • If processes that create mailslots operate within the same domain, then it is possible to create a shared mailslot for several processes. For this purpose, all processes must create a mailslot with the same name. If you now open the mailslot for writing using the CreateFile function and specify the name in the following format \\ DomainName \mailslot\[ path ] name , where DomainName is the name of the domain, then all processes that have created this mailslot will receive messages. In addition, it is also possible to use the \\*\mailslot\[ path ]name for the primary domain.

Thus, after learning the main theory behind mailslots, it is possible to implement practical examples. Listings 13.1 and 13.2 provide the source code of the server software that creates a mailslot and reads messages from there, and the client that sends messages to that mailslot. Note that I have used the results of previous chapters and have written programs that can be translated using both MASM32 and TASM32. Note that starting from this chapter, most programs will be presented in this universal form.

Listing 13.1: The server software (SERVER.ASM) creates a mailslot and waits for messages
image from book
 ; Server that creates a mailslot and reads from there .586P ; Flat memory model .MODEL  FLAT, stdcall ; Constants STD_OUTPUT_HANDLE      equ -11 MAILSLOT_WAIT_FOREVER  equ -1 ; Prototypes of external procedures IFDEF MASM         EXTERN  ReadFile@20:NEAR         EXTERN  CloseHandle@4:NEAR         EXTERN  lstrlenA@4:NEAR         EXTERN  WriteConsoleA@20:NEAR         EXTERN  CreateMailslotA@16:NEAR         EXTERN  ExitProcess@4:NEAR         EXTERN  GetStdHandle@4:NEAR ELSE         EXTERN  ReadFile:NEAR         EXTERN  CloseHandlerNEAR         EXTERN  lstrlenA:NEAR         EXTERN  WriteConsoleA:NEAR         EXTERN  CreateMailslotA:NEAR         EXTERN  GetStdHandle:NEAR         EXTERN  ExitProcess:NEAR         WriteConsoleA@20 = WriteConsoleA         ReadFile@20 = ReadFile         lstrlenA@4 = lstrlenA         CreateMailslotA@16 = CreateMailslotA         ExitProcess@4  = ExitProcess         GetStdHandle@4 = GetStdHandle         CloseHandle@4 =  CloseHandle ENDIF ;  INCLUDELIB directives for the  linker IFDEF MASM         includelib c:\masm32\lib\user32.lib         includelib c:\masm32\lib\kernel32.lib ELSE         includelib c:\tasm32\lib\import32.lib ENDIF ;----------------------------------------------- ;  Data segment _DATA SEGMENT         LENS    DD ?  ;  String length will be placed here         PATHM DB "\.\mailslot\maill", 0         BUFER DB 1000  DUP.(0)         H     DD ?         N     DD ?         HANDL DD ?         ERRS  DB 'Error!', 0 _DATA ENDS ; Code segment _TEXT SEGMENT START:         PUSH  STD_OUTPUT_HANDLE         CALL  GetStdHandle@4         MOV   HANDL, EAX ; Create a mailslot         PUSH  0         PUSH  MAILSLOT_WAIT_FOREVER         PUSH  0         PUSH  OFFSET PATHM         CALL  CreateMailslotA@16         CMP   EAX,  -1         JNZ   CON         LEA   EAX,  ERRS         MOV   EDI, 1         CALL  WRITE         JMP   EXI CON:         MOV   H, EAX ; Read  from the mailslot         PUSH  0         PUSH  OFFSET N         PUSH  1000         PUSH  OFFSET BUFER         PUSH  H         CALL  ReadFile@20 ; Output the contents         LEA   EAX, BUFER         MOV   EDI, 1         CALL  WRITE ; Close the mailslot         PUSH  H         CALL  CloseHandle@4 ; Exit the program EXI:         PUSH  0         CALL  ExitProcess@4 ; Display the string (terminated with line feed) ; EAX --- To the start of the string ; EDI --- With or without the line feed WRITE   PROC ; Get the parameter length         PUSH  EAX         PUSH  EAX         CALL  lstrlenA@4         MOV   ESI, EAX         POP   EBX         CMP   EDI, 1         JNE   NO_ENT ; Trailing line feed         MOV   BYTE PTR [EBX+ESI], 13         MOV   BYTE PTR [EBX+ESI+1],  10         MOV   BYTE PTR [EBX+ESI+2],  0         ADD   EAX, 2 NO_ENT: ;  String output         PUSH  0         PUSH  OFFSET LENS         PUSH  EAX         PUSH  EBX         PUSH  HANDL         CALL   WriteConsoleA@20         RET         WRITE   ENDP _TEXT ENDS END START 
image from book
 

The SERVER.ASM program creates a mailslot and then calls the ReadFile function. Note when creating the mailslot, the MAILSLOT_WAIT_FOREVER Parameter was set. This means that the ReadFile function will wait infinitely for the data to arrive at the mailslot. The function returns control only after the arrival of the data. The mailslot contents are then displayed on the console.

To translate this program using MASM32, issue the following:

 ML /c /coff /DMASM server.ASM     LINK /SUBSYSTEM:CONSOLE server.OBJ 

To translate the same program using TASM32, issue the following:

 TASM32  /ml  server.ASM     TLINK32 -ap server.OBJ 
Listing 13.2: The client program (CLIENT.ASM) opens the mailslot and writes information there
image from book
 ;Client that opens the mailslot and writes information into it .586P ; Flat memory model .MODEL FLAT, stdcall ; Constants STD_OUTPUT_HANDLE  equ -11 GENERIC_WRITE      equ 40000000h FILE_SHARE_READ    equ 1h OPEN_EXISTING      equ  3 ; Prototypes of external procedures IFDEF MASM         EXTERN  WriteFile@20:NEAR         EXTERN  CreateFileA@28:NEAR         EXTERN  ExitProcess@4: NEAR         EXTERN   CloseHandle@4:NEAR ELSE         EXTERN  WriteFile:NEAR         EXTERN  CreateFileA:NEAR         EXTERN  ExitProcess:NEAR         EXTERN  CloseHandle:NEAR         WriteFile@20  = WriteFile         CreateFileA@28 = CreateFileA         ExitProcess@4 = ExitProcess         CloseHandle@4 =  CloseHandle ENDIF ; INCLUDELIB  directives for  the linker IFDEF MASM         includelib c:\masm32\lib\user32.lib         includelib c:\masm32\lib\kernel32.lib ELSE         includelib c:\tasm32\lib\import32.lib ENDIF ;------------------------------------------------ ; Data segment _DATA SEGMENT         PATHM DB "\.\mailslot\mail1", 0         H  DD ?         MES DB  'Hello! Server!', 0         N   DD  ? _DATA ENDS ; Code segment _TEXT SEGMENT         START:         ; Open the mailslot         PUSH  0                    ; Must be zero         PUSH  0                    ; File attribute doesn't matter         PUSH  OPEN_EXISTING        ; How to open         PUSH  0                    ; Pointer to the security attribute         PUSH  FILE SHARE_READ      ; Shared access mode         PUSH  GENERIC_WRITE        ; Access type         PUSH  OFFSET PATHM         ; Mailslot name         CALL  CreateFileA@28         MOV   H, EAX         ; Write data to the mailslot         PUSH  0         PUSH  OFFSET N         PUSH  16 ;  Message length         PUSH  OFFSET MES         PUSH  H         CALL  WriteFile@20         ;  Close the mailslot         PUSH  H         CALL  CloseHandle@4         ;  Exit EXI:         PUSH  0         CALL  ExitProcess@4 _TEXT ENDS END  START 
image from book
 

The client program opens the mailslot using the CreateFile function. Having received the descriptor, it can send the data to the mailslot. The program sends a zero-terminated string.

To translate this program using MASM32, issue the following commands:

 ML /c /coff /DMASM client.ASM     LINK /SUBSYSTEM:CONSOLE client.OBJ 

To translate it using TASM32, use the following:

 TASM32  /ml client.ASM     TLINK32 -ap client.OBJ 

The programs in Listings 13.1 and 13.2 are simple. The server program carries out a single data-read operation from the mailslot. There are no difficulties in using the mailslot for permanent data exchange. For this purpose, it is necessary to remember the following:

  • The mailslot is released in the course of data read.

  • In the course of the write operation, the contents of the mailslot are overwritten.

Principally, the client also can create a mailslot, in which there will be bidirectional data exchange between the client and the server.

Pipes

Pipes provide an efficient method of bidirectional data exchange between processes. There are two types of pipes: anonymous and named. Anonymous pipes will be covered in Chapter 18 (see Listing 18.3). This type of pipes is convenient for use within the framework of a single application for data exchange between two processes. Named pipes are more powerful. They allow data to be exchanged with applications located on different computers within a local area network. In particular, the Microsoft SQL Server uses named pipes as one of the possible mechanisms of information exchange with clients .

Naturally, before using a named pipe, it is necessary to create it. For this purpose, the CreateNamePipe function is used. The process that creates the named pipe is called the server. When creating a named pipe, it is necessary to set several parameters that influence the way, in which this object will operate. The list of these parameters includes the parameter that defines the mode of operation through the pipe. Three modes of operation can be set:

  • Bidirectional (duplex)This method assumes the possibility of bidirectional data exchange: from server to client and from client to server.

  • Two unidirectional (simplex) pipes They assume unidirectional data transmission only.

Generally, the pipe name is represented by the following string: \\.\pipe\pipename . Here, pipename is the name of the pipe. As with mailslots, for named pipes it is possible

to set the mode for infinite waiting. In this case, the ReadFile and writeFile functions will complete execution only when data transmission is completed. Having created the pipe, use the ConnectNamedPipe function to allow client processes to connect to the pipein other words, to switch the server process to the waiting state.

The client process, as with mailslots, can connect to the pipe using the all-embracing CreateFile function. To open the pipe, it must use the same structure of the pipe name: \\.\pipe \ pipename . Thus, the client process must know the name of the pipe, to which it connects. If this attempt has failed, use the GetLastError function to discover the cause of the error. If the function returns the ERROR_PIPE_BUSY = 231 error code, [i] this means that the pipe is busy serving another process and it is necessary to wait until that process releases the pipe. To set the waiting mode, use the WaitNamedPipe function.

Disk Drives

The CreateFile function can also open disk devices. To open the first disk of your computer, it is necessary to use the \\.\PhysicalDrive0 name; to open the C: partition, use the \\. \C : name. The most interesting fact here is that after opening the device, you can use the ReadFile and WriteFile functions. [ii] Additionally, you have the DeviceIoControl function at your disposal. The latter function can carry out various operations, including getting statistics about the disk and even formatting the disk. I won't concentrate attention on this function but, instead, will provide an example illustrating the reading of the Master Boot Record (MBR) of the disk. When the device is opened, the MBR will be located at the starting position of the hypothetical file (Listing 13.3).

Listing 13.3: Reading the disk master boot record and partition table
image from book
 .586P ;  Flat memory model .MODEL FLAT,  stdcall ;  Constants          STD_OUTPUT_HANDLE  equ -11          GENERIC_READ       equ 80000000h          FILE_SHARE_WRITE   equ 2h          OPEN_EXISTING      equ 3 ;  Prototypes  of external procedures IFDEF MASM          EXTERN   GetLastError@0:NEAR          EXTERN   wsprint fA:NEAR          EXTERN   lstrlenA@4:NEAR          EXTERN   ReadFile@20:NEAR          EXTERN   CreateFileA@28:NEAR          EXTERN   ExitProcess@4:NEAR          EXTERN   CloseHandle@4:NEAR          EXTERN   WriteConsoleA@20:NEAR          EXTERN   GetStdHandle@4:NEAR ELSE         EXTERN   GetLastError:NEAR         EXTERN  _wsprintfA:NEAR         EXTERN   GetStdHandle:NEAR         EXTERN   lstrlenA:NEAR         EXTERN  ReadFile:NEAR         EXTERN  CreateFileA:NEAR         EXTERN  ExitProcess:NEAR         EXTERN  CloseHandle:NEAR         EXTERN  WriteConsoleA:NEAR         GetLastError@0 = GetLastError         wsprintfA = 0 wsprintfA         GetStdHandle@4'= GetStdHandle         WriteConsoleA@20 = WriteConsoleA         lstrlenA@4 = lstrlenA         ReadFile@20 = ReadFile         CreateFileA@28 = CreateFileA         ExitProcess@4 =  ExitProcess         CloseHandle@4 =  CloseHandle ENDIF ;  INCLUDELIB directives for  the linker IFDEF MASM         includelib c:\masm32\lib\user32.lib         includelib c:\masm32\lib\kernel32.lib ELSE         includelib c:\tasm32\lib\import32.lib ENDIF ;------------------------------------------------ ;  Data segment _DATA SEGMENT         H            DD 0         NN           DD 0         ; Device name (first hard disk)         PATHM        DB "\.\PhysicalDrive0",  0         ALIGN        4  ; Alignment by the double-word boundary         BUF          DB 512 DUP(0)         BUF1         DB 24  DUP(0)         HANDL        DD 0         LENS         DD 0         ERRS         DB "Error %u", 0         SINGL        DB "Signature %x", 0 _DATA ENDS ;  Code segment _TEXT SEGMENT         START:         PUSH  STD_OUTPUT_HANDLE         CALL  GetStdHandle@4         MOV   HANDL,  EAX         ;  Open the physical disk         PUSH  0              ; Must be zero         PUSH  0              ; File attribute doesn't matter         PUSH  OPEN_EXISTING  ; How to open         PUSH  0              ; Pointer to the security attribute = NULL         PUSH  FILE_SHARE_WRITE         ; Shared access mode         PUSH  GENERIC_READ             ; Access type - Read         PUSH  OFFSET PATHM             ; Device name         CALL  CreateFileA@28         CMP   EAX,  -1         JNZ   NO_ERR ER:         ;  Get error number         CALL  GetLastError@0         ;  MOVZX EAX, AX         PUSH  EAX         PUSH  OFFSET ERRS         PUSH  OFFSET BUF1         CALL  wsprintfA         ;  Output error number         LEA    EAX, BUF1         MOV    EDI, 1         CALL  WRITE         JMP    EXI NO_ERR:         MOV    H, EAX         ;  Reading the partition table         PUSH  0         PUSH  OFFSET NN         PUSH  512         PUSH  OFFSET BUF         PUSH  H         CALL  ReadFile@20         CMP    EAX, 0         JZ     ER         ;  Display the partition table signature         ; Must be aa55         PUSH   DWORD PTR BUF+510         PUSH   OFFSET SINGL         PUSH  OFFSET BUF1         CALL  wsprintfA         LEA   EAX, BUF1         MOV   EDI, 1         CALL  WRITE         ; Close the device         PUSH  H         CALL  CloseHandle@4         ; Exit EXI:         PUSH  0         CALL  ExitProcess@4         ; Display the string terminated by line feed         ; EAX --- To the start of the string         ; EDI --- With or without the line feed WRITE   PROC ;  Get the parameter length         PUSH  EAX         PUSH  EAX         CALL  lstrlenA@4         MOV   ESI, EAX         POP   EBX         CMP   EDI, 1         JNE   NO_ENT         ; The string is terminated with the line feed         MOV   BYTE PTR [EBX+ESI], 13         MOV   BYTE PTR [EBX+ESI+1], 10         MOV   BYTE PTR [EBX+ESI+2], 0         ADD   EAX, 2         NO_ENT: ;  String output         PUSH  0         PUSH  OFFSET LENS         PUSH  EAX         PUSH  EBX         PUSH  HANDL         CALL  WriteConsoleA@20         RET WRITE   ENDP _TEXT ENDS END START 
image from book
 

Now, it is necessary to provide some comments about Listing 13.3.

Note that the starting point of the buffer, into which the sector will be read, must be aligned by the 4-byte boundary. To ensure this, the ALIGN directive is used. Such alignment is not needed for reading from a normal file except when you disable data caching (see the description of the CreateFile function in the opening section of this chapter).

In this program, I have used the GetLastError function for the first time. If an error occurs when you open or read from the device, the program will output the error code to the console. To determine the cause of the error, consult the documentation. You can also try to change the parameters of the CreateFile and ReadFile functions and view the error codes that will result. In fact, such experimenting is instructive.

To translate this program, issue the following commands using MASM32:

 ML /c /coff /DMASM prog.ASM     LINK  /SUBSYSTEM:CONSOLE prog.OBJ 
  • Issue the following commands using TASM32:

     TASM32 /ml  prog.ASM TLINK32 -ap prog.OBJ 

[i] Remember that to discover the cause of the error by its number, it is convenient to use the ERRLOOK.EXE program supplied as part of Microsoft Visual Studio.NET.

[ii] Do not write anything in such a way without carefully studying the disk structure before proceeding.



The Assembly Programming Master Book
The Assembly Programming Master Book
ISBN: 8170088178
EAN: 2147483647
Year: 2004
Pages: 140
Authors: Vlad Pirogov

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net