home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / docs / pmgvol1.inf (.txt) < prev    next >
Encoding:
OS/2 Help File  |  1994-03-07  |  345.2 KB  |  13,848 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Introduction to the Control Program ΓòÉΓòÉΓòÉ
  3.  
  4. The OS/2 operating system is an advanced, multitasking, single-user, operating 
  5. system for personal computers. The operating system has a rich application 
  6. programming interface (API) that supports: 
  7.  
  8. o Multitasking 
  9. o Interprocess communication 
  10. o Error and exception handling 
  11. o Dynamic (run-time) linking 
  12. o Graphical user interface (GUI). 
  13. The operating system also provides advanced file system features such as 
  14. installable file systems, extended file attributes, and long file names. 
  15.  
  16. The OS/2 operating system runs on and takes full advantage of the 80386 
  17. microprocessor. Features based on the 80386 microprocessor include: 
  18.  
  19. o 32-bit operands and operations 
  20. o Flat (non-segmented) 4 gigabyte address space 
  21. o 32-bit memory pointers 
  22. o Hardware-based memory protection and task management. 
  23. The OS/2 operating system provides a windowed, graphical user interface called 
  24. the Presentation Manager (PM). 
  25.  
  26.  
  27. ΓòÉΓòÉΓòÉ 1.1. Control Program Functionality ΓòÉΓòÉΓòÉ
  28.  
  29. The lowest-level functions supplied by the OS/2 operating system are those 
  30. provided by the kernel and the kernel's subsystems-the control programs of the 
  31. operating system. The Control Program functions involve the most basic aspects 
  32. of program execution, such as memory management, file handling, and process, 
  33. thread, and session management. They also involve more sophisticated 
  34. programming tasks, such as exception handling and interprocess communications. 
  35. The names of all the system functions in the Control Program API are prefixed 
  36. with the letters "Dos", as in DosAllocMem. 
  37.  
  38. The book describes the following topics from the operating system's Control 
  39. Program API: 
  40.  
  41. o File and disk management 
  42. o Memory management 
  43. o Program execution control (Process and session management) 
  44. o Semaphores 
  45. o Pipes 
  46. o Queues 
  47. o Timing functions 
  48. o Error handling 
  49. o Exception handling 
  50. o Device I/O support 
  51. o Message management 
  52. o National language support and code page management 
  53. o Debugging. 
  54. The Presentation Manager windowed GUI is covered in the Programming Guide: 
  55. Volume II. The graphics programming interface is described in the Programming 
  56. Guide:  Volume III. 
  57.  
  58.  
  59. ΓòÉΓòÉΓòÉ 1.1.1. File Systems and File Management ΓòÉΓòÉΓòÉ
  60.  
  61. The file system is the component of the operating system that supports storing 
  62. information on mass storage devices, such as hard disks and floppy disks. 
  63. Applications view a file as a logical sequence of data; the file system manages 
  64. the physical locations of data on the storage device for the application and 
  65. specifies how the device and the stored information are formatted. 
  66.  
  67. The file system also manages file I/O operations. Applications use file system 
  68. functions to open, read, write, and close disk files. File system functions 
  69. enable an application to maintain the disk that holds the files-volumes, 
  70. directories, and files on the disks of the computer. Applications also use OS/2 
  71. file system functions to perform I/O operations to pipes and peripheral devices 
  72. connected to the computer, like the printer. 
  73.  
  74. The file system also supports redirection of input and output, for example 
  75. redirecting output from the monitor to a disk file or to the printer. 
  76.  
  77. There are two types of file systems supported by the OS/2 operating system. The 
  78. first is the File Allocation Table (FAT) file system. The FAT file system is 
  79. the file system used by DOS. The second type of file system supported by the 
  80. operating system is the installable file system (IFS). Installable file systems 
  81. are external to the base operating system and are loaded by the operating 
  82. system when the computer is started. The High Performance File System (HPFS) 
  83. included with the OS/2 operating system is an installable file system. 
  84.  
  85.  
  86. ΓòÉΓòÉΓòÉ 1.1.2. Memory Management ΓòÉΓòÉΓòÉ
  87.  
  88. The key features of OS/2 memory management are paged virtual memory and a 
  89. 32-bit linear (flat) address space that is mapped through page tables to 
  90. physical memory. This is in contrast to the segmented memory model used in 
  91. previous versions of the operating system. 
  92.  
  93. An application can allocate memory for its own use, or to be shared with other 
  94. applications. 
  95.  
  96.  
  97. ΓòÉΓòÉΓòÉ 1.1.3. Program Execution and Control ΓòÉΓòÉΓòÉ
  98.  
  99. Multitasking is the ability of the operating system to manage the execution of 
  100. more than one application at a time. For the programmer, this includes the 
  101. ability to multitask your own programs. 
  102.  
  103. The OS/2 operating system supports two forms of multitasking for programs. An 
  104. application can start other programs that will execute concurrently with the 
  105. application. These programs can be a new copy of the application, a related 
  106. program that is designed to work with the application, or an unrelated program. 
  107. The operating system provides functions to communicate with and control the 
  108. programs started by the application. 
  109.  
  110. The OS/2 operating system also enables applications to run multiple threads of 
  111. execution within the same application;  separate activities can be multitasked 
  112. within the application. An example of this is dispatching a separate subroutine 
  113. to load a file and having the subroutine execute at the same time the main 
  114. routine continues to monitor and respond to user input. 
  115.  
  116.  
  117. ΓòÉΓòÉΓòÉ 1.1.4. Semaphores ΓòÉΓòÉΓòÉ
  118.  
  119. Semaphores signal the beginning and ending of an operation and provide mutually 
  120. exclusive ownership of resources. Typically, semaphores are used to prevent 
  121. more than one process or thread within a process from accessing a resource, 
  122. such as shared memory, at the same time. 
  123.  
  124. Semaphores are defined by the system and reside in an internal memory buffer. 
  125. They are divided into three types, according to the functionality they provide: 
  126.  
  127. o Event semaphores enable a thread to notify waiting threads that an event has 
  128.   occurred. 
  129.  
  130. o Mutual exclusion (mutex) semaphores enable threads to serialize their access 
  131.   to shared resources. 
  132.  
  133. o Multiple Wait (muxwait) semaphores enable threads to wait either for multiple 
  134.   events to occur, or for multiple resources to become available. 
  135.  
  136.  
  137. ΓòÉΓòÉΓòÉ 1.1.5. Pipes ΓòÉΓòÉΓòÉ
  138.  
  139. A pipe is a named or unnamed buffer used to pass data between processes. A 
  140. process writes to or reads from a pipe as though the pipe were standard input 
  141. or standard output. A parent process can use pipes to control the input that a 
  142. child process receives and to receive the output that the child process 
  143. produces. There are two types of pipes-named and unnamed. 
  144.  
  145.  
  146. ΓòÉΓòÉΓòÉ 1.1.6. Queues ΓòÉΓòÉΓòÉ
  147.  
  148. A queue is a named, ordered list of elements that is used to pass information 
  149. between related or unrelated processes. The owner of the queue (the server 
  150. process) can choose the order in which to read incoming information and can 
  151. examine queue elements without removing them from the queue. Queue elements can 
  152. be added and accessed in First-In-First-Out (FIFO), Last-In-First-Out (LIFO), 
  153. or priority-based order. 
  154.  
  155.  
  156. ΓòÉΓòÉΓòÉ 1.1.7. Timers ΓòÉΓòÉΓòÉ
  157.  
  158. Timers enable an application to suspend operation for a specific length of 
  159. time, to block a thread of execution until an interval has elapsed, or to post 
  160. an event semaphore at repeated intervals. 
  161.  
  162.  
  163. ΓòÉΓòÉΓòÉ 1.1.8. Error Management ΓòÉΓòÉΓòÉ
  164.  
  165. The OS/2 operating system provides functions to facilitate error processing. 
  166. DosErrClass returns a classification of the error and a recommended action. 
  167. DosError enables an application to prevent the operating system from displaying 
  168. the default error message in a pop-up window when either a hard error or a 
  169. software exception occurs. 
  170.  
  171.  
  172. ΓòÉΓòÉΓòÉ 1.1.9. Exception Management ΓòÉΓòÉΓòÉ
  173.  
  174. A multitasking operating system must manage applications carefully. A serious 
  175. error (such as an attempt to access protected memory) occurring in one 
  176. application cannot be permitted to damage any other application in the system. 
  177. To manage errors that might damage other applications, the OS/2 operating 
  178. system defines a class of error conditions called exceptions and defines 
  179. default actions for those errors. 
  180.  
  181. An exception is an abnormal condition that can occur during program execution. 
  182. Common causes of exceptions include I/O errors and access protection 
  183. violations. When an exception is caused by the user pressing Ctrl+Break or 
  184. Ctrl+C, the exception is called a signal exception. 
  185.  
  186. When an exception occurs, the default action usually taken by the operating 
  187. system is to terminate the application that caused the exception. An 
  188. application can register its own exception handling routine and try to handle 
  189. the exception itself. It might be possible for the application to correct the 
  190. condition that caused the exception and continue execution. 
  191.  
  192.  
  193. ΓòÉΓòÉΓòÉ 1.1.10. Device I/O ΓòÉΓòÉΓòÉ
  194.  
  195. The OS/2 operating system uses devices to communicate with the real world. A 
  196. device is a piece of hardware used for input and output. Devices used with 
  197. computers include the keyboard, video display, mouse, floppy and fixed disk 
  198. drives, and external systems, such as modems and printers. The operating system 
  199. supplies functions that can be used to access and control such devices. 
  200.  
  201.  
  202. ΓòÉΓòÉΓòÉ 1.1.11. Message Management ΓòÉΓòÉΓòÉ
  203.  
  204. For full-screen applications, text messages-used by an application to display 
  205. information to the user-can be held in a message file. Keeping an application's 
  206. messages in a message file simplifies changing those messages, which, for 
  207. example, can facilitate marketing an application in several countries 
  208. simultaneously. 
  209.  
  210.  
  211. ΓòÉΓòÉΓòÉ 1.1.12. National Language Support and Code Page Management ΓòÉΓòÉΓòÉ
  212.  
  213. Many applications must support more than one national language, for example, 
  214. French and German. This requirement is simplified through the use of such 
  215. resources as string tables, menu templates, dialog templates, and accelerator 
  216. tables. 
  217.  
  218. A code page is a table that defines how characters are encoded. Code page 
  219. management enables a user to select a code page for keyboard input, and screen 
  220. and printer output before starting an application, a system command, or a 
  221. utility program in the OS/2 multitasking environment. 
  222.  
  223.  
  224. ΓòÉΓòÉΓòÉ 1.1.13. Debugging ΓòÉΓòÉΓòÉ
  225.  
  226. Debugging is the process of detecting, diagnosing, and eliminating errors in 
  227. programs. A debugger program is designed to interact with the application that 
  228. it is debugging. Because of the protected mode architecture of the OS/2 
  229. operating system, special steps must be taken to allow a debugging program to 
  230. perform its functions in the program being debugged. DosDebug enables one 
  231. application to control the execution of another application for debugging 
  232. purposes. 
  233.  
  234.  
  235. ΓòÉΓòÉΓòÉ 2. Debugging ΓòÉΓòÉΓòÉ
  236.  
  237. Debugging is the process of detecting, diagnosing, and eliminating errors in 
  238. programs. A debugger application is designed to interact with and control the 
  239. application that it is debugging. Because of the protected mode architecture of 
  240. the OS/2 operating system, special steps must be taken to enable a debugger 
  241. application to perform its functions in the application being debugged (for 
  242. example, to examine and manipulate memory locations in the address space of 
  243. another process). 
  244.  
  245. The following topic is related to the information in this chapter: 
  246.  
  247. Program Execution and Control. 
  248.  
  249.  
  250. ΓòÉΓòÉΓòÉ 2.1. About Debugging ΓòÉΓòÉΓòÉ
  251.  
  252. DosDebug  enables one application to control the execution of another 
  253. application for debugging purposes. 
  254.  
  255. An application is selected for debugging when it is started. DosExecPgm and 
  256. DosStartSession both have flags that can be used to specify that the 
  257. application being started is to be controlled by the starting application. 
  258.  
  259. DosExecPgm starts an application within a new process. DosStartSession starts a 
  260. new session within which one or more processes can be executing. See 
  261. DosStartSession and DosExecPgm for details on how to start an application for 
  262. debugging purposes. For information on processes and sessions, see Program 
  263. Execution Control in this book. 
  264.  
  265. Once a process has been selected for debugging, DosDebug  is used to control 
  266. its execution and to examine and manipulate its variables. 
  267.  
  268. DosDebug  provides a full set of debugging commands, including execution 
  269. control commands-like single stepping and setting watchpoints-and commands to 
  270. examine and manipulate the memory and registers of the process being debugged. 
  271. The debugger process can access specific threads within a process being 
  272. debugged and specific processes within a session being debugged. 
  273.  
  274. DosDebug  also has a rich set of notification messages to keep the debugger 
  275. application informed of activities occurring during the execution of the 
  276. application being debugged. 
  277.  
  278. The debugger application can use the session and process control functions 
  279. described in Program Execution Control to control the child process or session 
  280. being debugged. For example, the debugger can use DosSelectSession to switch 
  281. itself, or the session being debugged, to the foreground. 
  282.  
  283.  
  284. ΓòÉΓòÉΓòÉ 2.2. Using the Debugging Function ΓòÉΓòÉΓòÉ
  285.  
  286. DosDebug  provides a set of commands that permit one process to control another 
  287. process for debugging. 
  288.  
  289. In the following code fragment, the calling process uses DosDebug  to modify a 
  290. word in a controlled process. All the necessary steps have already been taken 
  291. so that the calling process controls the second process-the process identifier 
  292. of the controlled process has been placed into PID, the address of the word to 
  293. be modified in the controlled process has been placed into Addr, and the value 
  294. to be substituted in the controlled process has been placed into Value. 
  295.  
  296. (Due to the size of the debug_buffer data structure, the code fragment has been 
  297. divided into two figures. If you were actually entering this into a program, 
  298. the information would be together as if it were all one figure.) 
  299.  
  300. Note:  In the example code fragments that follow, error checking was left out 
  301.        to conserve space. Applications should always check the return code that 
  302.        the functions return. Control Program functions return an APIRET value. 
  303.        A return code of 0 indicates success. If a non-zero value is returned, 
  304.        an error occurred. 
  305.  
  306.     #define INCL_DOSPROCESS   /* Process and thread values */
  307.     #include <os2.h>
  308.     #include <stdio.h>
  309.  
  310.     struct debug_buffer {
  311.         ULONG   Pid;        /* Debuggee Process ID       */
  312.         ULONG   Tid;        /* Debuggee Thread ID        */
  313.         LONG    Cmd;        /* Command or Notification   */
  314.         LONG    Value;      /* Generic Data Value        */
  315.         ULONG   Addr;       /* Debuggee Address          */
  316.         ULONG   Buffer;     /* Debugger Buffer Address   */
  317.         ULONG   Len;        /* Length of Range           */
  318.         ULONG   Index;      /* Generic Identifier Index  */
  319.         ULONG   MTE;        /* Module Table Entry Handle */
  320.         ULONG   EAX;        /* Register Set              */
  321.         ULONG   ECX;
  322.         ULONG   EDX;
  323.         ULONG   EBX;
  324.         ULONG   ESP;
  325.         ULONG   EBP;
  326.         ULONG   ESI;
  327.         ULONG   EDI;
  328.         ULONG   EFlags;
  329.         ULONG   EIP;
  330.         ULONG   CSLim;      /* Byte Granular Limits      */
  331.         ULONG   CSBase;     /* Byte Granular Base        */
  332.         UCHAR   CSAcc;      /* Access Bytes              */
  333.         UCHAR   CSAtr;      /* Attribute Bytes           */
  334.         USHORT  CS;
  335.         ULONG   DSLim;
  336.         ULONG   DSBase;
  337.         UCHAR   DSAcc;
  338.         UCHAR   DSAtr;
  339.         USHORT  DS;
  340.         ULONG   ESLim;
  341.         ULONG   ESBase;
  342.         UCHAR   ESAcc;
  343.         UCHAR   ESAtr;
  344.         USHORT  ES;
  345.         ULONG   FSLim;
  346.         ULONG   FSBase;
  347.         UCHAR   FSAcc;
  348.         UCHAR   FSAtr;
  349.         USHORT  FS;
  350.         ULONG   GSLim;
  351.         ULONG   GSBase;
  352.         UCHAR   GSAcc;
  353.         UCHAR   GSAtr;
  354.         USHORT  GS;
  355.         ULONG   SSLim;
  356.         ULONG   SSBase;
  357.         UCHAR   SSAcc;
  358.         UCHAR   SSAtr;
  359.         USHORT  SS;
  360.     };
  361.  
  362. The debug_buffer Data Structure 
  363.  
  364.     struct  debug_buffer  DbgBuf;    /* Debug buffer                         */
  365.     ULONG   PID;                     /* Process ID of the controlled process */
  366.     ULONG   Addr;                    /* Address in the controlled process    */
  367.     LONG    Value;                   /* Value to be substituted in the       */
  368.                                      /* controlled process                   */
  369.     APIRET  rc;                      /* Return code                          */
  370.  
  371.     DbgBuf.Cmd = DBG_C_WriteMem;     /* Indicate that a Write Word           */
  372.                                      /* command is requested                 */
  373.  
  374.     DbgBuf.Pid = PID;                /* Place PID of controlled process      */
  375.                                      /* into the debug buffer                */
  376.  
  377.     DbgBuf.Addr = Addr;              /* Place the word address (within the   */
  378.                                      /* controlled process) into the debug   */
  379.                                      /* buffer                               */
  380.  
  381.     DbgBuf.Value = Value;            /* Place the value to be updated into   */
  382.                                      /* the specified word of the controlled */
  383.                                      /* process                              */
  384.  
  385.     rc = DosDebug(&DbgBuf);
  386.  
  387.     if (rc != 0) {
  388.        printf("DosDebug error: return code = %ld", rc);
  389.        return;
  390.     }
  391.  
  392.     /* Be sure to check DbgBuf.Cmd for the notification returned by DosDebug */
  393.  
  394.  
  395. Modifying a WORD in a Process Being Debugged 
  396.  
  397. The Cmd field in the debug buffer is used for two purposes. On input, the Cmd 
  398. field is used to pass the commands that direct DosDebug 's activities. On 
  399. output, the Cmd field is used by DosDebug  to return a notification indicating 
  400. the events and activities that occurred during the call. 
  401.  
  402. If DosDebug  returns no error, a notification resides in the Cmd field of the 
  403. debug buffer. The data returned with the notification varies, depending on the 
  404. command passed in the Cmd field of the debug buffer data structure when 
  405. DosDebug  was called. 
  406.  
  407. Not all fields in the debug buffer have to be defined on every DosDebug 
  408. command. The same field can have a different meaning in different DosDebug 
  409. commands. 
  410.  
  411. Some notifications (such as DBG_N_ModuleLoad and DBG_N_NewProc) might require 
  412. multiple returns to the debugger. These additional, pending notifications will 
  413. be returned before the process being debugged is permitted to execute any more 
  414. user code, and will be returned on the Go, Single Step, or Stop commands. 
  415.  
  416. Additional notifications can be pending at any time, so a debugger must be 
  417. ready to handle any notification any time a Go, Single Step, or Stop command is 
  418. called. 
  419.  
  420.  
  421. ΓòÉΓòÉΓòÉ 2.3. Summary of Functions Used for Debugging ΓòÉΓòÉΓòÉ
  422.  
  423. Following are the OS/2 functions used for debugging. 
  424.  
  425. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  426. ΓöéFunction                      ΓöéDescription                   Γöé
  427. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  428. ΓöéDosDebug                      ΓöéUsed by one process to controlΓöé
  429. Γöé                              Γöéanother for debugging         Γöé
  430. Γöé                              Γöépurposes.                     Γöé
  431. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  432.  
  433.  
  434. ΓòÉΓòÉΓòÉ 3. Exception Management ΓòÉΓòÉΓòÉ
  435.  
  436. An exception is an abnormal condition that can occur during program execution. 
  437. Common causes of exceptions include: 
  438.  
  439. o I/O errors 
  440. o Protection violations 
  441. o Math errors 
  442. o Intervention by the user or by another process. 
  443. Activities that can cause exceptions include: 
  444.  
  445. o Trying to use memory that you do not have permission to access 
  446. o Dividing by 0 
  447. o The user pressing Ctrl+Break. 
  448. Exceptions include both unexpected errors (such as a memory protection 
  449. violation) and expected errors (such as guard-page exceptions). Exceptions can 
  450. be a synchronous exception, that is, caused by an action of the executing 
  451. thread, or an asynchronous exception, caused by an event external to the 
  452. executing thread (such as the user pressing Ctrl+Break). When an exception is 
  453. caused by the user pressing Ctrl+Break or Ctrl+C, or by another process issuing 
  454. DosKillProcess for your process, the exception is called a signal exception. 
  455.  
  456. In most cases, the default action taken by the operating system when an 
  457. exception occurs is to terminate the application that caused the exception. 
  458. Rather than having the operating system default action occur, an application 
  459. can register its own subroutine to handle exceptions. These routines are called 
  460. exception handlers. Exception handlers enable an application to handle some 
  461. errors itself, allowing the application to avoid termination (or at least to 
  462. terminate gracefully). 
  463.  
  464. When exception handlers are registered, they are added to an exception handler 
  465. chain. The chain starts empty and each new handler is added to the head of the 
  466. chain. Exceptions are passed to the exception handlers in the chain in 
  467. Last-In-First-Out order, so the last exception handler to be registered is the 
  468. first one to get an opportunity to handle each exception. 
  469.  
  470. Exception handlers have the capability to complete critical code sections 
  471. without being interrupted by other asynchronous exceptions; these critical code 
  472. sections are called must-complete sections. 
  473.  
  474. Exception handlers can be removed from the exception handler chains with 
  475. DosUnsetExceptionHandler. Another way that exception handlers can be removed 
  476. from the chain is with an unwind operation. When unwinding an exception 
  477. handler, the exception handler is first called, then removed from the exception 
  478. handler chain. 
  479.  
  480. The following topics are related to the information in this chapter: 
  481.  
  482. o Memory 
  483. o Program Execution and Control. 
  484.  
  485.  
  486. ΓòÉΓòÉΓòÉ 3.1. About Exception Management ΓòÉΓòÉΓòÉ
  487.  
  488. A multitasking operating system must manage applications carefully. A serious 
  489. error (such as an attempt to access protected memory) occurring in one 
  490. application cannot be permitted to damage any other application in the system. 
  491. To manage errors that might damage other applications, the OS/2 operating 
  492. system defines a class of error conditions called exceptions and defines 
  493. default actions for those errors. 
  494.  
  495. When an exception occurs, the default action taken by the operating system is 
  496. usually to terminate the application causing the exception (unless the 
  497. application has registered its own exception handling routines). In some cases, 
  498. when the exception can safely be ignored, execution is allowed to continue. 
  499.  
  500. Rather than having the operating system default action occur, an application 
  501. can register its own exception handlers routines. An exception handler routine 
  502. could be written to correct certain error conditions-when these error 
  503. conditions occur, the thread's exception handler gets the exception, corrects 
  504. the condition, and the thread continues executing rather than being terminated 
  505. immediately by the operating system. The operating system's default action is 
  506. taken if there are no user-defined exception handling routines or if all 
  507. user-defined routines return without handling the exception. 
  508.  
  509. An application can use DosSetExceptionHandler to register an exception handling 
  510. routine. DosSetExceptionHandler takes a pointer to an 
  511. EXCEPTIONREGISTRATIONRECORD data structure as its only argument. The first 
  512. field in this data structure is a pointer to the previous exception handler in 
  513. the chain. This field is maintained by the operating system and must never be 
  514. modified by an application. The second field is a pointer to the exception 
  515. handling routine that will be registered by the operating system. 
  516.  
  517. A single exception handler can be used to handle all the exceptions that you 
  518. choose to handle. It is not necessary to have a separate exception handler for 
  519. each exception. 
  520.  
  521. Once an exception handling routine is registered, the system will notify it 
  522. when an exception occurs. The operating system sends synchronous exceptions 
  523. only to the thread causing the exception. An application must register an 
  524. exception handler for each thread that is handling exceptions. When the 
  525. operating system terminates an application, however, a process-termination 
  526. exception is sent to all threads used by the application to be terminated. When 
  527. the user presses Ctrl+Break, an asynchronous signal exception is sent only to 
  528. Thread 1, the main thread, of the executing process. 
  529.  
  530. The exception handling routine is passed the following four parameters that 
  531. provide exception-specific information: 
  532.  
  533. EXCEPTIONREPORTRECORD 
  534.    Describes the exception and its parameters. The first field of this data 
  535.    structure contains the number of the exception that occurred. 
  536.  
  537. EXCEPTIONREGISTRATIONRECORD 
  538.    The EXCEPTIONREGISTRATIONRECORD data structure used to initially register 
  539.    the exception handler. This is a microprocessor-specific value. 
  540.  
  541. ContextRecord 
  542.    Describes the machine state at the time the exception occurred. 
  543.  
  544. DispatcherContext 
  545.    Contains state information on nested exception and collided unwinds. This 
  546.    information must not be modified by the application. 
  547. Details of the parameters and data structures can be found in Exception Handler 
  548. Interface. 
  549.  
  550. The operating system places the exception handlers for each thread in an 
  551. exception handler chain. Registering an exception handler adds it to the head 
  552. of the chain. 
  553.  
  554. When an application registers an exception handler, the exception handler is 
  555. added to the head of the chain. If the application calls a routine in a dynamic 
  556. link library (DLL), the DLL might register an exception handler in case there 
  557. is an exception while its code is executing; the DLL deregisters the exception 
  558. handler before returning control to the application. The DLL's exception 
  559. handler would be ahead of the application's exception handler in the chain. 
  560.  
  561. Exception handlers in the chain are notified of an exception in 
  562. Last-In-First-Out (LIFO) order. Thus, if an exception occurs while your thread 
  563. is executing, the exception handler for your thread is notified of the 
  564. exception first. If your exception handler chooses to handle the exception, the 
  565. earlier exception handlers in the chain never see the exception. If your 
  566. exception handler chooses not to handle the exception, it is passed along to 
  567. the next earlier exception handler in the chain. If no exception handler in the 
  568. chain chooses to handle the exception, the operating system takes the default 
  569. action for the exception. 
  570.  
  571. If an exception happens while DLL code is executing, and if the DLL's exception 
  572. handler chooses to handle the exception, your application's exception handlers 
  573. will never be aware it. 
  574.  
  575.  
  576. ΓòÉΓòÉΓòÉ 3.1.1. System Exceptions ΓòÉΓòÉΓòÉ
  577.  
  578. The operating system defines a class of error conditions called system 
  579. exceptions, and specifies the default actions that are taken when these system 
  580. exceptions occur. The default action taken by the operating system in most 
  581. cases is to terminate the thread that caused the system exception. 
  582.  
  583. System exceptions include both synchronous and asynchronous exceptions. 
  584. Synchronous exceptions are caused by events that are internal to the execution 
  585. of a thread. For example, synchronous exceptions could be caused by invalid 
  586. parameters, or by the request of a thread to end its own execution. 
  587.  
  588. Asynchronous exceptions are caused by events that are external to the execution 
  589. of a thread. For example, an asynchronous exception can be caused by a user 
  590. entering a Ctrl+C or Ctrl+Break key sequence, or by a process calling 
  591. DosKillProcess to end the execution of another process. 
  592.  
  593. The Ctrl+Break, Ctrl+C, and DosKillProcess-generated exceptions are also known 
  594. as signals, or as signal exceptions. 
  595.  
  596. The operating system delivers exceptions that occur in 16-bit as well as 32-bit 
  597. code. The sequence or hierarchy for delivering exceptions is as follows: 
  598.  
  599. o When an exception occurs in 32-bit code, the system gives control only to the 
  600.   32-bit exception handlers registered for the current thread. If the thread 
  601.   has not registered any 32-bit handlers, the system default action occurs. 
  602.  
  603. o When an exception occurs in 16-bit code, the system first gives control to 
  604.   the 32-bit exception handlers registered for the current thread. If the 
  605.   exception is not handled by one of these handlers, control is passed to the 
  606.   16-bit handler, if one exists for the given exception. If there is no 16-bit 
  607.   handler for the exception, the system default action occurs. 
  608.  
  609. Notification of an exception is usually sent only to the thread that caused the 
  610. exception. However, if a thread uses DosExit to terminate all the threads in 
  611. the process, notification of the process-termination exception is sent to every 
  612. thread in the process. The thread that used DosExit gets a 
  613. XCPT_PROCESS_TERMINATE exception, all the other threads in the process get a 
  614. XCPT_ASYNC_PROCESS_TERMINATE exception. 
  615.  
  616. Exit-list processing occurs on a per-process basis after a process-termination 
  617. exception has been delivered to each thread in the process and each thread has 
  618. finally ended except Thread 1 (the main thread). Therefore, any thread that 
  619. handles a process-termination exception must eventually end its own execution 
  620. voluntarily. Otherwise, the process-termination sequence will not conclude 
  621. properly. 
  622.  
  623. The following tables briefly list the possible exceptions. For more detailed 
  624. information about the system exceptions, including default system action, 
  625. parameters, and related trap numbers, see the Control Program Programming 
  626. Reference. 
  627.  
  628. Non-Fatal, Software-Generated Exceptions 
  629.  
  630. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  631. ΓöéException Symbolic Constant           ΓöéDescription           Γöé
  632. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  633. ΓöéXCPT_GUARD_PAGE_VIOLATION             ΓöéA guard page has been Γöé
  634. Γöé                                      Γöéaccessed.             Γöé
  635. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  636. ΓöéXCPT_UNABLE_TO_GROW_STACK             ΓöéThe system is unable  Γöé
  637. Γöé                                      Γöéto allocate the memoryΓöé
  638. Γöé                                      Γöépage directly below   Γöé
  639. Γöé                                      Γöéthe guard page just   Γöé
  640. Γöé                                      Γöéaccessed.             Γöé
  641. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  642.  
  643. Fatal, Software-Generated Exceptions 
  644.  
  645. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  646. ΓöéException Symbolic Constant           ΓöéDescription           Γöé
  647. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  648. ΓöéXCPT_IN_PAGE_ERROR                    ΓöéAn I/O error occurred Γöé
  649. Γöé                                      Γöéwhile reading a memoryΓöé
  650. Γöé                                      Γöépage into memory.     Γöé
  651. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  652. ΓöéXCPT_PROCESS_TERMINATE                ΓöéThe thread has        Γöé
  653. Γöé                                      Γöéterminated itself withΓöé
  654. Γöé                                      ΓöéDosExit.              Γöé
  655. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  656. ΓöéXCPT_ASYNC_PROCESS_TERMINATE          ΓöéAnother thread in the Γöé
  657. Γöé                                      Γöéprocess has caused theΓöé
  658. Γöé                                      Γöéthread to terminate.  Γöé
  659. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  660. ΓöéXCPT_NONCONTINUABLE_EXCEPTION         ΓöéAn exception handler  Γöé
  661. Γöé                                      Γöéhas attempted to      Γöé
  662. Γöé                                      Γöécontinue execution in Γöé
  663. Γöé                                      Γöéresponse to a         Γöé
  664. Γöé                                      Γöénon-continuable       Γöé
  665. Γöé                                      Γöéexception.            Γöé
  666. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  667. ΓöéXCPT_INVALID_DISPOSITION              ΓöéAn exception handler  Γöé
  668. Γöé                                      Γöéhas returned an       Γöé
  669. Γöé                                      Γöéinvalid value.        Γöé
  670. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  671.  
  672. Fatal, Hardware-Generated Exceptions 
  673.  
  674. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  675. ΓöéException Symbolic Constant           ΓöéDescription           Γöé
  676. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  677. ΓöéXCPT_ACCESS_VIOLATION                 ΓöéAn access violation orΓöé
  678. Γöé                                      Γöépage fault has        Γöé
  679. Γöé                                      Γöéoccurred.             Γöé
  680. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  681. ΓöéXCPT_INTEGER_DIVIDE_BY_ZERO           ΓöéAn attempt to divide  Γöé
  682. Γöé                                      Γöéby 0 has occurred in  Γöé
  683. Γöé                                      Γöéan integer operation. Γöé
  684. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  685. ΓöéXCPT_FLOAT_DIVIDE_BY_ZERO             ΓöéAn attempt to divide  Γöé
  686. Γöé                                      Γöéby 0 has occurred in aΓöé
  687. Γöé                                      Γöéfloating point        Γöé
  688. Γöé                                      Γöéoperation.            Γöé
  689. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  690. ΓöéXCPT_FLOAT_INVALID_OPERATION          ΓöéAn invalid floating   Γöé
  691. Γöé                                      Γöépoint operation was   Γöé
  692. Γöé                                      Γöéattempted.            Γöé
  693. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  694. ΓöéXCPT_ILLEGAL_INSTRUCTION              ΓöéAn attempt was made toΓöé
  695. Γöé                                      Γöéexecute an instructionΓöé
  696. Γöé                                      Γöéthat is not defined onΓöé
  697. Γöé                                      Γöéthe host machine's    Γöé
  698. Γöé                                      Γöéarchitecture.         Γöé
  699. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  700. ΓöéXCPT_PRIVILEGED_INSTRUCTION           ΓöéAn attempt was made toΓöé
  701. Γöé                                      Γöéexecute an instructionΓöé
  702. Γöé                                      Γöéthat is not permitted Γöé
  703. Γöé                                      Γöéin the current machineΓöé
  704. Γöé                                      Γöémode or that the      Γöé
  705. Γöé                                      Γöéapplication does not  Γöé
  706. Γöé                                      Γöéhave permission to    Γöé
  707. Γöé                                      Γöéexecute.              Γöé
  708. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  709. ΓöéXCPT_INTEGER_OVERFLOW                 ΓöéAn integer operation  Γöé
  710. Γöé                                      Γöégenerated a carry-out Γöé
  711. Γöé                                      Γöéof the most           Γöé
  712. Γöé                                      Γöésignificant bit.      Γöé
  713. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  714. ΓöéXCPT_FLOAT_OVERFLOW                   ΓöéA floating point      Γöé
  715. Γöé                                      Γöéoperation generated a Γöé
  716. Γöé                                      Γöéresulting exponent    Γöé
  717. Γöé                                      Γöéthat is greater than  Γöé
  718. Γöé                                      Γöéthe magnitude         Γöé
  719. Γöé                                      Γöépermitted for the     Γöé
  720. Γöé                                      Γöéoperands.             Γöé
  721. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  722. ΓöéXCPT_FLOAT_UNDERFLOW                  ΓöéA floating point      Γöé
  723. Γöé                                      Γöéoperation generated a Γöé
  724. Γöé                                      Γöéresulting exponent    Γöé
  725. Γöé                                      Γöéthat is less than the Γöé
  726. Γöé                                      Γöémagnitude provided forΓöé
  727. Γöé                                      Γöéthe operands.         Γöé
  728. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  729. ΓöéXCPT_FLOAT_DENORMAL_OPERAND           ΓöéAn attempt was made toΓöé
  730. Γöé                                      Γöéperform an arithmetic Γöé
  731. Γöé                                      Γöéoperation on a        Γöé
  732. Γöé                                      Γöédenormal operand.     Γöé
  733. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  734. ΓöéXCPT_FLOAT_INEXACT_RESULT             ΓöéThe result of an      Γöé
  735. Γöé                                      Γöéoperation is not      Γöé
  736. Γöé                                      Γöéexactly representable Γöé
  737. Γöé                                      Γöéin the target format. Γöé
  738. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  739. ΓöéXCPT_FLOAT_STACK_CHECK                ΓöéAn illegal stack      Γöé
  740. Γöé                                      Γöéoperation was         Γöé
  741. Γöé                                      Γöéattempted by the      Γöé
  742. Γöé                                      Γöéfloating point        Γöé
  743. Γöé                                      Γöécoprocessor.          Γöé
  744. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  745. ΓöéXCPT_DATATYPE_MISALIGNMENT            ΓöéAn attempt was made toΓöé
  746. Γöé                                      Γöéstore a data in an    Γöé
  747. Γöé                                      Γöéaddress that is not   Γöé
  748. Γöé                                      Γöénaturally aligned on aΓöé
  749. Γöé                                      Γöéhardware architecture Γöé
  750. Γöé                                      Γöéthat does not provide Γöé
  751. Γöé                                      Γöéalignment hardware.   Γöé
  752. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  753. ΓöéXCPT_BREAKPOINT                       ΓöéA breakpoint          Γöé
  754. Γöé                                      Γöéinstruction was       Γöé
  755. Γöé                                      Γöéexecuted.             Γöé
  756. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  757. ΓöéXCPT_SINGLE_STEP                      ΓöéOne instruction has   Γöé
  758. Γöé                                      Γöébeen executed in      Γöé
  759. Γöé                                      Γöésingle-step mode.     Γöé
  760. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  761.  
  762. Fatal Exceptions 
  763.  
  764. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  765. ΓöéException Symbolic Constant           ΓöéDescription           Γöé
  766. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  767. ΓöéXCPT_INVALID_LOCK_SEQUENCE            ΓöéAn invalid operation  Γöé
  768. Γöé                                      Γöéwas attempted within  Γöé
  769. Γöé                                      Γöéan interlocked sectionΓöé
  770. Γöé                                      Γöéof code.              Γöé
  771. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  772. ΓöéXCPT_ARRAY_BOUNDS_EXCEEDED            ΓöéAn array index outsideΓöé
  773. Γöé                                      Γöéits upper and lower   Γöé
  774. Γöé                                      Γöéboundary was detected.Γöé
  775. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  776.  
  777. Unwind Operation Exceptions 
  778.  
  779. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  780. ΓöéException Symbolic Constant           ΓöéDescription                 Γöé
  781. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  782. ΓöéXCPT_UNWIND                           ΓöéAn unwind operation is in   Γöé
  783. Γöé                                      Γöéprocess.                    Γöé
  784. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  785. ΓöéXCPT_BAD_STACK                        ΓöéAn                          Γöé
  786. Γöé                                      ΓöéEXCEPTIONREGISTRATIONRECORD Γöé
  787. Γöé                                      Γöédata structure was reached  Γöé
  788. Γöé                                      Γöéthat is not properly alignedΓöé
  789. Γöé                                      Γöéor that is not within the   Γöé
  790. Γöé                                      Γöécurrent stack boundaries.   Γöé
  791. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  792. ΓöéXCPT_INVALID_UNWIND_TARGET            ΓöéThe address of the target   Γöé
  793. Γöé                                      ΓöéEXCEPTIONREGISTRATIONRECORD Γöé
  794. Γöé                                      Γöéis below the current stack  Γöé
  795. Γöé                                      Γöépointer or not in the       Γöé
  796. Γöé                                      Γöéexception handler chain.    Γöé
  797. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  798.  
  799. Fatal Signal Exceptions 
  800.  
  801. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  802. ΓöéException Symbolic Constant           ΓöéDescription           Γöé
  803. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  804. ΓöéXCPT_SIGNAL                           ΓöéA signal was made to  Γöé
  805. Γöé                                      Γöéyour process (usually Γöé
  806. Γöé                                      Γöéto stop). All the     Γöé
  807. Γöé                                      Γöésignal exceptions     Γöé
  808. Γöé                                      Γöé(Ctrl+Break, Ctrl+C,  Γöé
  809. Γöé                                      Γöéand                   Γöé
  810. Γöé                                      ΓöéXCPT_SIGNAL_KILLPROC) Γöé
  811. Γöé                                      Γöécome under this       Γöé
  812. Γöé                                      Γöéexception.            Γöé
  813. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  814.  
  815.  
  816. ΓòÉΓòÉΓòÉ 3.1.2. Signal Exceptions ΓòÉΓòÉΓòÉ
  817.  
  818. Signal exceptions are special events sent to a thread when the user presses 
  819. certain key sequences or when another thread or process explicitly initiates 
  820. the exception. There are three types of signal exceptions: 
  821.  
  822. XCPT_SIGNAL_BREAK When the user presses Ctrl+Break 
  823. XCPT_SIGNAL_INTR When the user presses Ctrl+C 
  824. XCPT_SIGNAL_KILLPROC When another process uses DosKillProcess to send a 
  825.      XCPT_SIGNAL_KILLPROC exception to your process. 
  826.  
  827. Signal exceptions are sent only to Thread 1 (the main thread) in the process 
  828. receiving the exception. If an exception handler is registered on Thread 1, it 
  829. must be prepared to receive signal exceptions. The thread 1 exception handler 
  830. can always ignore the signal exception by returning XCPT_CONTINUE_SEARCH. 
  831.  
  832. If the thread 1 exception handler is to receive signal exceptions, it must use 
  833. DosSetSignalExceptionFocus to notify the operating system that it wants to 
  834. receive the XCPT_SIGNAL_INTR (Ctrl+C) and XCPT_SIGNAL_BREAK (Ctrl+Break) 
  835. signals. Otherwise, these exceptions are not passed to the exception handler 
  836. and the default action-to terminate the process-is taken by the operating 
  837. system. The thread will get XCPT_SIGNAL_KILLPROC signals whether it uses 
  838. DosSetSignalExceptionFocus or not. 
  839.  
  840. All three of these signals are delivered by a single exception-XCPT_SIGNAL-and 
  841. the exception handler for Thread 1 can choose to handle none, some, or all of 
  842. the signals. The signal being sent can be determined by examining the exception 
  843. information in EXCEPTIONREPORTRECORD. 
  844.  
  845. The following table provides information about each type of signal. 
  846.  
  847. Signal Exceptions 
  848.  
  849. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  850. ΓöéSignal      ΓöéSymbolic Constant         ΓöéDescription                Γöé
  851. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  852. ΓöéCtrl+Break  ΓöéXCPT_SIGNAL_BREAK         ΓöéThis exception is sent to  Γöé
  853. Γöé            Γöé                          ΓöéThread 1 in the current    Γöé
  854. Γöé            Γöé                          Γöékeyboard-focus process whenΓöé
  855. Γöé            Γöé                          Γöéa Ctrl+Break key sequence  Γöé
  856. Γöé            Γöé                          Γöéis received from the       Γöé
  857. Γöé            Γöé                          Γöékeyboard. The default      Γöé
  858. Γöé            Γöé                          Γöéaction taken by the        Γöé
  859. Γöé            Γöé                          Γöéoperating system for this  Γöé
  860. Γöé            Γöé                          Γöéexception is forced processΓöé
  861. Γöé            Γöé                          Γöétermination.               Γöé
  862. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  863. ΓöéCtrl+C      ΓöéXCPT_SIGNAL_INTR          ΓöéThis exception is sent to  Γöé
  864. Γöé            Γöé                          ΓöéThread 1 in the current    Γöé
  865. Γöé            Γöé                          Γöékeyboard-focus process whenΓöé
  866. Γöé            Γöé                          Γöéa Ctrl+C key sequence is   Γöé
  867. Γöé            Γöé                          Γöéreceived from the keyboard.Γöé
  868. Γöé            Γöé                          ΓöéThe default action taken byΓöé
  869. Γöé            Γöé                          Γöéthe operating system for   Γöé
  870. Γöé            Γöé                          Γöéthis exception is forced   Γöé
  871. Γöé            Γöé                          Γöéprocess termination.       Γöé
  872. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  873. ΓöéKill ProcessΓöéXCPT_SIGNAL_KILLPROC      ΓöéThis exception is sent to  Γöé
  874. ΓöéSignal      Γöé                          ΓöéThread 1 in the process    Γöé
  875. Γöé            Γöé                          Γöéspecified when an          Γöé
  876. Γöé            Γöé                          Γöéapplication uses           Γöé
  877. Γöé            Γöé                          ΓöéDosKillProcess. The        Γöé
  878. Γöé            Γöé                          ΓöéXCPT_SIGNAL_KILLPROC signalΓöé
  879. Γöé            Γöé                          Γöéexception results from an  Γöé
  880. Γöé            Γöé                          Γöéaction external to the     Γöé
  881. Γöé            Γöé                          Γöéprocess. The default actionΓöé
  882. Γöé            Γöé                          Γöétaken by the operating     Γöé
  883. Γöé            Γöé                          Γöésystem for this exception  Γöé
  884. Γöé            Γöé                          Γöéis forced process          Γöé
  885. Γöé            Γöé                          Γöétermination.               Γöé
  886. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  887.  
  888.  
  889. ΓòÉΓòÉΓòÉ 3.1.2.1. Handling Signal Exceptions ΓòÉΓòÉΓòÉ
  890.  
  891. To handle signal exceptions, a process must first call DosSetExceptionHandler 
  892. to register a handler for the exceptions. Next, the process must call 
  893. DosSetSignalExceptionFocus, with the Flag parameter set to ON, in order to 
  894. receive signal exceptions. 
  895.  
  896. After a process calls DosSetSignalExceptionFocus, it remains the signal focus 
  897. for its screen group until it calls DosSetSignalExceptionFocus again with the 
  898. Flag parameter set to OFF, or until another process in the screen group makes a 
  899. call to the same function with Flag set to ON. 
  900.  
  901. Each call to DosSetSignalExceptionFocus with Flag set to ON increments a 
  902. counter in the per-task data area of the process. Each call with Flag set to 
  903. OFF decrements the counter. When a signal exception occurs, the system checks 
  904. to see whether the value of the counter is greater than 0. If it is, the signal 
  905. is sent. 
  906.  
  907. DosSetSignalExceptionFocus returns ERROR_NESTED_TOO_DEEP if the value of the 
  908. counter exceeds 65535. If a thread tries to turn off the signal focus when the 
  909. value of the counter is 0, ERROR_ALREADY_RESET is returned. 
  910.  
  911. All 32-bit exception handlers that are attached to thread 1 of the process will 
  912. be given an opportunity to handle the signal. If no 32-bit exception handler 
  913. returns XCPT_CONTINUE_EXECUTION in response to the signal, then the 16-bit 
  914. handler for the signal will be executed, if one exists; if none exists, then 
  915. the process will be terminated. 
  916.  
  917. In order to continue receiving signals, the process must either return 
  918. XCPT_CONTINUE_EXECUTION from a 32-bit exception handler, or it must call the 
  919. 16-bit DosSetSigHandler function, specifying SIG_ACKNOWLEDGE as the value of 
  920. the Action parameter to acknowledge the signal, or call 
  921. DosAcknowledgeSignalException. 
  922.  
  923. The typematic facility of the keyboard could cause a Ctrl+C or Ctrl+Break 
  924. signal exception to repeat. For this reason, the system holds these exceptions 
  925. until an exception handler returns XCPT_CONTINUE_EXECUTION, or calls 
  926. DosAcknowledgeSignalException. However, only one signal exception is actually 
  927. held; they are not queued by the system. 
  928.  
  929. See Must-Complete Sections for information about how a process can defer the 
  930. handling of signal exceptions. 
  931.  
  932.  
  933. ΓòÉΓòÉΓòÉ 3.1.2.2. Sending Signal Exceptions ΓòÉΓòÉΓòÉ
  934.  
  935. A process can send the XCPT_SIGNAL signal exception to another process by 
  936. calling DosSendSignalException. 
  937.  
  938. In order for the specified process to receive the exception, it must have an 
  939. exception handler registered for Thread 1, and it must designate itself as the 
  940. signal focus for its screen group by calling DosSetSignalExceptionFocus. 
  941.  
  942. Presentation Manager applications cannot request exception focus for Ctrl+C and 
  943. Ctrl+Break. However, establishing an exception handler for Ctrl+C and 
  944. Ctrl+Break is supported for Vio-Window and full-screen applications. 
  945.  
  946.  
  947. ΓòÉΓòÉΓòÉ 3.1.3. Raising Exceptions ΓòÉΓòÉΓòÉ
  948.  
  949. Asynchronous exceptions that have been deferred in a must-complete section are 
  950. dispatched automatically by the system when the thread exits the must-complete 
  951. section. However, a synchronous exception that has been deferred must be raised 
  952. by calling DosRaiseException. 
  953.  
  954. DosRaiseException can also be used to simulate either an asynchronous or 
  955. synchronous exception. For example, a floating point emulator (a program that 
  956. emulates a numeric coprocessor) can use this function to simulate an NPX 
  957. exception. 
  958.  
  959. Raising a software exception captures the machine state of the current thread 
  960. in a ContextRecord data structure. The ExceptionAddress field of 
  961. EXCEPTIONREPORTRECORD is set to the return address of the caller, as are the 
  962. corresponding fields of the ContextRecord data structure. The system then calls 
  963. each exception handler on the list, passing each a pointer to 
  964. EXCEPTIONREPORTRECORD and the created ContextRecord data structures. In the 
  965. case of a continuable exception for which XCPT_CONTINUE_EXECUTION is returned, 
  966. DosRaiseException restores the potentially modified context back into the 
  967. machine before returning. Note that control cannot return to the caller of 
  968. DosRaiseException if the instruction pointer in ContextRecord has been 
  969. modified. 
  970.  
  971. The caller of DosRaiseException can set the EH_NONCONTINUABLE bit in the flags 
  972. field of the EXCEPTIONREPORTRECORD data structure. By doing so, the caller 
  973. guarantees that it is never returned to after the call to DosRaiseException. 
  974. Note that once set, the EH_NONCONTINUABLE bit cannot be modified by any 
  975. exception handler. The system will enforce this. 
  976.  
  977. Following are some possible scenarios that might occur after a call to 
  978. DosRaiseException has been made: 
  979.  
  980. o If one of the exception handlers returns from a continuable exception with a 
  981.   status of XCPT_CONTINUE_EXECUTION, DosRaiseException returns NO_ERROR to the 
  982.   caller, and the thread resumes execution. 
  983.  
  984. o If one of the exception handlers returns from a noncontinuable exception with 
  985.   a status of XCPT_CONTINUE_EXECUTION, the process is terminated, because it is 
  986.   illegal to return XCPT_CONTINUE_EXECUTION from a noncontinuable exception. 
  987.  
  988. o If none of the exception handlers in the thread's chain of handlers returns 
  989.   with a status of XCPT_CONTINUE_EXECUTION, then the action taken depends on 
  990.   the exception number: 
  991.  
  992.    - If the exception number indicates a user-assigned exception or an 
  993.      unassigned system exception, the process is terminated. 
  994.  
  995.    - If the exception number is assigned to a system exception, and CS:EIP 
  996.      points to 32-bit code, no 16-bit handlers are called and the system 
  997.      default action is taken. Depending on which system exception has been 
  998.      raised, the default action is either to terminate the process, or to 
  999.      continue execution of the thread with NO_ERROR returned to the caller. 
  1000.  
  1001.    - If the exception number is assigned to a system exception that maps to a 
  1002.      16-bit exception and CS:EIP points to 16-bit code, a 16-bit exception 
  1003.      handler is called, if one is registered. Otherwise the operating system 
  1004.      takes the default action. 
  1005.  
  1006.  
  1007. ΓòÉΓòÉΓòÉ 3.1.4. User-Defined Exceptions ΓòÉΓòÉΓòÉ
  1008.  
  1009. Exceptions can also be defined by the application. These are called 
  1010. user-defined exceptions (as opposed to system-defined exceptions, which are 
  1011. those exceptions defined by the operating system). Applications can define an 
  1012. exception in the following fashion: 
  1013.  
  1014.     #define XCPT_YOUR_EXCEPTION 0xE004ABCD
  1015. The application then raises the exception, using DosRaiseException: 
  1016.  
  1017.     DosRaiseException(XCPT_YOUR_EXCEPTION);
  1018. The exception handlers in the exception handler chain that are ahead of the 
  1019. application's exception handler will see the exception, but they will not 
  1020. recognize it, so they will return XCPT_CONTINUE_SEARCH. Only the application's 
  1021. exception handler will recognize the exception. 
  1022.  
  1023. The application's exception handler must return XCPT_CONTINUE_EXECUTION so that 
  1024. the exception will not continue to be passed down the exception handler chain. 
  1025.  
  1026.  
  1027. ΓòÉΓòÉΓòÉ 3.1.5. Must-Complete Sections ΓòÉΓòÉΓòÉ
  1028.  
  1029. A thread can defer the handling of asynchronous exceptions by creating a 
  1030. must-complete section. A must-complete section is a section of code that cannot 
  1031. be safely interrupted; it must be allowed to complete its execution even if an 
  1032. asynchronous exception occurs while within its boundaries. For example, a 
  1033. must-complete section can be used: 
  1034.  
  1035. o When modifying shared-memory data structures that cannot be modified through 
  1036.   an atomic operation 
  1037. o Across database update operations 
  1038. o During a remote communications operation. 
  1039.  
  1040. Creating a must-complete section ensures that the execution of critical 
  1041. instructions will be completed and that resources will be cleaned up before the 
  1042. thread ends. When used in conjunction with a mutual exclusion (mutex) 
  1043. semaphore, a must-complete section also ensures that a thread will have 
  1044. exclusive access to a resource. 
  1045.  
  1046. The boundaries of the must-complete section are defined by DosEnterMustComplete 
  1047. and DosExitMustComplete requests. While a thread is executing instructions in a 
  1048. must-complete section, the system will hold asynchronous exceptions, which 
  1049. include signal exceptions and asynchronous process terminations. 
  1050.  
  1051. The system increments a counter each time DosEnterMustComplete is called, and 
  1052. decrements the counter when DosExitMustComplete is called.  Any asynchronous 
  1053. exceptions that have been held are dispatched when the counter reaches 0.  A 
  1054. count greater than 1 indicates the degree of nesting of the must-complete 
  1055. section. If DosExitMustComplete is called when the count is already 0, 
  1056. ERROR_ALREADY_RESET is returned. 
  1057.  
  1058. The handling of synchronous system exceptions and user-defined exceptions is 
  1059. not deferred by the system. To defer the handling of these exceptions, a 
  1060. procedure typically registers an exception handler (by calling 
  1061. DosSetExceptionHandler) and initializes a local Raise Exception flag to 0 
  1062. before entering the must-complete section. The flag is set to 1, and the 
  1063. information is stored, if the exception handler receives a synchronous 
  1064. exception that it wants to reraise later. 
  1065.  
  1066. If the value of the raise exception flag is 0 after the thread exits from the 
  1067. must-complete section, then no exceptions occurred, and the thread continues 
  1068. its normal operation. 
  1069.  
  1070. If the value of the flag is 1 after the must-complete section has been 
  1071. completed, then an exception occurred, and the thread must call 
  1072. DosRaiseException to raise the deferred exception for handling. 
  1073.  
  1074. Note:  A thread must not call a function that is outside the scope of the 
  1075.        must-complete section (for example, a DLL routine), because an error in 
  1076.        the called routine could cause the process to end without returning. 
  1077.        Keep must-complete sections as short as possible. 
  1078.  
  1079.  
  1080. ΓòÉΓòÉΓòÉ 3.1.6. Unwinding Exception Handlers ΓòÉΓòÉΓòÉ
  1081.  
  1082. In addition to handling exceptions, exception handlers are used to clean up 
  1083. resources during the execution of a nonlocal GOTO instruction or during thread 
  1084. termination. (A nonlocal GOTO instruction jumps to a label outside the current 
  1085. procedure. The label is a procedure address or an address within a procedure 
  1086. that is on the stack, higher in the call frame chain.) 
  1087.  
  1088. DosUnwindException calls and removes exception handlers from a thread's chain 
  1089. of registered exception handlers up to, but not including, a specified 
  1090. exception handler. This is known as an unwind operation. DosUnwindException can 
  1091. also be used to unwind all exception handlers from the thread's exception 
  1092. handler chain and to terminate the thread. 
  1093.  
  1094. For example, with the C language setjmp() and longjmp() routines, the setjmp() 
  1095. would save the address of the current exception handler structure, along with 
  1096. any other information that is necessary to perform the longjmp() routine.  (The 
  1097. address of the current exception handler structure is obtained from the head of 
  1098. the exception handler chain. A pointer to the head of the chain is located in 
  1099. the Thread Information Block.) 
  1100.  
  1101. The longjmp() routine would initiate the unwind of procedure call frames by 
  1102. calling DosUnwindException and passing to it the saved address of the 
  1103. EXCEPTIONREGISTRATIONRECORD data structure. If the address of the 
  1104. EXCEPTIONREGISTRATIONRECORD data structure is not found in the chain, then the 
  1105. XCPT_INVALID_UNWIND_TARGET exception is raised, and the chain is not unwound. 
  1106.  
  1107. The machine state at the time of the call to DosUnwindException is captured in 
  1108. ContextRecord. The EH_UNWINDING flag is set in the exception flags field of the 
  1109. EXCEPTIONREPORTRECORD data structure. The EH_EXIT_UNWIND flag is also set if 
  1110. the EXCEPTIONREGISTRATIONRECORD parameter is set to 0 (if the application does 
  1111. not provide its own EXCEPTIONREPORTRECORD parameter the operating system will 
  1112. construct one). A backward walk through the procedure call frames is then 
  1113. performed to find the target of the unwind operation. 
  1114.  
  1115. The first parameter to DosUnwindException is the address of an exception 
  1116. handler's EXCEPTIONREGISTRATIONRECORD. DosUnwindException will unwind exception 
  1117. handlers up to, but not including that exception handler. If a -1 is passed to 
  1118. DosUnwindException for this parameter, DosUnwindException will unwind all the 
  1119. exception handlers on the chain. If a 0 is passed to DosUnwindException for 
  1120. this parameter, DosUnwindException will unwind all the exception handlers on 
  1121. the chain and exit. 
  1122.  
  1123. There is no return from a call to DosUnwindException, unless the stack is 
  1124. invalid. Control is transferred to the specified instruction pointer address. 
  1125. If DosUnwindException encounters an error during its processing, it raises 
  1126. another exception rather than return control to the caller. 
  1127.  
  1128. If the target call frame is reached and an exit unwind is not being performed 
  1129. (that is, an EXCEPTIONREGISTRATIONRECORD is not 0), then the computed machine 
  1130. state is restored from ContextRecord and control is transferred to the address 
  1131. specified by the target-IP address parameter. Note that the stack pointer is 
  1132. not restored, making it possible to transfer information on the stack. It is 
  1133. the responsibility of the code at the target address to reset the stack pointer 
  1134. as necessary. 
  1135.  
  1136. DosUnwindException is called with C language calling conventions, which permits 
  1137. the use of a variable number of arguments. Thus, the caller can pass any amount 
  1138. of information on the stack, to be picked up at the target-IP address. 
  1139.  
  1140. If an exit unwind is being performed (the EXCEPTIONREGISTRATIONRECORD parameter 
  1141. is 0 or -1), then all call frames are unwound until the base of the stack is 
  1142. reached. 
  1143.  
  1144. If the EXCEPTIONREPORTRECORD parameter is specified, then each exception 
  1145. handler encountered during the unwind operation is called, using the specified 
  1146. record. If this parameter is not specified, then DosUnwindException constructs 
  1147. an EXCEPTIONREPORTRECORD that specifies the exception XCPT_UNWIND. 
  1148.  
  1149. Colliding Unwinds 
  1150. During an unwind operation, it is possible for one unwind to collide with a 
  1151. previous unwind. This occurs when the scope of the second unwind overlaps the 
  1152. scope of the first unwind. Following are two situations: 
  1153.  
  1154. o The target frame of the second unwind is a frame that has already been 
  1155.   unwound by the first unwind. 
  1156.  
  1157. o The target frame of the second unwind is a valid frame that is positioned 
  1158.   before or after the target frame of the first unwind. 
  1159.  
  1160. Either of these situations could occur during the following scenarios: 
  1161.  
  1162. o An unwind handler calls unwind, or 
  1163.  
  1164. o An unwind handler hits an exception that has called unwind. 
  1165.  
  1166. In the first scenario, the second unwind is attempting to unwind to an invalid 
  1167. target. This causes the exception XCPT_INVALID_UNWIND_TARGET to be raised. 
  1168.  
  1169. In the second scenario, the first unwind is abandoned, and the second unwind 
  1170. continues to its target. The second scenario is far more likely. 
  1171.  
  1172. Note:  A user program that uses high level language exception mechanisms must 
  1173.        never call DosUnwindException, because this could create conflicts with 
  1174.        the runtime exception strategy of the high level language. Unwind 
  1175.        operations in this case are performed through language-supported 
  1176.        facilities such as the C language longjmp() routine. 
  1177.  
  1178.  
  1179. ΓòÉΓòÉΓòÉ 3.1.7. Nested Exceptions ΓòÉΓòÉΓòÉ
  1180.  
  1181. A nested exception is an exception that occurs while another exception is being 
  1182. handled. 
  1183.  
  1184. The operating system supports nested exceptions because an unhandled exception 
  1185. that occurs in an exception handler should be handled at a higher level-that 
  1186. is, by an ancestor of the procedure that registered the offending handler. 
  1187.  
  1188. When a nested exception occurs, the EH_NESTED_CALL flag is set in the exception 
  1189. structure to indicate that a nested function call is being made. The normal 
  1190. convention then is for the handler to return immediately without handling the 
  1191. exception if the EH_NESTED_CALL flag is set. Without this flag, it would be 
  1192. easy to create an infinitely recursive situation. 
  1193.  
  1194. For example, suppose we have the following scenario: 
  1195.  
  1196.  1. Procedure main calls procedure PA, which establishes exception handler HA. 
  1197.  2. Procedure PA calls procedure PB, which establishes exception handler HB. 
  1198.  3. Procedure PB calls procedure PC, which establishes exception handler HC. 
  1199.  4. Procedure PC calls procedure PD. 
  1200.  
  1201. Now suppose that procedure PD causes an exception. The system refers to the 
  1202. current thread's chain of exception handlers. 
  1203.  
  1204. Because procedure PD has no handler, the system calls HC, the handler for 
  1205. procedure PC, with the EH_NESTED_CALL flag clear. If handler HC returns 
  1206. CONTINUE_SEARCH, the system calls the next handler in the chain, handler HB, 
  1207. again with the EH_NESTED_CALL flag clear. 
  1208.  
  1209. Now suppose that exception handler HB causes an exception while it is 
  1210. processing the original exception. The call frames for the procedures are 
  1211. arranged in the following order on the stack: 
  1212.  
  1213.  1. Procedure main 
  1214.  2. Procedure PA 
  1215.  3. Procedure PB 
  1216.  4. Procedure PC 
  1217.  5. Procedure PD 
  1218.  6. The operating system's exception dispatcher 
  1219.  7. Procedure HB, which is the exception handler procedure 
  1220.  8. The operating system's exception dispatcher 
  1221.  
  1222. The system will now start traversing the exception handler chain again. 
  1223. Exception handler HB could have registered an exception handler, which would be 
  1224. the first handler in the chain. If it had registered a handler, it would be 
  1225. called with the EH_NESTED_CALL flag clear. 
  1226.  
  1227. The range of the nested exception is exception handlers HC and HB. The end of 
  1228. this range can be determined by the fact that exception handler HB is the 
  1229. currently active handler. 
  1230.  
  1231. These exception handlers have already been given a chance to handle the 
  1232. original exception.  They are now about to be called again in a nested range. 
  1233. Therefore, when handlers HC and HB are called again, they will be called with 
  1234. the EH_NESTED_CALL flag set.  If they do not handle the exception, then 
  1235. exception handler HA will be called with the EH_NESTED_CALL flag clear, because 
  1236. it is outside the nested range. 
  1237.  
  1238.  
  1239. ΓòÉΓòÉΓòÉ 3.1.8. Process Exit Lists ΓòÉΓòÉΓòÉ
  1240.  
  1241. A process executes any routines registered in its exit list (with DosExitList) 
  1242. after the Process Termination exception has been delivered to each thread in 
  1243. the process and after each thread except Thread 1 has finally been terminated. 
  1244. If a thread handles the process termination exception, it must eventually 
  1245. voluntarily terminate, or the exit-list sequence will not finish running 
  1246. properly. Threads must not use DosCreateThread, DosExecPgm, DosStartSession, or 
  1247. DosExit when they are delivered a process termination exception. 
  1248.  
  1249.  
  1250. ΓòÉΓòÉΓòÉ 3.1.9. Error Pop-Up Screens ΓòÉΓòÉΓòÉ
  1251.  
  1252. Some error conditions, such as general protection violations, cause the 
  1253. operating system to display a pop-up screen containing information about the 
  1254. error. An application can use DosError to disable error pop-up screens. 
  1255. Typically, a Presentation Manager application would disable error pop-up 
  1256. screens if it sets up its own routines to handle errors that would ordinarily 
  1257. generate pop-up screens. 
  1258.  
  1259. DosError is also used to control and disable hard errors, which usually have to 
  1260. do with reading from and writing to disks. 
  1261.  
  1262.  
  1263. ΓòÉΓòÉΓòÉ 3.2. Exception Handler Interface ΓòÉΓòÉΓòÉ
  1264.  
  1265. Exception handlers are passed four parameters. The interface for writing a 
  1266. 32-bit exception handler is: 
  1267.  
  1268.     ExceptionHandler (ExceptionReportRecord,
  1269.                       ExceptionRegistrationRecord,
  1270.                       ContextRecord,
  1271.                       DispatcherContext);
  1272.  
  1273. Exception Handler Interface 
  1274.  
  1275. The exception handler returns XCPT_CONTINUE_EXECUTION to indicate that the 
  1276. exception has been handled and is to be dismissed, or XCPT_CONTINUE_SEARCH to 
  1277. indicate that the exception has not been handled and is to be passed to the 
  1278. next exception handler on the chain. 
  1279.  
  1280. Note that there are no invalid exception numbers; if a handler does not 
  1281. recognize an exception number, it simply returns XCPT_CONTINUE_SEARCH. 
  1282.  
  1283. In addition to handling exceptions, exception handlers are used in unwind 
  1284. operations. An unwind operation simply calls and removes exception handlers 
  1285. from the exception handler chain of the thread. Unwind exceptions are not 
  1286. actually being delivered to the handlers, so the individual return codes are 
  1287. irrelevant, and they do not affect the unwind operation. 
  1288.  
  1289. A single exception handler can be used to handle all the exceptions that you 
  1290. choose to handle. It is not necessary to have a separate exception handler for 
  1291. each exception. 
  1292.  
  1293. A handler is not required to return to the system; it can handle the exception, 
  1294. and then continue thread execution directly. For example, when an application 
  1295. executes a longjmp(), the C language compiler adds code that essentially 
  1296. performs an unwind operation to clean up the stack. Execution then resumes at 
  1297. the point where the target setjmp() occurred. 
  1298.  
  1299. For synchronous exceptions, an exception handler can alter the contents of the 
  1300. interrupted thread's context, except for the fields that cannot normally be 
  1301. altered during thread execution. For asynchronous exceptions (signal and 
  1302. termination) changes made to the context of the thread are ignored. 
  1303.  
  1304. Some exceptions are continuable; if the thread's exception handler handles the 
  1305. exception, execution can continue. If the exception condition is such that 
  1306. execution cannot be continued safely, the exception is said to be 
  1307. noncontinuable. If an exception is noncontinuable the EH_NONCONTINUABLE bit is 
  1308. set in the exception structure, and it is an error to indicate the exception 
  1309. has been handled. Returning XCPT_CONTINUE_EXECUTION causes an 
  1310. XCPT_NONCONTINUABLE_EXCEPTION exception to be raised. 
  1311.  
  1312. Generally, exception handlers can use any function while they are handling an 
  1313. exception. However, while handling a process-termination exception, an 
  1314. exception handler must not call DosCreateThread, DosExecPgm, or 
  1315. DosStartSession, because unpredictable results can occur. A handler also must 
  1316. not call DosExit while handling a process-termination exception, because this 
  1317. request will cause the exception to be dispatched as a nested exception to the 
  1318. current thread's entire chain of handlers. 
  1319.  
  1320.  
  1321. ΓòÉΓòÉΓòÉ 3.2.1. Exception Handler Parameters ΓòÉΓòÉΓòÉ
  1322.  
  1323. EXCEPTIONREPORTRECORD (EXCEPTIONREPORTRECORD) - input/output 
  1324.    A pointer to the exception report record, which describes the exception and 
  1325.    its parameters. 
  1326.  
  1327. EXCEPTIONREGISTRATIONRECORD ( EXCEPTIONREGISTRATIONRECORD) - input/output 
  1328.    This is a microprocessor-specific value.  For the 80386 microprocessor, this 
  1329.    is a pointer to the exception registration record data structure that was 
  1330.    used to register the current exception handler. 
  1331.  
  1332. ContextRecord (CONTEXTRECORD) - input/output 
  1333.    A pointer to a context record, which describes the machine state at the time 
  1334.    the exception occurred. 
  1335.  
  1336. DispatcherContext (DISPATCHERCONTEXT) - output 
  1337.    A pointer to a reserved field that receives state information on nested 
  1338.    exceptions and collided unwinds. This field returns information to either 
  1339.    the exception dispatcher (in the case of nested exceptions) or to the unwind 
  1340.    routine (in the case of collided unwinds). User code must not modify the 
  1341.    DispatcherContext field at any time. 
  1342.  
  1343.    When the system's exception handler is called (it is already registered by 
  1344.    the exception dispatcher), the exception handler returns NESTED and fills in 
  1345.    the DispatcherContext field with the address of the 
  1346.    EXCEPTIONREGISTRATIONRECORD corresponding to the exception handler most 
  1347.    recently called by the exception dispatcher. This indicates how far the 
  1348.    exception dispatcher progressed through the call chain before the nesting 
  1349.    occurred. The EH_NESTED_CALL bit is set in the EXCEPTIONREPORTRECORD flags 
  1350.    field for each exception handler that is called between handler of the 
  1351.    exception dispatcher and the establisher of the most recently called 
  1352.    handler. 
  1353.  
  1354.    In the case of a collided unwind, the exception handler registered by the 
  1355.    unwind dispatcher will  return COLLIDED_UNWIND and the DispatcherContext 
  1356.    field will contain a pointer to the target frame of the current unwind. 
  1357.  
  1358.  
  1359. ΓòÉΓòÉΓòÉ 3.2.2. Exception Management Data Structures ΓòÉΓòÉΓòÉ
  1360.  
  1361. Applications use three data structures for exception management (the 
  1362. DispatcherContext parameter is for system use). 
  1363.  
  1364. o EXCEPTIONREPORTRECORD data structure 
  1365. o ExceptionRegistrationRecord data structure 
  1366. o ContextRecord data structure. 
  1367. An overview of each of these data structures is presented below. 
  1368.  
  1369.  
  1370. ΓòÉΓòÉΓòÉ 3.2.2.1. ExceptionReportRecord Data Structure ΓòÉΓòÉΓòÉ
  1371.  
  1372. The EXCEPTIONREPORTRECORD data structure describes an exception and any 
  1373. additional parameters associated with the exception. The data structure 
  1374. contains fields for the following information: 
  1375.  
  1376. o Exception number 
  1377. o Exception flags, describing exception attributes 
  1378. o A pointer to a nested exception report record, if any 
  1379. o The address where the exception occurred 
  1380. o Information for any additional parameters. 
  1381.  
  1382. For descriptions of the system exceptions see the Control Program Programming 
  1383. Reference. 
  1384.  
  1385. Following are the flags that are set to indicate exception attributes. Only the 
  1386. EH_NONCONTINUABLE flag can be set (but not cleared) by the user. All other 
  1387. flags are set by the system. 
  1388.  
  1389. EH_NONCONTINUABLE (0x1) 
  1390.    The exception is not continuable, and any attempt to continue causes the 
  1391.    exception XCPT_NONCONTINUABLE_EXCEPTION to be raised. 
  1392.  
  1393. EH_UNWINDING (0x2) 
  1394.    The EXCEPTIONREPORTRECORD data structure describes an exception for which an 
  1395.    unwind is in progress. 
  1396.  
  1397. EH_EXIT_UNWIND (0x4) 
  1398.    An exit unwind operation implies that call frames are being unwound until 
  1399.    the base of the stack is reached. Note that EH_UNWINDING is also set. 
  1400.  
  1401. EH_STACK_INVALID (0x8) 
  1402.    Following are causes for this flag to be set: 
  1403.  
  1404.    o The user stack exceeds the limits specified by the Thread Information 
  1405.      Block. Applications can get the Thread Information Block by calling 
  1406.      DosGetThreadInfo. 
  1407.  
  1408.    o A call frame exceeds the stack limits specified by the Thread Information 
  1409.      Block. 
  1410.  
  1411.    o A call frame is not aligned on the stack. 
  1412.  
  1413.    This flag is set only when the EXCEPTIONREPORTRECORD is passed to an 
  1414.    associated debugger. It is not possible to build exception information on 
  1415.    the user's stack when the stack is invalid. 
  1416.  
  1417. EH_NESTED_CALL (0x10) 
  1418.    EXCEPTIONREPORTRECORD describes an exception raised while the current 
  1419.    exception handler was active. That is, a nested exception is in progress, 
  1420.    and the current handler was also called to handle the previous exception. 
  1421.  
  1422. EXCEPTIONREPORTRECORD data structures can be chained together to provide 
  1423. additional information when nested exceptions are raised. 
  1424.  
  1425.  
  1426. ΓòÉΓòÉΓòÉ 3.2.2.2. ExceptionRegisterRecord Data Structure ΓòÉΓòÉΓòÉ
  1427.  
  1428. The application is responsible for the creation and registration of the 
  1429. EXCEPTIONREGISTRATIONRECORD data structure. This is the data structure used by 
  1430. the application when it established the exception handler on the chain. 
  1431.  
  1432. The only restrictions are that each pointer in the linked list must either 
  1433. point directly to the next pointer in the list or contain END_OF_CHAIN (-1), 
  1434. and the field immediately following the pointer field must be the pointer to 
  1435. the exception handler code. No fields other than these two will be examined by 
  1436. the operating system. The application can keep any state information that it 
  1437. chooses in this data structure, as long as it does not alter either of the 
  1438. fields used by the system. 
  1439.  
  1440. When a procedure begins, it must create an EXCEPTIONREGISTRATIONRECORD on the 
  1441. stack, fill in the pointer to the exception handler routine, and link the data 
  1442. structure to the front of the exception handler chain by calling 
  1443. DosSetExceptionHandler. 
  1444.  
  1445. Similarly, when the procedure ends, it must remove EXCEPTIONREGISTRATIONRECORD 
  1446. from the chain by calling DosUnsetExceptionHandler. This maintains the 
  1447. necessary frame-exception handler correspondence. 
  1448.  
  1449. Note: 
  1450.  
  1451. For the benefit of assembly language programmers, the Thread Information Block 
  1452. (TIB) is located at FS:[0]. This speeds access to the TIB data structure. 
  1453.  
  1454. Because the FS is used to point to the TIB, applications that use the FS 
  1455. register must restore the original value when they are finished. Exception 
  1456. handling depends on the FS register pointing to the TIB. 
  1457.  
  1458. EXCEPTIONREGISTRATIONRECORD data structure must be created on the stack of the 
  1459. application. That is, it must be a data structure that is local to the routine 
  1460. that registers the exception handler. It cannot be stored in the application's 
  1461. data segment. The reason for this is that the operating system must be able to 
  1462. determine the relative ordering of ExceptionRegistration records by examining 
  1463. their addresses. 
  1464.  
  1465.  
  1466. ΓòÉΓòÉΓòÉ 3.2.2.3. ContextRecord Data Structure ΓòÉΓòÉΓòÉ
  1467.  
  1468. The ContextRecord data structure describes the machine state at the time of an 
  1469. exception. This data structure is hardware dependent and is not portable. 
  1470. Therefore, as a rule, software should not use the information contained in this 
  1471. data structure. However, hardware dependent code, such as math libraries, can 
  1472. make use of this information to optimize certain operations. 
  1473.  
  1474. For a hardware-initiated exception, ContextRecord contains the complete machine 
  1475. state at the time of the exception. For a software-initiated exception, 
  1476. ContextRecord contains the machine state at the time the software raised the 
  1477. exception. 
  1478.  
  1479. The ContextRecord data structure consists of fields for the following: 
  1480.  
  1481. o General purpose registers 
  1482. o Segment registers 
  1483. o The flags register 
  1484. o The floating point environment and stack. 
  1485.  
  1486. Note:  With asynchronous exceptions (signal and termination exceptions), the 
  1487.        context in ContextRecord is read-only. The exception handler can modify 
  1488.        it, but the changes with be ignored. 
  1489.  
  1490. With synchronous exceptions, changes to ContextRecord will be used when the 
  1491. context is restored. 
  1492.  
  1493.  
  1494. ΓòÉΓòÉΓòÉ 3.2.3. Exception Handler Return Values ΓòÉΓòÉΓòÉ
  1495.  
  1496. Exception handlers can return one of the following values: 
  1497.  
  1498. XCPT_CONTINUE_SEARCH (0x00000000) 
  1499.           Indicates that the exception has not been handled. The system 
  1500.           responds by passing the exception to the previously installed handler 
  1501.           in the thread's chain of exception handlers. 
  1502.  
  1503. XCPT_CONTINUE_EXECUTION (0xFFFFFFFF) 
  1504.           Indicates that the exception has been handled. The operating system 
  1505.           responds by dismissing the exception, restoring the context of the 
  1506.           thread, and continuing the execution of the thread. 
  1507.  
  1508.  
  1509. ΓòÉΓòÉΓòÉ 3.3. Using Exception Management ΓòÉΓòÉΓòÉ
  1510.  
  1511. When an exception occurs, the system default action in most cases is to end the 
  1512. application that caused the exception. Instead of having the system default 
  1513. action occur, an application can register its own exception handling routines. 
  1514. Exception handlers can be written to take corrective action so that a thread 
  1515. can continue running rather than being terminated by the system. 
  1516.  
  1517. If an exception is handled by the application's exception handler, the 
  1518. exception handler must return XCPT_CONTINUE_EXECUTION. If the application's 
  1519. exception handler does not handle the exception, the exception handler must 
  1520. return XCPT_CONTINUE_SEARCH. If all the exception handlers in the exception 
  1521. handler chain return XCPT_CONTINUE_SEARCH, the operating system takes the 
  1522. default action, which is usually to terminate the process that caused the 
  1523. exception. 
  1524.  
  1525. Note:  In the example code fragments that follow, error checking was left out 
  1526.        to conserve space. Applications should always check the return code that 
  1527.        the functions return. Control Program functions return an APIRET value. 
  1528.        A return code of 0 indicates success. If a non-zero value is returned, 
  1529.        an error occurred. 
  1530.  
  1531.  
  1532. ΓòÉΓòÉΓòÉ 3.3.1. Example Exception Handler ΓòÉΓòÉΓòÉ
  1533.  
  1534. This section of the chapter will present a simple exception handler. Because 
  1535. exception handlers are commonly used to handle memory faults, the example will 
  1536. show the exception handler working with a memory fault. 
  1537.  
  1538. Memory exceptions can occur when an application attempts to access a guard 
  1539. page, attempts to use memory that has been allocated but not committed (a 
  1540. sparse memory object), or when an application attempts to write to memory that 
  1541. has read-only access. Without an application-registered exception handler, some 
  1542. of these exceptions might cause the application to terminate. If the 
  1543. application registers its own exception handler, it can correct the cause of 
  1544. the memory fault and continue to run. 
  1545.  
  1546. If the application's exception handler handles the exception, it returns 
  1547. XCPT_CONTINUE_EXECUTION. If the routine does not handle the exception, it 
  1548. returns XCPT_CONTINUE_SEARCH so that the exception will be passed to the next 
  1549. handler in the chain. 
  1550.  
  1551. The following code fragment shows an exception handling routine set up to deal 
  1552. with memory errors: 
  1553.  
  1554.     #define INCL_BASE
  1555.     #define INCL_DOSEXCEPTIONS
  1556.     #include <os2.h>
  1557.  
  1558.     #define HF_STDERR 2    /* Standard error handle */
  1559.  
  1560.     ULONG _cdecl myHandler(PEXCEPTIONREPORTRECORD pERepRec,
  1561.                            PEXCEPTIONREGISTRATIONRECORD pERegRec,
  1562.                            PCONTEXTRECORD pCtxRec,
  1563.                            PVOID p)
  1564.     {
  1565.         ULONG   cbWritten, ulMemSize, flMemAttrs;
  1566.         APIRET  rc;
  1567.  
  1568.         /* Access violation at a known location */
  1569.         if (pERepRec->ExceptionNum == XCPT_ACCESS_VIOLATION &&
  1570.             pERepRec->ExceptionAddress != (PVOID) XCPT_DATA_UNKNOWN) {
  1571.  
  1572.             /* Page fault */
  1573.             if ((pERepRec->ExceptionInfo[0] == XCPT_READ_ACCESS ||
  1574.                 pERepRec->ExceptionInfo[0] == XCPT_WRITE_ACCESS) &&
  1575.                 pERepRec->ExceptionInfo[1] != XCPT_DATA_UNKNOWN) {
  1576.  
  1577.                 DosWrite(HF_STDERR, "\r\nPage Fault\r\n", 15, &cbWritten);
  1578.  
  1579.                 /* Now query the memory to find out why we faulted. */
  1580.                 ulMemSize = 1;
  1581.  
  1582.                 DosQueryMem((PVOID) pERepRec->pExceptionInfo[1],
  1583.                             &ulMemSize, &flMemAttrs);
  1584.  
  1585.                 /* If the memory is free or committed, */
  1586.                 /* we have some other problem.         */
  1587.                 /* If it is not free or not committed, commit it. */
  1588.                 if (!(flMemAttrs & (PAG_FREE | PAG_COMMIT))) {
  1589.                     DosWrite(HF_STDERR,
  1590.                              "\r\nAttempt to access uncommitted memory\r\n",
  1591.                              40, &cbWritten);
  1592.  
  1593.                     rc = DosSetMem((PVOID) pERepRec->ExceptionInfo[1],
  1594.                                    4096, PAG_DEFAULT | PAG_COMMIT);
  1595.  
  1596.                     if (rc) {
  1597.                         DosWrite(HF_STDERR, "\r\nError committing memory\r\n",
  1598.                                  27, &cbWritten);
  1599.  
  1600.                         return (XCPT_CONTINUE_SEARCH);
  1601.                     }
  1602.                     else
  1603.                         return (XCPT_CONTINUE_EXECUTION);
  1604.                 }
  1605.             }
  1606.         }
  1607.         return (XCPT_CONTINUE_SEARCH);
  1608.     }
  1609.  
  1610. Exception Handler for Memory Errors 
  1611.  
  1612.  
  1613. ΓòÉΓòÉΓòÉ 3.3.2. Registering an Exception Handler ΓòÉΓòÉΓòÉ
  1614.  
  1615. An application uses DosSetExceptionHandler to register its own exception 
  1616. handling routines. More than one routine can be registered; the last routine 
  1617. registered will be called first. 
  1618.  
  1619. One or more exception handlers can be registered for each thread in a process. 
  1620. Moreover, exception handlers can be specified not only for system exceptions, 
  1621. but also for user-defined exceptions that are anticipated for a particular 
  1622. thread. 
  1623.  
  1624. Only Process Termination exceptions are sent to all threads in a process. Other 
  1625. exceptions (synchronous exceptions) are sent only to the exception handler 
  1626. registered for the thread where the exception occurred. The application must 
  1627. register an exception handler for each thread that is handling exceptions. 
  1628.  
  1629. The following code fragment shows how an application registers an exception 
  1630. handling routine: 
  1631.  
  1632.     #define INCL_BASE
  1633.     #define INCL_DOSEXCEPTIONS
  1634.     #include <os2.h>
  1635.  
  1636.     ULONG _cdecl myHandler(PEXCEPTIONREPORTRECORD,
  1637.                            PEXCEPTIONREGISTRATIONRECORD,
  1638.                            PCONTEXTRECORD,
  1639.                            PVOID);
  1640.  
  1641.     VOID main(VOID)
  1642.     {
  1643.         EXCEPTIONREGISTRATIONRECORD xcpthand = { 0, &myHandler };
  1644.  
  1645.         DosError(FERR_DISABLEEXCEPTION | FERR_DISABLEHARDERR);
  1646.  
  1647.         DosSetExceptionHandler(&xcpthand);
  1648.  
  1649.         /*
  1650.          .
  1651.          . Other processing occurs here; myHandler will handle the exceptions.
  1652.          .
  1653.          */
  1654.  
  1655.         DosUnsetExceptionHandler(&xcpthand);
  1656.     }
  1657.  
  1658.  
  1659. Registering an Exception Handler 
  1660.  
  1661. If a procedure registers an exception handler, it must deregister the handler 
  1662. by calling DosUnsetExceptionHandler before returning. 
  1663.  
  1664. Note: 
  1665.  
  1666. A procedure must not call DosSetExceptionHandler if it performs 
  1667. language-specific exception or unwind handling. This restriction is not 
  1668. enforced, but unpredictable results could occur if it is violated. 
  1669. DosSetExceptionHandler and DosUnsetExceptionHandler provide the portable means 
  1670. of implementing exception handlers. The non-portable approach is taken by 
  1671. directly manipulating the exception handler chain. High level languages 
  1672. generate code that abides by this restriction. Assembly language programmers 
  1673. must assume responsibility for verifying that handler registration and 
  1674. deregistration occur correctly. 
  1675. EXCEPTIONREGISTRATIONRECORD must be created on the application's stack. That 
  1676. is, it must be local to the routine that registers the exception handler, 
  1677. rather than a global variable. It cannot be stored in the data segment of the 
  1678. program. 
  1679.  
  1680. Note that in the code fragment above, the declaration 
  1681.  
  1682.     EXCEPTIONREGISTRATIONRECORD xcpthand = { 0, &myHandler };
  1683. is placed inside the braces.  Therefore xcpthand is local to the main() routine 
  1684. and is stored on the program's stack. 
  1685.  
  1686.  
  1687. ΓòÉΓòÉΓòÉ 3.4. Summary of Functions and Data Structures Used for Exception Handling ΓòÉΓòÉΓòÉ
  1688.  
  1689. Following are the OS/2 functions and data structures used for exception 
  1690. handling. 
  1691.  
  1692. Exception Handling Functions 
  1693.  
  1694. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1695. ΓöéException Handling Functions          ΓöéDescription           Γöé
  1696. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1697. ΓöéDosRaiseException                     ΓöéRaises an exception.  Γöé
  1698. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1699. ΓöéDosSetExceptionHandler                ΓöéRegisters an exceptionΓöé
  1700. Γöé                                      Γöéhandler.              Γöé
  1701. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1702. ΓöéDosUnsetExceptionHandler              ΓöéDeregisters an        Γöé
  1703. Γöé                                      Γöéexception handler     Γöé
  1704. Γöé                                      Γöé(removes it from the  Γöé
  1705. Γöé                                      Γöéexception handler     Γöé
  1706. Γöé                                      Γöéchain).               Γöé
  1707. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1708. ΓöéDosUnwindException                    ΓöéCalls and removes     Γöé
  1709. Γöé                                      Γöéexception handlers    Γöé
  1710. Γöé                                      Γöéfrom a thread's chain Γöé
  1711. Γöé                                      Γöéof exception handlers.Γöé
  1712. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1713. ΓöéSignal Exception Functions            ΓöéDescription           Γöé
  1714. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1715. ΓöéDosAcknowledgeSignalException         ΓöéAcknowledges a signal Γöé
  1716. Γöé                                      Γöéexception.            Γöé
  1717. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1718. ΓöéDosSendSignalException                ΓöéSends a keyboard      Γöé
  1719. Γöé                                      Γöésignal (Ctrl+C or     Γöé
  1720. Γöé                                      ΓöéCtrl+Break) exception.Γöé
  1721. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1722. ΓöéDosSetSignalExceptionFocus            ΓöéSets keyboard signal  Γöé
  1723. Γöé                                      Γöéfocus.                Γöé
  1724. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1725. ΓöéMust-Complete Functions               ΓöéDescription           Γöé
  1726. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1727. ΓöéDosEnterMustComplete                  ΓöéEnters a must-completeΓöé
  1728. Γöé                                      Γöésection of code.      Γöé
  1729. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1730. ΓöéDosExitMustComplete                   ΓöéExits a must-complete Γöé
  1731. Γöé                                      Γöésection of code.      Γöé
  1732. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1733.  
  1734. Exception Handling Data Structures 
  1735.  
  1736. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1737. ΓöéData Structure                        ΓöéDescription           Γöé
  1738. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1739. ΓöéCONTEXTRECORD                         ΓöéContains information  Γöé
  1740. Γöé                                      Γöéabout the machine's   Γöé
  1741. Γöé                                      Γöécontext at the time ofΓöé
  1742. Γöé                                      Γöéthe exception.        Γöé
  1743. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1744. ΓöéEXCEPTIONREGISTRATIONRECORD           ΓöéContains information  Γöé
  1745. Γöé                                      Γöéabout the exception   Γöé
  1746. Γöé                                      Γöéhandler. Used in      Γöé
  1747. Γöé                                      Γöéregistering the       Γöé
  1748. Γöé                                      Γöéexception handler.    Γöé
  1749. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1750. ΓöéEXCEPTIONREPORTRECORD                 ΓöéContains information  Γöé
  1751. Γöé                                      Γöéabout the exception   Γöé
  1752. Γöé                                      Γöéthat occurred.        Γöé
  1753. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1754.  
  1755.  
  1756. ΓòÉΓòÉΓòÉ 4. Error Management ΓòÉΓòÉΓòÉ
  1757.  
  1758. Error checking and error handling is extremely important in a multitasking 
  1759. operating system. The conditions in which an application is executing can 
  1760. change at any time due to the activity of other programs executing concurrently 
  1761. with the application. This chapter describes the functions that an application 
  1762. can use to manage errors that occur during processing. 
  1763.  
  1764. The following topic is related to the information in this chapter: 
  1765.  
  1766. o Exception Management. 
  1767.  
  1768.  
  1769. ΓòÉΓòÉΓòÉ 4.1. About Error Management ΓòÉΓòÉΓòÉ
  1770.  
  1771. Successful completion of most Control Program functions is indicated by an 
  1772. error return code of 0. In the event of an error, Control Program functions 
  1773. usually return an error code that has a non-zero integer value. The non-zero 
  1774. value equates to a symbolic error identifier in the include file, BSEERR.H. The 
  1775. symbolic identifiers indicate the cause of the error. For example, a return 
  1776. code of 2 from DosOpen equates to the symbolic identifier ERROR_FILE_NOT_FOUND; 
  1777. the cause of the error is that the file being opened cannot be found. 
  1778.  
  1779. DosErrClass and DosError are supplied to assist in error processing. 
  1780.  
  1781. o DosErrClass takes as input a non-zero return value that was received from any 
  1782.   control-program function. (Any return value other than 0 indicates that an 
  1783.   error occurred.) The output is a classification of the error and a 
  1784.   recommended action. Depending on the application, the recommended action 
  1785.   could be followed, or a specific recovery action could be performed. 
  1786.  
  1787. o DosError enables an application to prevent the operating system from 
  1788.   displaying a default error message in a pop-up window when either a hard 
  1789.   error or a software exception occurs. 
  1790.  
  1791.  
  1792. ΓòÉΓòÉΓòÉ 4.1.1. Classifying Return Values ΓòÉΓòÉΓòÉ
  1793.  
  1794. When a control-program function has been successfully completed, a return value 
  1795. of 0 is returned to the calling thread. A non-zero return value indicates that 
  1796. an error has occurred. 
  1797.  
  1798. Each non-zero value corresponds to a symbolic error identifier that indicates 
  1799. the cause of the error. For example, a return value of 2 from DosOpen 
  1800. (indicating that the file was not found) corresponds to the symbolic identifier 
  1801. ERROR_FILE_NOT_FOUND. 
  1802.  
  1803. DosErrClass helps applications deal with non-zero return values by taking a 
  1804. return value as input and returning both an error classification and a 
  1805. recommended action. Depending on the application, the recommended action could 
  1806. be followed, or a more specific recovery routine could be executed. 
  1807.  
  1808.  
  1809. ΓòÉΓòÉΓòÉ 4.1.2. Disabling Error Notification ΓòÉΓòÉΓòÉ
  1810.  
  1811. A hard error is typically an error (such as the opening of a disk-drive door 
  1812. while a diskette is being read, or any similar kind of device error) that 
  1813. cannot be resolved by software. When a hard error occurs, the system default 
  1814. action is to prompt for user input by displaying a message in a pop-up window. 
  1815.  
  1816. DosError disables the default action, foregoing the displayed message and 
  1817. causing an appropriate return value to be returned to whichever control-program 
  1818. function was running when the hard error occurred. The application must 
  1819. determine the appropriate response by referring to the return value. 
  1820.  
  1821. DosError also enables the application to disable end-user notification if 
  1822. either a program exception or an untrapped numeric-processor exception occurs. 
  1823. However, if one of these exceptions occurs while user notification is disabled, 
  1824. the application will still be ended. 
  1825.  
  1826. As with hard errors, the system default is that user notification for these 
  1827. exceptions is enabled. 
  1828.  
  1829.  
  1830. ΓòÉΓòÉΓòÉ 4.2. Using Error Management ΓòÉΓòÉΓòÉ
  1831.  
  1832. The OS/2 operating system supplies DosErrClass and DosError for error 
  1833. processing. DosErrClass aids in determining the appropriate action that an 
  1834. application should take in response to an error. DosError enables applications 
  1835. to disable the pop-up windows used by the operating system to inform the user 
  1836. of a hard-error or an exception. 
  1837.  
  1838. Note:  In the example code fragments that follow, error checking was left out 
  1839.        to conserve space. Applications should always check the return code that 
  1840.        the functions return. Control Program functions return an APIRET value. 
  1841.        A return code of 0 indicates success. If a non-zero value is returned, 
  1842.        an error occurred. 
  1843.  
  1844.  
  1845. ΓòÉΓòÉΓòÉ 4.2.1. Classifying Errors ΓòÉΓòÉΓòÉ
  1846.  
  1847. DosErrClass receives a non-zero return value from another control-program 
  1848. function as input. It then classifies the return value, tells where in the 
  1849. system the error occurred, and recommends a corrective action. 
  1850.  
  1851. In the following example, an attempt is made to delete a nonexistent file. The 
  1852. return value is then passed to DosErrClass so that more information about the 
  1853. error can be obtained, including any corrective actions that can be taken. 
  1854.  
  1855.     #define INCL_DOSQUEUES
  1856.     #include <os2.h>
  1857.  
  1858.     #define FILE_DELETE "JUNK.FIL"
  1859.  
  1860.     ULONG   Error;
  1861.     ULONG   Class;
  1862.     ULONG   Action;
  1863.     ULONG   Locus;
  1864.     APIRET  rc;
  1865.  
  1866.     Error = DosDelete(FILE_DELETE);        /* File name path                */
  1867.  
  1868.     rc = DosErrClass(Error,                /* Return value to be analyzed   */
  1869.                      &Class,               /* Error classification          */
  1870.                      &Action,              /* Recommended corrective action */
  1871.                      &Locus);              /* Where the error occurred      */
  1872.  
  1873.  
  1874. Classifying File Errors 
  1875.  
  1876. When called by a family-mode application, this function can return a valid 
  1877. error classification only for errors that have actually occurred. Also, the 
  1878. classifications of a given return value might not be the same for family-mode 
  1879. and OS/2-mode applications. 
  1880.  
  1881.  
  1882. ΓòÉΓòÉΓòÉ 4.2.2. Disabling Hard-Error and Exception Messages ΓòÉΓòÉΓòÉ
  1883.  
  1884. DosError disables or enables end-user notification of hard errors, program 
  1885. exceptions, or untrapped, numeric-processor exceptions. 
  1886.  
  1887. In the following example, pop-up windows for hard errors and exceptions are 
  1888. disabled, then enabled again. 
  1889.  
  1890.     #define INCL_DOSMISC   /* Error and exception values */
  1891.     #include <os2.h>
  1892.  
  1893.     #define ENABLE_HARDERROR    1
  1894.     #define DISABLE_HARDERROR   0
  1895.     #define ENABLE_EXCEPTION    0
  1896.     #define DISABLE_EXCEPTION   2
  1897.     #define ENABLE_ERRORPOPUPS  ENABLE_EXCEPTION | ENABLE_HARDERROR
  1898.     #define DISABLE_ERRORPOPUPS DISABLE_EXCEPTION | DISABLE_HARDERROR
  1899.  
  1900.     APIRET rc;    /* Return code */
  1901.  
  1902.     rc = DosError(DISABLE_ERRORPOPUPS);   /* Action flag for disable */
  1903.     rc = DosError(ENABLE_ERRORPOPUPS);    /* Action flag for enable  */
  1904.  
  1905.  
  1906. Disabling and Enabling Hard-Error and Exception Messages 
  1907.  
  1908. The action to take is encoded as a binary flag. The following table shows the 
  1909. bit-values and their meanings. 
  1910.  
  1911. Bit Values to Enable and Disable Hard-Error and Exception Pop-up Messages 
  1912.  
  1913. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1914. ΓöéBit  ΓöéValueΓöéMeaning                                           Γöé
  1915. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1916. Γöé0    Γöé1    ΓöéEnables hard-error pop-up messages.               Γöé
  1917. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1918. Γöé0    Γöé0    ΓöéDisables hard-error pop-up messages.              Γöé
  1919. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1920. Γöé1    Γöé0    ΓöéEnables exception pop-up messages.                Γöé
  1921. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1922. Γöé1    Γöé1    ΓöéDisables exception pop-up messages.               Γöé
  1923. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1924. If DosError is not called, user notification for hard errors and exceptions is 
  1925. enabled by default. 
  1926.  
  1927.  
  1928. ΓòÉΓòÉΓòÉ 4.3. Summary of Functions Used for Error Management ΓòÉΓòÉΓòÉ
  1929.  
  1930. Following are the OS/2 functions used for error management. 
  1931.  
  1932. Error Management Functions 
  1933.  
  1934. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1935. ΓöéFunction            ΓöéDescription                             Γöé
  1936. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1937. ΓöéDosErrClass         ΓöéReturns information on the              Γöé
  1938. Γöé                    Γöéclassification of a non-zero return     Γöé
  1939. Γöé                    Γöécode, and a recommended corrective      Γöé
  1940. Γöé                    Γöéaction.                                 Γöé
  1941. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1942. ΓöéDosError            ΓöéDisables and enables hard-error and     Γöé
  1943. Γöé                    Γöéexception pop-up messages.              Γöé
  1944. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1945.  
  1946.  
  1947. ΓòÉΓòÉΓòÉ 5. Extended Attributes ΓòÉΓòÉΓòÉ
  1948.  
  1949. OS/2 file systems maintain a standard set of information on file objects. This 
  1950. standard set of information is referred to as Level 1 file information. Level 1 
  1951. file information includes the name and size of the file object, and the date 
  1952. and time the file object was created, last accessed, and last written to. 
  1953.  
  1954. Applications can attach additional information to a file object in the form of 
  1955. an extended attribute (EA). There can be many EAs associated with a file object 
  1956. and, because of their flexibility, almost any information about the file can be 
  1957. stored in one. 
  1958.  
  1959. The following topics are related to the information in this chapter: 
  1960.  
  1961. o File Systems 
  1962. o File Names 
  1963. o File Management 
  1964.  
  1965.  
  1966. ΓòÉΓòÉΓòÉ 5.1. About Extended Attributes. ΓòÉΓòÉΓòÉ
  1967.  
  1968. Level 1 file information is the basic information describing files that is 
  1969. stored by the file system. Level 1 file information includes the size of the 
  1970. file, and the date and time it was created, last written, and last accessed. A 
  1971. subset of this information is typically displayed by entering the DIR command 
  1972. on the OS/2 command line. Applications can obtain Level 1 file information by 
  1973. calling DosQueryPathInfo and DosQueryFileInfo. Applications can set Level 1 
  1974. File Information by calling DosSetPathInfo and DosSetFileInfo. 
  1975.  
  1976. Applications can attach additional information to a file object in the form of 
  1977. an extended attribute (EA). Extended attributes can be used to describe the 
  1978. file object to another application, to the operating system, and to the file 
  1979. system that is managing that object. 
  1980.  
  1981. This information can be used to: 
  1982.  
  1983. o Store notes on file objects (for example, the name of the file creator) 
  1984. o Categorize file objects (for example, source, samples, icons, bit maps) 
  1985. o Describe the format of data contained in the file object (for example, a data 
  1986.   record) 
  1987. o Append additional data to the file object. 
  1988.  
  1989. An application uses extended attributes to provide a description of a file or 
  1990. directory but the application does not place the description in the file or 
  1991. directory itself. Extended attributes associated with a file object are not 
  1992. part of the file object or its data. They are stored separately from the file 
  1993. they are linked to and the file system manages the storage and maintenance of 
  1994. the EA. 
  1995.  
  1996. Each extended attribute has two parts, a name and a value. The name is a 
  1997. NULL-terminated string; any convenient name can be chosen. EA names are 
  1998. restricted to the same character set as file names. 
  1999.  
  2000. The value of the EA can be text, a bit map, binary data, anything at all. The 
  2001. operating system does not check data that is associated with an EA. The 
  2002. application that creates the extended attributes and the applications that read 
  2003. them must recognize the format and meaning of the data associated with a given 
  2004. EA name. 
  2005.  
  2006. Applications can examine, add, and replace extended attributes at any time. Any 
  2007. application can read the extended attributes by using the DosQueryFileInfo or 
  2008. DosQueryPathInfo function. Applications can use DosFindFirst and DosFindNext to 
  2009. search for files that have specific extended attributes. 
  2010.  
  2011. A file can have any number of extended attributes. Each extended attribute can 
  2012. be up to 64KB  in size. The sum of all extended attributes for a file must not 
  2013. exceed 64KB. 
  2014.  
  2015. So that extended attribute data can be understood by other applications, 
  2016. conventions have been established for naming EAs and indicating the type of 
  2017. data they contain. 
  2018.  
  2019. In addition, a set of Standard Extended Attributes (SEAs) have been defined. 
  2020. SEAs define a common set of information that can be associated with most files 
  2021. (for example, file type and file purpose). Through SEAs, many applications can 
  2022. access the same, useful information associated with files. 
  2023.  
  2024. Applications are not limited to using SEAs to associate information with files. 
  2025. They can define their own application-specific extended attributes. 
  2026.  
  2027. Extended attributes associated with a file object are not part of the file 
  2028. object or its data. 
  2029.  
  2030. Extended attributes are supported by the OS/2 High Performance File System and 
  2031. by the OS/2 FAT file system in versions of the OS/2 operating system including 
  2032. and following Version 1.2. 
  2033.  
  2034. Applications define and associate extended attributes with a file object 
  2035. through file system functions. The file system functions that use and 
  2036. manipulate EAs are: 
  2037.  
  2038. o DosOpen 
  2039. o DosFindFirst 
  2040. o DosQueryFileInfo 
  2041. o DosQueryPathInfo 
  2042. o DosSetFileInfo 
  2043. o DosSetPathInfo 
  2044.  
  2045.  
  2046. ΓòÉΓòÉΓòÉ 5.1.1. Extended Attribute Data Type Conventions ΓòÉΓòÉΓòÉ
  2047.  
  2048. Extended attributes (EAs) can contain any type of data. So that applications 
  2049. can understand the type of information stored in an EA, the first WORD of EA 
  2050. data must specify one of the following data types: 
  2051.  
  2052. Extended Attribute Data Types 
  2053.  
  2054. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2055. ΓöéData Type      ΓöéValue ΓöéDescription                             Γöé
  2056. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2057. ΓöéEAT_BINARY     ΓöéFFFE  ΓöéBinary (non-text) data; the first WORD  Γöé
  2058. Γöé               Γöé      Γöéfollowing the data type specifies the   Γöé
  2059. Γöé               Γöé      Γöélength of the data.                     Γöé
  2060. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2061. ΓöéEAT_ASCII      ΓöéFFFD  ΓöéASCII text; the first WORD following theΓöé
  2062. Γöé               Γöé      Γöédata type specifies the length of the   Γöé
  2063. Γöé               Γöé      Γöédata.                                   Γöé
  2064. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2065. ΓöéEAT_BITMAP     ΓöéFFFB  ΓöéBit map data; the first WORD following  Γöé
  2066. Γöé               Γöé      Γöéthe data type specifies the length of   Γöé
  2067. Γöé               Γöé      Γöéthe data.                               Γöé
  2068. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2069. ΓöéEAT_METAFILE   ΓöéFFFA  ΓöéMetafile data; the first WORD following Γöé
  2070. Γöé               Γöé      Γöéthe data type specifies the length of   Γöé
  2071. Γöé               Γöé      Γöéthe data.                               Γöé
  2072. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2073. ΓöéEAT_ICON       ΓöéFFF9  ΓöéIcon data; the first WORD following the Γöé
  2074. Γöé               Γöé      Γöédata type specifies the length of the   Γöé
  2075. Γöé               Γöé      Γöédata.                                   Γöé
  2076. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2077. ΓöéEAT_EA         ΓöéFFEE  ΓöéASCII name of another EA that is        Γöé
  2078. Γöé               Γöé      Γöéassociated with the file. The contents  Γöé
  2079. Γöé               Γöé      Γöéof that EA are to be included into the  Γöé
  2080. Γöé               Γöé      Γöécurrent EA. The first WORD following theΓöé
  2081. Γöé               Γöé      Γöédata type specifies the length of the   Γöé
  2082. Γöé               Γöé      Γöédata.                                   Γöé
  2083. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2084. ΓöéEAT_MVMT       ΓöéFFDF  ΓöéMulti-Valued, Multi-Typed data-two or   Γöé
  2085. Γöé               Γöé      Γöémore consecutive extended attribute     Γöé
  2086. Γöé               Γöé      Γöévalues. Each value has an explicitly    Γöé
  2087. Γöé               Γöé      Γöéspecified type.                         Γöé
  2088. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2089. ΓöéEAT_MVST       ΓöéFFDE  ΓöéMulti-Valued, Single-Typed data-two or  Γöé
  2090. Γöé               Γöé      Γöémore consecutive extended attribute     Γöé
  2091. Γöé               Γöé      Γöévalues. All values have the same type.  Γöé
  2092. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2093. ΓöéEAT_ASN1       ΓöéFFDD  ΓöéASN.1 field data; an ISO standard for   Γöé
  2094. Γöé               Γöé      Γöédescribing multivalue data streams.     Γöé
  2095. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2096. Values of hex 8000 and up are reserved. Values between hex 0000 and hex 7FFF 
  2097. can be defined by the user. 
  2098.  
  2099. Symbolic constants are defined in BSEDOS.H and BSEDOS.INC. 
  2100.  
  2101. In all cases, the length specifies the number of bytes of data. Other values 
  2102. for data types, in the range hex 0000 through hex 7FFF, can be used for 
  2103. user-defined extended attributes. 
  2104.  
  2105. All user-defined data types should be length-preceded, meaning that a WORD 
  2106. indicating the length of the data (in bytes) precedes the data. 
  2107.  
  2108. For example, here is how to represent the string "Hello": 
  2109.  
  2110.     EAT_ASCII    0005    Hello
  2111.  
  2112.  
  2113. Extended Attribute ASCII Text String 
  2114.  
  2115.  
  2116. ΓòÉΓòÉΓòÉ 5.1.1.1. Multi-Value Data Type Fields ΓòÉΓòÉΓòÉ
  2117.  
  2118. In many cases, it is desirable for extended attributes (EAs) to store more than 
  2119. a single piece of information. For example, an extended attribute can store a 
  2120. list of names to which a document was sent. The multi-value formats specify how 
  2121. individual pieces of data are stored. 
  2122.  
  2123. Data entries are length-preceded, making it easy to traverse a multi-valued 
  2124. list. 
  2125.  
  2126. In order to allow EAs of different code pages, multi-valued EAs include a field 
  2127. in which the EA's code page is specified. For example, the code page field 
  2128. could be used to indicate that the comments for a Kanji file are written in 
  2129. Spanish. If this value is 0, the file default is assumed. (Code page data is 
  2130. for use by applications. The operating system does not examine or use EA code 
  2131. page information.) 
  2132.  
  2133. When the concept of a default applies to a multi-valued EA, the first entry in 
  2134. the list is assumed to be the default. For example, suppose an EA entry 
  2135. contains the strings "Text" and "C Code". "Text" is considered the default 
  2136. type. If "C Code" were the first entry in the list ("C Code" then "Text"), then 
  2137. "C Code" would be considered the default type. 
  2138.  
  2139. There are three multi-valued EA data types: 
  2140.  
  2141. o Multi-Valued, Multi-Typed Data 
  2142. o Multi-Valued, Single-Type Data 
  2143. o ASN.1 Data. 
  2144.  
  2145.  
  2146. ΓòÉΓòÉΓòÉ 5.1.1.2. Multi-Valued, Multi-Typed Data Type ΓòÉΓòÉΓòÉ
  2147.  
  2148. This data type indicates that the value of a single extended attribute (EA) 
  2149. contains several pieces of information, each of a different data type. It is 
  2150. formatted as follows: 
  2151.  
  2152.     EAT_MVMT  Codepage  NumEntries  [DataType Data] ...
  2153.     WORD      WORD      WORD         WORD
  2154.  
  2155.  
  2156. Format of Multi-Valued, Multi-Typed Extended Attributes 
  2157.  
  2158. The first word indicates that the EA value is multi-valued, multi-typed. The 
  2159. second word indicates the code page associated with the language in which the 
  2160. EA value is written. The third word indicates the number of entries contained 
  2161. in this EA value. The next word indicates the data type for the first entry in 
  2162. this EA value, followed by the data for the first entry. The next word, if any, 
  2163. indicates the data type for the second entry in this EA value, followed by the 
  2164. data for the second entry. The pattern repeats- data type, followed by data-for 
  2165. any remaining entries. 
  2166.  
  2167. For example, an extended attribute can have the following value: 
  2168.  
  2169.     EAT_MVMT  0000  0002  EAT_ASCII   000A Hello John
  2170.                           EAT_BINARY  0003 0x12 0x21 0x34
  2171.  
  2172.  
  2173. A Multi-Valued Multi-Typed Extended Attribute 
  2174.  
  2175. This is a multi-valued extended attribute with two entries, using the default 
  2176. code page. The first entry is the string "Hello John", and the second is the 
  2177. binary data 0x12 0x21 0x34. 
  2178.  
  2179. Whether or not the data is length-preceded is a function of the data type. 
  2180.  
  2181.  
  2182. ΓòÉΓòÉΓòÉ 5.1.1.3. Multi-Valued, Single-Type Data Type ΓòÉΓòÉΓòÉ
  2183.  
  2184. This data type indicates that the value of a single extended attribute (EA) 
  2185. contains several pieces of information, each of the same data type.  For 
  2186. example: 
  2187.  
  2188.     EAT_MVST  Codepage  NumEntries  Data_Type  [data] ...
  2189.     WORD      WORD      WORD        WORD
  2190.  
  2191.  
  2192. Format of Multi-Valued, Single-Typed Extended Attributes 
  2193.  
  2194. The first word indicates that the EA value is multi-valued, single-typed. The 
  2195. second word indicates the code page associated with the language in which the 
  2196. EA value is written. The third word indicates the number of entries contained 
  2197. in this EA value. The next word indicates the data type of all the entries 
  2198. contained in this EA value, followed by the data for all entries. 
  2199.  
  2200. For example, the following EA value contains three ASCII names: 
  2201.  
  2202.     EAT_MVST 0000 0003 EAT_ASCII 0004 Mark
  2203.                                  0005 Ellen
  2204.                                  0003 Liz
  2205.  
  2206.  
  2207. MVMT Extended Attribute Containing Three ASCII Names 
  2208.  
  2209. Each name string is preceded by the length of the string. Whether or not the 
  2210. data is length-preceded is a function of the data type. 
  2211.  
  2212.  
  2213. ΓòÉΓòÉΓòÉ 5.1.1.4. ASN.1 Data Type ΓòÉΓòÉΓòÉ
  2214.  
  2215. This data type indicates that the extended attribute uses the ASN.1 ISO 
  2216. standard to describe a multi-valued data stream. 
  2217.  
  2218.  
  2219. ΓòÉΓòÉΓòÉ 5.1.2. Including One Extended Attribute in Another ΓòÉΓòÉΓòÉ
  2220.  
  2221. Extended attributes (EA) can contain pointers to data stored in other places. 
  2222.  
  2223. This data type indicates that the data contained in another EA associated with 
  2224. the file object should be included into the current EA. 
  2225.  
  2226. For example, the following EA value contains the string "Hello", followed by 
  2227. the data in the EA named AB.STUFF, followed by the string "Bye". 
  2228.  
  2229.     EA_MVMT 0000 0003 EAT_ASCII 0005  Hello
  2230.                       EAT_EA    0008  AB.STUFF
  2231.                       EAT_ASCII 0003  Bye
  2232.  
  2233.  
  2234. Extended Attribute Containing Data in Another Extended Attribute 
  2235.  
  2236.  
  2237. ΓòÉΓòÉΓòÉ 5.1.3. Extended Attribute Naming Conventions ΓòÉΓòÉΓòÉ
  2238.  
  2239. Because many applications use text, bit maps, and other binary data in extended 
  2240. attributes, standard names have been adopted to help identify these formats. An 
  2241. application is not limited to these Standard Extended Attributes but should use 
  2242. them when many applications will be accessing the same data. 
  2243.  
  2244. Standard Extended Attributes (SEAs) have a dot (.) as a prefix. This identifies 
  2245. the extended attribute as a SEA. The leading dot is reserved, so applications 
  2246. should not define extended attributes that start with a dot. Also, extended 
  2247. attributes that start with the characters $, @, &, or + are reserved for system 
  2248. use. 
  2249.  
  2250. To ensure that its extended attributes are unique, an application should use 
  2251. the name of the company and the name of the application (or suitable 
  2252. abbreviations of each) as a prefix for application-specific extended 
  2253. attributes. 
  2254.  
  2255. For example, Company A has an OS/2 Application, B, that defines extended 
  2256. attributes STUFF, MORE_STUFF, and STILL_MORE_STUFF for its file objects. The 
  2257. names of these extended attributes could be represented by the following entry: 
  2258.  
  2259.     AB.STUFF   AB.MORE_STUFF   AB.STILL_MORE_STUFF
  2260.  
  2261.  
  2262. Extended Attribute Names 
  2263.  
  2264.  
  2265. ΓòÉΓòÉΓòÉ 5.1.4. Standard Extended Attributes ΓòÉΓòÉΓòÉ
  2266.  
  2267. There are nine OS/2 Standard Extended Attributes (SEAs). 
  2268.  
  2269. The name of a SEA has a dot (.) as a prefix. This identifies the extended 
  2270. attribute as a SEA. 
  2271.  
  2272. The values of Standard Extended Attributes can be multi- or single-valued, with 
  2273. formats following the data type conventions discussed previously. 
  2274.  
  2275. Where entries for Standard EAs consist of ASCII characters, case is important. 
  2276.  
  2277.  The Standard EAs that have been defined are: 
  2278.  
  2279. .ASSOCTABLE 
  2280. .CODEPAGE 
  2281. .COMMENTS 
  2282. .HISTORY 
  2283. .ICON 
  2284. .KEYPHRASES 
  2285. .LONGNAME 
  2286. .SUBJECT 
  2287. .TYPE 
  2288. .VERSION 
  2289.  
  2290. The .TYPE and .ASSOCTABLE extended attributes (EA) are two of the most useful 
  2291. SEAs. 
  2292.  
  2293. The .TYPE extended attribute indicates what type of data is in a file. It also 
  2294. implies what programs can edit the file, and what icon is to be used for the 
  2295. file. The operating system can use the .TYPE EA to determine a default 
  2296. application to run and a default icon for a file of a particular type (if there 
  2297. is a .ICON EA, it will be used instead of the icon associated with a particular 
  2298. data type). 
  2299.  
  2300. The .ASSOCTABLE extended attribute allows an application to indicate the type, 
  2301. extension, and icon for data files that it recognizes. It also contains an 
  2302. ownership flag. This data can be automatically installed by the operating 
  2303. system. When your program recognizes files created by other programs, you might 
  2304. want to install .ASSOCTABLE EA entries for those other programs. 
  2305.  
  2306.  
  2307. ΓòÉΓòÉΓòÉ 5.1.4.1. The .ASSOCTABLE Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2308.  
  2309. The .ASSOCTABLE extended attribute (EA) contains information that associates 
  2310. data files with the applications that create them or that know how to use them. 
  2311. The .ASSOCTABLE extended attribute enables an application to indicate the type, 
  2312. extension, and icon for the data files it recognizes. The .ASSOCTABLE EA also 
  2313. contains an ownership flag. This tells the operating system which application 
  2314. to run when the user double-clicks the mouse on a given data file. 
  2315.  
  2316. Because programs can understand and reference data files generated by other 
  2317. programs, this EA can be used to link a program with those files. 
  2318.  
  2319. The name of this EA consists of the string ".ASSOCTABLE". The value of this EA 
  2320. contains application information and consists of multi-valued, multi-typed 
  2321. fields that link the application with: 
  2322.  
  2323. o the file type (that is, the value of a .TYPE EA), 
  2324. o the file extension, 
  2325. o and icon data for data files that it generates or references. The .ASSOCTABLE 
  2326.   EA associates icons by file-type. The data file's file-type is indicated in 
  2327.   the .TYPE EA, or, if the data file does not have a .TYPE EA, by the 
  2328.   extension. 
  2329.  
  2330. This data can be installed automatically by the operating system. 
  2331.  
  2332. The format of the EA is as follows. 
  2333.  
  2334.     EAT_MVMT 0000 0004 EAT_ASCII  .TYPE name
  2335.                        EAT_ASCII   file extension
  2336.                        EAT_BINARY  flags
  2337.                        EAT_ICON    icon data
  2338.  
  2339.  
  2340. Format of the Entries in the .ASSOCTABLE Extended Attribute 
  2341.  
  2342. The source for the .ASSOCTABLE EA is contained in the resource file for an 
  2343. application. The .ASSOCTABLE EA is created using the Resource Compiler from a 
  2344. table with the following form: 
  2345.  
  2346.     ASSOCTABLE  assoctable -id
  2347.     BEGIN
  2348.     association_name,[extension],[flags], [icon_filename]
  2349.     association_name,[extension],[flags], [icon_filename]
  2350.      .
  2351.      .
  2352.      .
  2353.     END
  2354.  
  2355.  
  2356. .ASSOCTABLE Table Used by the Resource Compiler 
  2357.  
  2358. The association_name is the name of a file type that the Resource Compiler 
  2359. understands. (This is the same name found in the .TYPE field of data files.) 
  2360.  
  2361. The extension is the three letter file extension that is used to identify files 
  2362. of this type, if they have no .TYPE EA entry. (Three letter extensions should 
  2363. be used so that FAT file systems can make use of this EA). This field can be 
  2364. empty. 
  2365.  
  2366. The icon_filename is the name of the file that contains the icon that is to be 
  2367. used to represent this file type.  (This field can also be empty.) 
  2368.  
  2369. The .ASSOCTABLE flag indicates that the program is the default application for 
  2370. data files with the specified type. This determines the program the operating 
  2371. system will start when the file is double-clicked with the mouse. 
  2372.  
  2373. If more than one program has marked itself as the EAF_DEFAULTOWNER for a 
  2374. particular data file .TYPE, the operating system will not know which program to 
  2375. run when the file of this .TYPE is double-clicked on with the mouse. If no 
  2376. program is marked as the EAF_DEFAULTOWNER for a particular data file .TYPE, the 
  2377. operating system will be similarly confused. In both cases, the operating 
  2378. system provides the user with a list of applications that understand the file 
  2379. .TYPE, regardless of whether the application is the owner or not.  The user 
  2380. selects the program to run from this list. 
  2381.  
  2382. The flag entry indicates whether the application owns the file or merely 
  2383. recognizes the .TYPE. If this flag is set, the entry describing data files of 
  2384. this type cannot be edited. This flag is specified if a previously defined icon 
  2385. in the ASSOCTABLE is to be reused. Entries with this flag set have no icon data 
  2386. defined. The icon used for this entry will be the icon used for the previous 
  2387. entry. 
  2388.  
  2389. EAF_ flags can be ORed together when specified in the ASSOCTABLE. The EAF_ 
  2390. flags are defined in PMWIN.H and PMWIN.INC. 
  2391.  
  2392. .ASSOCTABLE Example 
  2393. For example, My_Company's application, My_Application, generates or references 
  2394. data files that have the following .TYPE names: 
  2395.  
  2396.     My_Company My_Application documentation
  2397.     My_Company My_Application macros
  2398.     My_Company My_Application spreadsheet
  2399.     My_Company My_Application chart
  2400.     Your_Company Your_Application forecast
  2401.  
  2402.  
  2403. My_Application's .TYPE Extended Attribute 
  2404.  
  2405. The source for the .ASSOCTABLE extended attribute in the resource file for 
  2406. My_Application could look like the following. 
  2407.  
  2408.     ASSOCTABLE
  2409.     BEGIN
  2410.     "My_Company My_Application documentation", "DOC", EAF_DEFAULTOWNER, My_App.ICO
  2411.     "My_Company My_Application macros", "MAC", EAF_DEFAULTOWNER+EAF_REUSEICON
  2412.     "My_Company My_Application spreadsheet", "SPR", EAF_DEFAULTOWNER+EAF_REUSEICON
  2413.     "My_Company My_Application chart", "CHT", EAF_DEFAULTOWNER+EAF_REUSEICON
  2414.     "Your_Company Your_Application forecast", "FOR", 0
  2415.     END
  2416.  
  2417.  
  2418. Sample Resource Compiler Source File 
  2419.  
  2420. My_Application can load and use some files generated by Your_Application. 
  2421. However, because My_Application is not the default owner of those files, the 
  2422. operating system does not run My_Application when the user double-clicks on the 
  2423. files with the mouse. 
  2424.  
  2425. The following example illustrates how the value of the .ASSOCTABLE EA for 
  2426. My_Application might look. It is a multi-valued, multi-typed EA with five 
  2427. multi-valued, multi-typed entries (one for each file type referenced or 
  2428. generated by the application). 
  2429.  
  2430.     EAT_MVMT   0000 0005          ; There are 5 associated file types
  2431.  
  2432.     EAT_MVMT   0000 0004          ; Description of 1st associated file type
  2433.     EAT_ASCII  0027 My_Company My_Application documentation  ; File type
  2434.     EAT_ASCII  0003 DOC           ; File extension
  2435.     EAT_BINARY flags              ; Flags
  2436.     EAT_ASCII  icon data          ; Physical icon data
  2437.  
  2438.     EAT_MVMT   0000 0004          ; Description of 2nd associated file type
  2439.     EAT_ASCII  0020 My_Company My_Application macros
  2440.     EAT_ASCII  0003 MAC
  2441.     EAT_BINARY flags
  2442.     EAT_ICON   icon data
  2443.  
  2444.     EAT_MVMT   0000 0004          ; Description of 3rd associated file type
  2445.     EAT_ASCII  0025 My_Company My_Application spreadsheet
  2446.     EAT_ASCII  0003 SPR
  2447.     EAT_BINARY flags
  2448.     EAT_ICON   icon data
  2449.  
  2450.     EAT_MVMT   0000 0004          ; Description of 4th associated file type
  2451.     EAT_ASCII  001F My_Company My_Application chart
  2452.     EAT_ASCII  0003 CHT
  2453.     EAT_BINARY flags
  2454.     EAT_ICON   icon data
  2455.  
  2456.     EAT_MVMT   0000 0004          ; Description of 5th associated file type
  2457.     EAT_ASCII  001F Your_Company Your_Application forecast
  2458.     EAT_ASCII  0003 FOR
  2459.     EAT_BINARY flags
  2460.     EAT_ICON   icon data
  2461.  
  2462.  
  2463. .ASSOCTABLE EA Value for My_Application
  2464.  
  2465.  
  2466. ΓòÉΓòÉΓòÉ 5.1.4.2. The .CODEPAGE Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2467.  
  2468. The .CODEPAGE extended attribute (EA) contains the code page for the file. If 
  2469. this extended attribute is not provided, the code page of the file is the 
  2470. system default or is defined by the application. 
  2471.  
  2472. The code page of the EA data associated with the file is assumed to be that of 
  2473. the file, unless the EA entry is specifically overridden in the code page field 
  2474. in the multi-valued extended attribute data type. 
  2475.  
  2476.  
  2477. ΓòÉΓòÉΓòÉ 5.1.4.3. The .COMMENTS Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2478.  
  2479. The .COMMENTS extended attribute (EA) contains miscellaneous notes or reminders 
  2480. about the file (for example, peculiarities, restrictions, or requirements). 
  2481.  
  2482. The name of this EA consists of the string ".COMMENT". The value of this EA 
  2483. consists of miscellaneous notes and can be multi-valued and of any type. 
  2484.  
  2485.  
  2486. ΓòÉΓòÉΓòÉ 5.1.4.4. The .HISTORY Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2487.  
  2488. The .HISTORY extended attribute (EA) contains the modification history for a 
  2489. file object, indicating the author of the file and all subsequent changes. Each 
  2490. entry is separate field in a multi-value field and consists of be ASCII 
  2491. characters only. 
  2492.  
  2493. The name of this EA consists of the string ".HISTORY". The value of this EA 
  2494. contains the modification history for a file object and can be multi-valued, 
  2495. with each action entry described in a separate field. 
  2496.  
  2497. Each entry in the .HISTORY field has the following format: 
  2498.  
  2499.     PERSON  ACTION(created, changed or printed)  DATE
  2500.  
  2501.  
  2502. Format of the .HISTORY Extended Attribute 
  2503.  
  2504. For example, the following .HISTORY extended attribute contains two entries: 
  2505.  
  2506.     EAT_MVMT 0000 0002
  2507.              EAT_ASCII 0017 Joe    Created  2/10/88
  2508.              EAT_ASCII 0017 Harry  Changed  2/11/88
  2509.  
  2510.  
  2511. .HISTORY Extended Attribute with Two Entries 
  2512.  
  2513. This extended attribute can potentially become quite large. To avoid unwanted 
  2514. growth, an application can let the user decide when an entry should be added to 
  2515. this extended attribute. For example, there are some cases when it is important 
  2516. to note when a document is printed. However, it is probably unnecessary to note 
  2517. it every time the file is printed. 
  2518.  
  2519.  
  2520. ΓòÉΓòÉΓòÉ 5.1.4.5. The .ICON Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2521.  
  2522. The .ICON extended attribute (EA) specifies the icon to be used for the file 
  2523. representation, for example when the application is minimized. This extended 
  2524. attribute contains the physical icon data used to represent the file object. 
  2525.  
  2526. If there is no .ICON EA, the operating system can use the .TYPE entry to 
  2527. determine a default icon to use for the particular file. If there is an .ICON 
  2528. entry, however, it is used instead of the default icon. 
  2529.  
  2530. The name of this EA consists of the string ".ICON". The value of this EA 
  2531. contains the physical icon data and has the following format: 
  2532.  
  2533.     EAT_ICON  data_length  data
  2534.     WORD      DWORD
  2535.  
  2536.  
  2537. Format of the .ICON Extended Attribute 
  2538.  
  2539. The data is of type BITMAPARRAYFILEHEADER and is used to specify an array of 
  2540. one device-dependent and one device-independent icon bit maps. The 
  2541. GpiLoadBitmap and WinLoadPointer functions support this icon file format. 
  2542.  
  2543. It is best to provide as much icon information as possible. Ideally, an icon 
  2544. should be 64-by-64 bits in 8-color, device-independent format. 
  2545.  
  2546. The Icon Editor is used to create the icon, which is saved in an icon file. The 
  2547. .ICON extended attribute for an application is created by the Resource Compiler 
  2548. as part of the compile process by specifying the DEFAULTICON keyword, as in: 
  2549.  
  2550.     DEFAULTICON <filename.ico>
  2551. This keyword uses the icon definition contained in the specified icon file 
  2552. (FILENAME.ICO) to create the .ICON EA for the application. 
  2553.  
  2554. Applications store the binary icon data in this extended attribute. To install 
  2555. icons for data files, the applications can use the .ASSOCTABLE extended 
  2556. attribute, or DosSetPathInfo. 
  2557.  
  2558.  
  2559. ΓòÉΓòÉΓòÉ 5.1.4.6. The .KEYPHRASES Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2560.  
  2561. The .KEYPHRASES extended attribute (EA) contains key text phrases for the file. 
  2562. Such phrases can be used in performing a database-type search or in helping the 
  2563. user understand the nature of the file. 
  2564.  
  2565. The name of this EA consists of the string ".KEYPHRASES". The value of this EA 
  2566. consists of key phrases in ASCII. 
  2567.  
  2568. Key phrases are represented as ASCII characters. Multiple key phrases can be 
  2569. stored in the value of this extended attribute, each stored in a separate entry 
  2570. in a multi-valued field. 
  2571.  
  2572. For example, the following extended attribute contains three key phrases: 
  2573.  
  2574.     EAT_MVST 0000 0003 EAT_ASCII 0008 ABC Inc.
  2575.                        EAT_ASCII 000A Salesman A
  2576.                        EAT_ASCII 000F Product X sales
  2577.  
  2578.  
  2579. .KEYPHRASES Extended Attribute with Three Keyphrases 
  2580.  
  2581. If there is more than one key phrase, each should be stored in a separate entry 
  2582. in a multi-value field. 
  2583.  
  2584.  
  2585. ΓòÉΓòÉΓòÉ 5.1.4.7. The .LONGNAME Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2586.  
  2587. When an application attempts to write a file with a long name to a file system 
  2588. that does not support long names, it must generate a short name for the file. 
  2589. The application should notify the user of the new short name and save the 
  2590. original (long) name in the .LONGNAME extended attribute. 
  2591.  
  2592. When a file is copied from a system that uses short names to a system that uses 
  2593. long names, the application should check the .LONGNAME extended attribute. If a 
  2594. value is present, the application should rename the file to the long name, then 
  2595. remove the .LONGNAME extended attribute. 
  2596.  
  2597. See Moving Files with Long Names for more information on moving files with long 
  2598. file names. 
  2599.  
  2600.  
  2601. ΓòÉΓòÉΓòÉ 5.1.4.8. The .SUBJECT Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2602.  
  2603. The .SUBJECT extended attribute (EA) contains a brief summary of the content or 
  2604. purpose of the file object it is associated with. 
  2605.  
  2606. The name of this EA consists of the string ".SUBJECT". The value of this EA 
  2607. consists of a single-valued ASCII string that contains the purpose of the file 
  2608. object. 
  2609.  
  2610. The length of this field must be less than 40 characters. 
  2611.  
  2612.  
  2613. ΓòÉΓòÉΓòÉ 5.1.4.9. The .TYPE Standard Extended Attribute ΓòÉΓòÉΓòÉ
  2614.  
  2615. The .TYPE extended attribute (EA) indicates the file-type of the file object it 
  2616. is associated with. It is similar to a file name extension. 
  2617.  
  2618. The name of this EA consists of the string ".TYPE". The value of this EA 
  2619. contains the file object's file-type. The following file types are predefined: 
  2620.  
  2621. Plain Text 
  2622. OS/2 Command File 
  2623. DOS Command File 
  2624. Executable 
  2625. Metafile 
  2626. Bit map 
  2627. Icon 
  2628. Binary Data 
  2629. Dynamic Link Library 
  2630. C Code 
  2631. Pascal Code 
  2632. BASIC Code 
  2633. COBOL Code 
  2634. FORTRAN Code 
  2635. Assembler Code 
  2636. Library 
  2637. Resource File 
  2638. Object Code. 
  2639.  
  2640. Data files only require identification of the file type. For data files without 
  2641. EAs, the file type is derived from the file extension, if there is one. 
  2642.  
  2643. File object types are represented as length-preceded ASCII strings, uniquely 
  2644. identifying the file object's type. This identifier is referenced within the 
  2645. application's .ASSOCTABLE EA in order to bind the data file type to the 
  2646. application. It is important that this name be a unique identifier because all 
  2647. file type names are public data. For example, if application A and application 
  2648. B both had a type name of SPREADSHEET, the filing system would not be able to 
  2649. identify A's SPREADSHEET from B's SPREADSHEET. 
  2650.  
  2651. The recommended convention for defining file object types is: 
  2652.  
  2653. o Company_name 
  2654. o Application_name 
  2655. o Application-specific_name 
  2656.  
  2657. For example, spreadsheet files generated by My_Application written by 
  2658. My_Company might have a file object type of the following. 
  2659.  
  2660.     My_Company My_Application Spreadsheet
  2661.  
  2662.  
  2663. My_Company My_Application Spreadsheet's File Type 
  2664.  
  2665. Type names must be ASCII characters and case is significant. 
  2666.  
  2667. Note:  The performance of extended attributes is dependent on the file system. 
  2668.        Because some file systems store extended attributes in 
  2669.        first-in/first-out (FIFO) order, it is important to write the .TYPE 
  2670.        entry first so the operating system can access that information quickly. 
  2671.  
  2672.  
  2673. ΓòÉΓòÉΓòÉ 5.1.4.10. The .VERSION Extended Attribute ΓòÉΓòÉΓòÉ
  2674.  
  2675. The .VERSION extended attribute (EA) contains the version number of the file 
  2676. format, as shown below. 
  2677.  
  2678.     My_Application 1.0
  2679.  
  2680.  
  2681. The .VERSION Extended Attribute 
  2682.  
  2683. The name of this EA consists of the string ".VERSION". The value of this EA 
  2684. contains the file object version number. This attribute can be ASCII or binary. 
  2685. Only the application that created the file object should modify the value of 
  2686. this EA. It can also be used to indicate an application or dynamic link library 
  2687. version number. 
  2688.  
  2689.  
  2690. ΓòÉΓòÉΓòÉ 5.1.5. Managing Extended Attributes ΓòÉΓòÉΓòÉ
  2691.  
  2692. An application can create, query, and set extended attributes (EAs) for any 
  2693. file object. 
  2694.  
  2695. The application can define extended attributes for a file when the file is 
  2696. created with DosOpen. Similarly, the application can define EAs for a directory 
  2697. when the directory is created using DosCreateDir. 
  2698.  
  2699. An application can define EAs for existing file objects by referencing the file 
  2700. object by its handle and calling DosSetFileInfo, or by referencing the file 
  2701. object by its name and calling DosSetPathInfo. 
  2702.  
  2703. An application can examine the EAs for a file object by referencing the file 
  2704. object by its handle and calling DosQueryFileInfo, or by referencing the file 
  2705. object by its name and calling DosQueryPathInfo. The application can also call 
  2706. DosEnumAttribute, using either the file object's handle or its name, to get 
  2707. information about the file object's EAs. 
  2708.  
  2709. In addition, an application can search for file objects and specify that 
  2710. certain EAs be returned by calling DosFindFirst. 
  2711.  
  2712.  
  2713. ΓòÉΓòÉΓòÉ 5.1.5.1. Controlling Access to Extended Attributes ΓòÉΓòÉΓòÉ
  2714.  
  2715. Like the file objects they are associated with, extended attributes (EAs) can 
  2716. have more than one process accessing them at the same time. This means that one 
  2717. process could be querying EAs for a file object, while another is setting EAs 
  2718. for the same file object. 
  2719.  
  2720. In addition, operations on EAs are not atomic. That is, a query or set 
  2721. operation might not complete before another query or set operation is performed 
  2722. on the same object. If an error occurs before an entire list of EAs has been 
  2723. set, all, some, or none of them may actually remain set on the file object. 
  2724. This means that EAs may not remain in a consistent state unless the order in 
  2725. which the operations are performed can be guaranteed. 
  2726.  
  2727. Sharing protection is provided so that unpredictable results do not occur 
  2728. during multiple simultaneous operations on extended attributes. EA manipulation 
  2729. is associated with the access permission to the related file object (file or 
  2730. directory). 
  2731.  
  2732. Handle-based access permission is controlled by the sharing/access mode of the 
  2733. associated file object: 
  2734.  
  2735. o If the file object is open for read access, querying EAs (using 
  2736.   DosQueryFileInfo) is permitted. 
  2737.  
  2738. o If the file object is open for write access, setting EAs (using 
  2739.   DosSetFileInfo) is permitted. 
  2740.  
  2741. Path-based access permission is controlled by adding the file object to the 
  2742. sharing set for the duration of the call: an application requires read access 
  2743. and file-sharing permission must be set to deny-write. 
  2744.  
  2745. o For setting EAs (using DosSetPathInfo), an application requires write access 
  2746.   and file-sharing permission must be deny-read-write. 
  2747.  
  2748. Note:  The functions that set and query EAs fail if another process holds 
  2749.        conflicting sharing rights to the file object. 
  2750.  
  2751. No explicit EA sharing is performed for DosEnumAttribute. Implicit sharing 
  2752. exists if the caller passes the handle of an open file, since sharing access to 
  2753. the associated file is required to modify its EA. No sharing is performed if 
  2754. the caller passes the path name. This means that if some other process is 
  2755. editing the EAs, and changes them between two calls to DosEnumAttribute, 
  2756. inconsistent results might be returned (for example, the same values might be 
  2757. returned twice, some values might be missed, and so on). 
  2758.  
  2759. To prevent the modification of EAs for the handle case, the file should be 
  2760. opened in deny-write mode before calling DosEnumAttribute. To prevent the 
  2761. modification of EAs for the path name case, the file should be open in 
  2762. deny-write mode before calling DosEnumAttribute. For the directory name case, 
  2763. no sharing is possible. 
  2764.  
  2765.  
  2766. ΓòÉΓòÉΓòÉ 5.1.5.2. Extended Attribute Data Structures ΓòÉΓòÉΓòÉ
  2767.  
  2768. There are a series of data structures through which OS/2 functions manipulate 
  2769. extended attributes (EAs) for applications: 
  2770.  
  2771. o Full EAs (FEA2s) 
  2772. o A list of full EAs (FEA2LIST) 
  2773. o Get EAs (GEA2) 
  2774. o A list of get EAs (GEA2LIST) 
  2775. o EAOP2s 
  2776.  
  2777. Full Extended Attribute (FEA2) Data Structure 
  2778. A full EA (FEA2) data structure contains the extended attribute name and value. 
  2779. The name length does not include the trailing NULL. The characters that form 
  2780. the name are legal file name characters. 
  2781.  
  2782. An FEA2LIST is a list of FEA2 structures, preceded by the length of the list 
  2783. (including the length itself). FEA2Lists are used for querying, adding, 
  2784. deleting, or changing EAs. They are required input parameters for the functions 
  2785. that create or set extended attributes (DosSetFileInfo and DosSetPathInfo). 
  2786. They are required output parameters for the functions that query extended 
  2787. attributes (DosQueryFileInfo, DosQueryPathInfo, and DosEnumAttribute). 
  2788.  
  2789. FEA2 data structures include the lengths of the extended attribute's names and 
  2790. values. EA name lengths of 0 are illegal and cause errors to be returned by EA 
  2791. functions. An EA value length of 0 has special meaning: 
  2792.  
  2793. o Setting an EA with a value length of 0 in the FEA2 data structure causes that 
  2794.   attribute to be deleted, if possible. 
  2795.  
  2796. o Getting an EA with a value length of 0 in the FEA2 data structure indicates 
  2797.   that the attribute is not present. 
  2798.  
  2799. Get Extended Attribute (GEA2) Data Structure 
  2800. A Get EA (GEA2) is an extended attribute name. The name length does not include 
  2801. the trailing NULL. 
  2802.  
  2803. A GEA2LIST is a list of GEA2 structures, preceded by a length of the list 
  2804. (including the length itself). GEA2Lists are used for retrieving the values for 
  2805. a particular set of extended attributes. They are required input parameters for 
  2806. the functions that query extended attributes (DosQueryFileInfo, 
  2807. DosQueryPathInfo, and DosEnumAttribute). 
  2808.  
  2809. Note:  GEA2 data structures include the lengths of extended attribute's names 
  2810.        and values. EA name lengths of 0 are illegal and cause errors to be 
  2811.        returned by EA functions. An EA value length of 0 has special meaning. 
  2812.        Setting an EA with a value length of 0 in the FEA2 data structure causes 
  2813.        that attribute to be deleted, if possible. Getting an EA with a value 
  2814.        length of 0 in the FEA2 data structure indicates that the attribute is 
  2815.        not present. 
  2816.  
  2817. Extended Attribute Operation ( EAOP2) Data Structure 
  2818. An extended attribute operation (EAOP2) data structure consists of a GEA2LIST, 
  2819. an FEA2LIST, and an error field. All extended attribute manipulation is 
  2820. performed using this structure. Before calling an extended attribute function, 
  2821. an application must define an EAOP2 structure, with the GEA2LIST and FEA2LIST 
  2822. appropriately defined. 
  2823.  
  2824. The use of GEA2LIST and FEA2LIST for each function is described further in the 
  2825. Control Program Programming Reference. 
  2826.  
  2827.  
  2828. ΓòÉΓòÉΓòÉ 5.1.5.3. Preserving Extended Attributes ΓòÉΓòÉΓòÉ
  2829.  
  2830. Extended attributes (EAs) are supported in the OS/2 operating system FAT file 
  2831. system and High Performance File System. Extended attributes are not supported 
  2832. by the FAT file system used in versions of Operating System/2 prior to Version 
  2833. 1.2, nor are they supported in the DOS operating system. 
  2834.  
  2835. EAs associated with a file object are not part of a file object or of its data, 
  2836. but are maintained separately and managed by the file system that manages that 
  2837. object. EAs reside on the volume on which the file object resides and are 
  2838. connected to their file object by pointers from the file object. 
  2839.  
  2840. Therefore, EAs belonging to a file object are lost when moving that file object 
  2841. from a storage device managed by an OS/2 FAT or installable file system to a 
  2842. storage device managed by the old FAT file system. 
  2843.  
  2844. EAs can be lost under other circumstances, as well: 
  2845.  
  2846. o When a program that does not recognize EAs (for example, an editor written 
  2847.   for DOS) performs a non-truncating open on the files the EAs are associated 
  2848.   with 
  2849.  
  2850. o When the files they are associated with are sent over COM links. 
  2851. So that files with EAs can be manipulated under these circumstances, without 
  2852. losing their EAs, the OS/2 operating system provides a utility called EAUTIL 
  2853. EAUTIL enables users to separate extended attributes from the specified file 
  2854. object, optionally disassociating them from the file object. The extended 
  2855. attributes are placed into a specified HoldFile. This utility also enables 
  2856. users to reattach the separated extended attributes with their file objects. 
  2857.  
  2858. EAUTIL can be applied to subdirectories, as well as to files. It does not 
  2859. support global file name characters in parameters; it operates on a single file 
  2860. object at each invocation. 
  2861.  
  2862. Users can use EAUTIL to: 
  2863.  
  2864. o Strip EAs off files to be edited with a program that does not recognize EAs. 
  2865.  
  2866. o Place the EAs into normal files so they can be dealt with by old tools (such 
  2867.   as backup, restore, and so on) or easily transmitted. 
  2868.  
  2869. o Reattach EAs to files after the files have been brought back from the systems 
  2870.   where EAs are not supported. 
  2871.  
  2872. For more information on EAUTIL, see the online OS/2 Command Reference. 
  2873.  
  2874.  
  2875. ΓòÉΓòÉΓòÉ 5.1.5.4. Protecting Extended Attributes ΓòÉΓòÉΓòÉ
  2876.  
  2877.  
  2878. Programs written for releases of the OS/2 operating system and DOS that do not 
  2879. support extended attributes (EAs) will tend to lose EAs simply because they do 
  2880. not know that they exist. The OS/2 operating system provides some controls that 
  2881. prevent old programs from destroying critical data without unduly restricting 
  2882. their activities. This is done by classifying programs and marking the extended 
  2883. attributes that are associated with files. 
  2884.  
  2885. Programs are classified as: 
  2886.  
  2887. o Those that recognize EAs. These include OS/2 Version 1.2 and later programs. 
  2888.  
  2889. o Those that do not recognize EAs. These include programs written for releases 
  2890.   of the OS/2 operating system and DOS that do not support EAs. 
  2891.  
  2892. EAs associated with files are marked as critical or non-critical. Programs that 
  2893. do not recognize EAs are not permitted to manipulate files that have critical 
  2894. EAs associated with them. This protection does not apply to directories. EAs 
  2895. associated with directories cannot be marked as critical. 
  2896.  
  2897. Critical Extended Attributes 
  2898. Extended attributes (EAs) are non-critical by default. A non-critical EA is one 
  2899. that is not necessary to the functionality of the application. That is, if a 
  2900. non-critical EA is lost, the system continues to operate correctly. For 
  2901. example, losing the icons associated with data files does not generally cause 
  2902. any ill effect other than the inability to show the icon. 
  2903.  
  2904. A critical extended attribute is one which is necessary to the correct 
  2905. operation of the operating system or of a particular application. EAs should be 
  2906. marked as critical if their loss would cause the system or program to perform 
  2907. incorrectly. For example, a mail program might store mail headers in EAs. The 
  2908. loss of the header from a message would normally render the mail program 
  2909. completely unable to further use that message. This would be unacceptable, so 
  2910. the mail program should mark this EA as critical. 
  2911.  
  2912. A file has critical extended attributes (EAs) if at least one EA attached to 
  2913. the file is marked as critical. 
  2914.  
  2915. Marking EAs as critical only prevents programs that do not recognize EAs from 
  2916. losing the EAs from the file. It does not prevent deletion of files by any 
  2917. application. 
  2918.  
  2919. Applications must be careful how they mark their EAs. If they are too 
  2920. aggressive marking EAs as critical, users might be prevented from accessing 
  2921. files that their application uses. EAs are marked as critical by setting the 
  2922. critical bit. The critical bit is bit 7 of the flags byte of the FEA2 data 
  2923. structure. If this bit is 0, the EA is a non-critical EA. If it is 1, it is a 
  2924. critical EA. The symbolic constant FEA_NEEDEA can be used to indicate a 
  2925. critical EA. 
  2926.  
  2927. The creator of the EA determines whether it is critical or not. 
  2928.  
  2929. Programs that do not recognize extended attributes (EAs) are prevented from 
  2930. performing certain operations on files that have critical EAs associated with 
  2931. them. For example, a program that does not recognize EAs is not permitted to 
  2932. perform a non-truncating open on a file with critical EAs associated with it, 
  2933. because programs cannot be permitted to read the data and ignore the EAs. 
  2934.  
  2935. Programs that do not recognize EAs are, however, permitted to perform those 
  2936. operations that they can do completely. For example, they can delete files with 
  2937. critical EAs associated with them. Programs that do not recognize EAs are not 
  2938. prevented from accessing files whose EAs are not critical. 
  2939.  
  2940. Programs that recognize EAs have no restrictions placed on their actions with 
  2941. respect to critical EAs. 
  2942.  
  2943. Programs that recognize extended attributes must identify themselves to the 
  2944. operating system. This is done by including the NEWFILES declaration in the 
  2945. program's module definition file. The NEWFILES declaration is also how programs 
  2946. indicate that they understand and use long file names. 
  2947.  
  2948.  
  2949. ΓòÉΓòÉΓòÉ 5.1.5.5. Searching for Extended Attributes ΓòÉΓòÉΓòÉ
  2950.  
  2951. An application can search for file objects that have specific extended 
  2952. attribute names by calling DosFindFirst twice. The steps involved are: 
  2953.  
  2954.  1. Call DosFindFirst for FileInfoLevel = 2, to get the length of the buffer 
  2955.     required to hold the EAOP2 data associated with a matching file object. 
  2956.  
  2957.  2. Call DosFindFirst for FileInfoLevel = 3, to get the EAOP2 data associated 
  2958.     with the matching file object. 
  2959.  
  2960.  
  2961. ΓòÉΓòÉΓòÉ 5.1.5.6. Supporting Extended Attributes ΓòÉΓòÉΓòÉ
  2962.  
  2963. To support extended attributes, applications should do the following: 
  2964.  
  2965.  1. Fill in the .ASSOCTABLE extended attribute for all major file types that 
  2966.     the application recognizes or uses. 
  2967.  
  2968.  2. Fill in the .ICON extended attribute for executable files. 
  2969.  
  2970.  3. Set the .TYPE extended attribute for data files the application creates. 
  2971.  
  2972.  4. Fill in and use the .LONGNAME extended attribute as appropriate. 
  2973.  
  2974.  5. Support .HISTORY and .VERSION. 
  2975.  
  2976.  6. Support the other Standard Extended Attributes as appropriate. 
  2977.  
  2978.  
  2979. ΓòÉΓòÉΓòÉ 5.2. Summary of Extended Attribute Data Structures ΓòÉΓòÉΓòÉ
  2980.  
  2981. Following are the OS/2 data structures used in managing extended file 
  2982. attributes. 
  2983.  
  2984. Extended Attribute Data Structures 
  2985.  
  2986. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2987. ΓöéData Structure          ΓöéDescription                         Γöé
  2988. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2989. ΓöéEAOP2                   ΓöéExtended Attribute OPeration data   Γöé
  2990. Γöé                        Γöéstructure. Contains a FEA2LIST data Γöé
  2991. Γöé                        Γöéstructure, a GEA2LIST data          Γöé
  2992. Γöé                        Γöéstructure, and an error field. All  Γöé
  2993. Γöé                        ΓöéEA manipulation is performed using  Γöé
  2994. Γöé                        Γöéthis structure.                     Γöé
  2995. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2996. ΓöéFEA2                    ΓöéFull Extended Attribute data        Γöé
  2997. Γöé                        Γöéstructure. Contains an EAs name and Γöé
  2998. Γöé                        Γöévalue. Used in a FEA2LIST for       Γöé
  2999. Γöé                        Γöéquerying, adding, deleting, and     Γöé
  3000. Γöé                        Γöéchanging EAs.                       Γöé
  3001. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3002. ΓöéFEA2LIST                ΓöéList of FEA2 data structures. Used  Γöé
  3003. Γöé                        Γöéin an EAOP2 for the functions that  Γöé
  3004. Γöé                        Γöécreate, set, or query EAs.          Γöé
  3005. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3006. ΓöéGEA2                    ΓöéGet Extended Attribute data         Γöé
  3007. Γöé                        Γöéstructure. Contains an EAs name.    Γöé
  3008. Γöé                        ΓöéUsed in a GEA2LIST for querying     Γöé
  3009. Γöé                        Γöécertain EAs.                        Γöé
  3010. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3011. ΓöéGEA2LIST                ΓöéList of GEA2 data structures. Used  Γöé
  3012. Γöé                        Γöéin an EAOP2 for the functions that  Γöé
  3013. Γöé                        Γöéquery certain EAs.                  Γöé
  3014. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3015.  
  3016.  
  3017. ΓòÉΓòÉΓòÉ 6. File Management ΓòÉΓòÉΓòÉ
  3018.  
  3019. The OS/2 operating system provides a standard set of file system functions. 
  3020. This means that applications can create, open, read, write, copy, and delete 
  3021. files and directories by using the same functions, regardless of which file 
  3022. system is used. When an application calls a file system function, the operating 
  3023. system passes the request to the dynamic link library that supports the file 
  3024. system. The dynamic link library carries out most file system processing, such 
  3025. as validating file names. If an error occurs, the file system returns the error 
  3026. to the operating system, which then passes it back to the calling application. 
  3027.  
  3028. The OS/2 file system functions identify files and directories by their names. 
  3029. These functions store or search for the file or directory in the current 
  3030. directory on the current drive unless the name explicitly specifies a different 
  3031. directory and drive. Occasionally, a file system has control functions in 
  3032. addition to the standard file system functions. The control functions are 
  3033. specific to the given file system. An application can call a control function 
  3034. by using DosFSCtl, which directs the operating system to pass the 
  3035. control-function information to the corresponding dynamic link library. 
  3036.  
  3037. The following topics are related to the information in this chapter: 
  3038.  
  3039. o Files Systems 
  3040. o Files Names 
  3041. o Extended Attributes 
  3042. o Pipes 
  3043. o Device I/O. 
  3044.  
  3045.  
  3046. ΓòÉΓòÉΓòÉ 6.1. About Volumes and Drives ΓòÉΓòÉΓòÉ
  3047.  
  3048. The OS/2 operating system allows more than one file system on a single storage 
  3049. device. If the device can have more than one partition (or volume), each 
  3050. partition can be initialized as an OS/2 partition and given a valid OS/2 file 
  3051. system. For each volume, the operating system determines the type of file 
  3052. system the first time the volume is accessed by a function or when the medium 
  3053. in the drive changes. After that, the operating system manages all input and 
  3054. output to that volume by using the corresponding dynamic link library. 
  3055.  
  3056. The operating system uses the volume label and serial number to ensure that the 
  3057. medium in the drive does not change while there are outstanding requests for 
  3058. input and output. Each volume has a volume label and a 32-bit volume serial 
  3059. number, stored in a reserved location in logical sector 0 at the time of 
  3060. formatting. If the volume label and serial number do not match, the operating 
  3061. system signals the critical error handler to prompt the user to insert the 
  3062. volume that has the specified serial number and label. The operating system 
  3063. maintains the connection between the medium and the volume label and serial 
  3064. number until all open files on the volume are closed and all search references 
  3065. and cache buffer references are removed. The system redetermines the type of 
  3066. file system and the volume label and serial number only when the medium 
  3067. changes. 
  3068.  
  3069. The OS/2 operating system enables applications to: 
  3070.  
  3071. o Determine and set the default drive using DosQueryCurrentDisk and 
  3072.   DosSetDefaultDisk, respectively. 
  3073.  
  3074. o Determine and set drive information using DosQueryFSInfo and DosSetFSInfo. 
  3075.  
  3076. o Determine and set the write verification switch using DosQueryVerify and 
  3077.   DosSetVerify. If the write verification switch is on, each time data is 
  3078.   written to the disk, the data is verified to ensure it has been recorded 
  3079.   correctly. These functions are provided for recording critical data. 
  3080.  
  3081.  
  3082. ΓòÉΓòÉΓòÉ 6.2. About Directories ΓòÉΓòÉΓòÉ
  3083.  
  3084. When an application starts, it inherits the current directory and drive from 
  3085. the application that starts it. An application can determine which directory 
  3086. and drive are current by using DosQueryCurrentDir and DosQueryCurrentDisk. An 
  3087. application can change the current directory and drive of the file system by 
  3088. using DosSetCurrentDir and DosSetDefaultDisk. 
  3089.  
  3090. When an application creates a new file, the system adds a file entry to the 
  3091. specified directory. Each directory can have any number of entries, up to the 
  3092. physical limit of the disk. An application can create new directories and 
  3093. delete existing directories by using DosCreateDir and DosDeleteDir. Before a 
  3094. directory can be deleted, it must be empty; if there are files or directories 
  3095. in that directory, they must be deleted or moved. An application can delete a 
  3096. file by using DosDelete or move a file to another directory by using DosMove. 
  3097.  
  3098.  
  3099. ΓòÉΓòÉΓòÉ 6.2.1. Creating a Subdirectory ΓòÉΓòÉΓòÉ
  3100.  
  3101. To create a new subdirectory, an application calls DosCreateDir and specifies a 
  3102. directory path name. If the call is successful, a new subdirectory is created 
  3103. at the end of the path on the specified disk. If no path name is specified, a 
  3104. new subdirectory is created at the end of the current directory for the 
  3105. process. If any subdirectories in the path do not exist, the subdirectory is 
  3106. not created. 
  3107.  
  3108. Because a subdirectory is a file object, an application also can define an 
  3109. extended attribute for the directory when it is created during this call. See 
  3110. Extended Attributes for more information on extended attributes. 
  3111.  
  3112.  
  3113. ΓòÉΓòÉΓòÉ 6.2.2. Determining and Changing the Current Directory ΓòÉΓòÉΓòÉ
  3114.  
  3115. Calling DosQueryCurrentDir returns the full path name of the current directory 
  3116. for the specified drive. The string does not begin with a back slash (\) and it 
  3117. ends with a byte containing 00H, the NULL character. 
  3118.  
  3119. To change the current directory, call DosQueryCurrentDir with the path name of 
  3120. the directory you want to make the current directory. 
  3121.  
  3122.  
  3123. ΓòÉΓòÉΓòÉ 6.2.3. Deleting a Directory ΓòÉΓòÉΓòÉ
  3124.  
  3125. A subdirectory cannot be removed if it is the current subdirectory or if it 
  3126. contains hidden files or subdirectory entries other than the "." and ".." 
  3127. entries. When these requirements for removal are met, DosDeleteDir can be 
  3128. called with a path name to remove the subdirectory from the disk. 
  3129.  
  3130.  
  3131. ΓòÉΓòÉΓòÉ 6.3. About Files ΓòÉΓòÉΓòÉ
  3132.  
  3133. A file is one or more bytes of data, usually stored on a disk. While the 
  3134. application that creates the file determines the format of the file, the file 
  3135. system determines how the file is stored on the disk and what actions can be 
  3136. performed on it. The file system also stores information about the file in file 
  3137. attributes and extended attributes. 
  3138.  
  3139. Files are accessed through the file system using file handles. File handles are 
  3140. returned by DosOpen when the file is opened and are used for all subsequent 
  3141. accesses to the file. Files can be be opened, read from, written to, closed, 
  3142. copied, moved, deleted, renamed, and locked. Files can be searched for based on 
  3143. a metacharacter template. 
  3144.  
  3145. Each open file has a file pointer that indicates the current reading or writing 
  3146. location within the file. The file pointer moves automatically with each read 
  3147. or write operation on the file and can be moved manually by the application. 
  3148.  
  3149.  
  3150. ΓòÉΓòÉΓòÉ 6.3.1. File Attributes ΓòÉΓòÉΓòÉ
  3151.  
  3152. Each directory entry includes a set of file attributes. File attributes specify 
  3153. whether the directory entry is for a file, a directory, or a volume identifier. 
  3154. The attributes also specify if the file is read-only, hidden, archived, or a 
  3155. system file. 
  3156.  
  3157. A read-only file cannot be opened for writing, nor can it be deleted. A hidden 
  3158. file (or directory) cannot be displayed by using an ordinary directory listing. 
  3159. A system file is excluded from normal directory searches. The archived 
  3160. attribute is for use by special purpose applications to mark a file that has 
  3161. been changed since the last time the file was examined. 
  3162.  
  3163. An application can retrieve and set the file attributes by using 
  3164. DosQueryFileInfo  and DosSetFileInfo . 
  3165.  
  3166.  
  3167. ΓòÉΓòÉΓòÉ 6.3.2. File Handles ΓòÉΓòÉΓòÉ
  3168.  
  3169. The operating system identifies each open file by assigning it a file handle 
  3170. when the application opens or creates the file. The file handle is a unique 
  3171. 32-bit integer. The application can use the handle in functions that read from 
  3172. and write to the file, depending on how the file was opened. The application 
  3173. can continue to use the handle until the file is closed. 
  3174.  
  3175. The default maximum number of file handles for a process is 20. An application 
  3176. can change this maximum by using DosSetMaxFH. When this call is made, all 
  3177. currently open file handles are preserved. 
  3178.  
  3179. When an application starts, it inherits all open file handles from the process 
  3180. that starts it. If the system's command processor starts an application, file 
  3181. handles 0, 1, and 2 represent the standard input, standard output, and standard 
  3182. error files. The standard input file is the keyboard; the standard output and 
  3183. standard error files are the screen. An application can read from the standard 
  3184. input file and write to the standard output and standard error files 
  3185. immediately; it does not have to open the files first. 
  3186.  
  3187. An application can create a duplicate file handle for an open file by using 
  3188. DosDupHandle. A duplicate handle is identical to the original handle. 
  3189. Typically, duplicate handles are used to redirect the standard input and 
  3190. standard output files. For example, an application can open a disk file and 
  3191. duplicate the disk-file handle as handle 0. Thereafter, an application reading 
  3192. from the standard input file (handle 0) takes data from the disk file, not from 
  3193. the keyboard. 
  3194.  
  3195. When devices and pipes are accessed through the file system functions (using 
  3196. DosOpen, DosRead, and so on), the devices and pipes are treated as files and 
  3197. are identified using file handles. The standard file handles can be redirected 
  3198. to a device or pipe. 
  3199.  
  3200.  
  3201. ΓòÉΓòÉΓòÉ 6.3.3. File Pointer ΓòÉΓòÉΓòÉ
  3202.  
  3203. Every open file has a file pointer that specifies the next byte to be read or 
  3204. the location to receive the next byte that is written. When a file is first 
  3205. opened, the system places the file pointer at the beginning of the file. As 
  3206. each byte is read or written, the operating system advances the pointer. 
  3207.  
  3208. An application can also move the pointer by using DosSetFilePtr. When the 
  3209. pointer reaches the end of the file and the application attempts to read from 
  3210. the file, no bytes are read and no error occurs. Thus, reading 0 bytes without 
  3211. an error means the program has reached the end of the file. 
  3212.  
  3213. When an application writes to a disk file, the data being written is usually 
  3214. collected in an internal buffer. The operating system writes to the disk only 
  3215. when the amount of data equals (or is a multiple of) the sector size of the 
  3216. disk. If there is data in the internal buffer when the file is closed, the 
  3217. system automatically writes the data to the disk before closing the file. An 
  3218. application can also flush the buffer (that is, write the contents of the 
  3219. buffer to the disk) by using DosResetBuffer. 
  3220.  
  3221.  
  3222. ΓòÉΓòÉΓòÉ 6.3.4. Copying Files ΓòÉΓòÉΓòÉ
  3223.  
  3224. DosCopy is used to copy files and subdirectories. Metacharacters (global file 
  3225. name characters) are not allowed, so only individual files or entire 
  3226. subdirectories can be copied with this function. The source and target can be 
  3227. on different drives. 
  3228.  
  3229. When the source specified is a subdirectory and an I/O error occurs, the file 
  3230. being copied from the source directory to the target directory at the time of 
  3231. the error will be deleted from the target directory and DosCopy will be 
  3232. terminated. 
  3233.  
  3234. When a file is being copied and an I/O error occurs, 
  3235.  
  3236. o if the source file name is that of a file to be replaced, the file is deleted 
  3237.   from the target path, 
  3238.  
  3239. o if the source file name is that of a file to be appended, the target file is 
  3240.   resized to its original size, 
  3241.  
  3242. DosCopy will copy the attributes of the source file, such as date of creation, 
  3243. and time of creation to the target file. Additionally, DosCopy will copy the 
  3244. extended attributes of the source file when creating a new subdirectory or a 
  3245. new file, or when replacing an existing file. 
  3246.  
  3247.  
  3248. ΓòÉΓòÉΓòÉ 6.3.5. Moving Files ΓòÉΓòÉΓòÉ
  3249.  
  3250. DosMove is used to move a file from one subdirectory to another on the same 
  3251. drive. In the process of moving the file, its name can be changed. 
  3252. Metacharacters (global file name characters) are not permitted. 
  3253.  
  3254.  
  3255. ΓòÉΓòÉΓòÉ 6.3.6. Deleting Files ΓòÉΓòÉΓòÉ
  3256.  
  3257. Calling DosDelete  removes the directory entry associated with a file name. 
  3258. Metacharacters (global file name characters) are not permitted. 
  3259.  
  3260. Files whose read-only attribute is set cannot be deleted. 
  3261.  
  3262.  
  3263. ΓòÉΓòÉΓòÉ 6.3.7. Changing File Sizes ΓòÉΓòÉΓòÉ
  3264.  
  3265. DosSetFileSize  is used to extend or truncate the size of a file that is open 
  3266. for Read/Write or Write-Only access. 
  3267.  
  3268. When a file is extended, for example to reserve disk space, the value of the 
  3269. additional bytes allocated by the system is undefined. 
  3270.  
  3271.  
  3272. ΓòÉΓòÉΓòÉ 6.3.8. Locking and Unlocking File Regions ΓòÉΓòÉΓòÉ
  3273.  
  3274. Because the OS/2 operating system permits more than one application to open a 
  3275. file and write to it, it is important that the applications not write over each 
  3276. other's work. An application can protect against this problem by temporarily 
  3277. locking a region in a file. 
  3278.  
  3279. DosSetFileLocks  provides a simple mechanism that temporarily prevents access 
  3280. by other processes to regions within a file. DosSetFileLocks specifies a range 
  3281. of bytes in the file that is locked by an application and that can be accessed 
  3282. only by the application locking the region. The application uses the same 
  3283. function to free the locked region. 
  3284.  
  3285. Locking and unlocking regions in a file enables sharing processes to coordinate 
  3286. their efforts. A process can lock a region in a file so the process can read 
  3287. and update the file region. A sharing process that attempts to lock the region 
  3288. before the other process finishes its update and unlocks the region receives an 
  3289. error code. When a lock is unsuccessful because a lock is already in place, 
  3290. ERROR_LOCK_VIOLATION is returned. 
  3291.  
  3292. A lock that extends beyond end-of-file is not considered an error. However, a 
  3293. locked region cannot overlap another locked region, nor can it encompass a 
  3294. locked region. Any such conflicting locks must be cleared before a region can 
  3295. be locked. 
  3296.  
  3297. When a file handle is duplicated, the duplicate handle has access to any locked 
  3298. regions currently being accessed by the original handle. Although a child 
  3299. process created with DosExecPgm  can inherit the file handles of its parent 
  3300. process, it does not inherit access to locked regions in effect for a file 
  3301. handle unless the file handle is duplicated and passed to it. 
  3302.  
  3303. Note: 
  3304.  
  3305. File locks are intended to be in effect for only short periods of time. 
  3306.  
  3307. When a file with locks is closed, the locks are released in no defined order. 
  3308.  
  3309.  
  3310. ΓòÉΓòÉΓòÉ 6.3.9. Searching for Files ΓòÉΓòÉΓòÉ
  3311.  
  3312. An application can use DosFindFirst, DosFindNext, and DosFindClose to search 
  3313. the current directory for all file names that match a given pattern. 
  3314.  
  3315. The pattern must be an OS/2 file name and can include metacharacters (global 
  3316. file name characters). The wildcard characters are the question mark (?) and 
  3317. the asterisk (*). The question mark matches any single character; the asterisk 
  3318. matches any combination of characters. For example, the pattern "A*" matches 
  3319. the names "ABC", "A23", and "ABCD", but the pattern "A?C" matches only the name 
  3320. "ABC". 
  3321.  
  3322.  
  3323. ΓòÉΓòÉΓòÉ 6.3.10. Determining the Maximum Path Length ΓòÉΓòÉΓòÉ
  3324.  
  3325. An application that recognizes long file names might be run on systems with or 
  3326. without installable file systems. Additionally, the maximum length of a file 
  3327. name might vary from one installable file system to another. So that an 
  3328. application can properly handle this variable condition (and, for example, 
  3329. allocate large enough buffers to hold file names), the application should call 
  3330. DosQuerySysInfo to determine the maximum path length supported by the file 
  3331. system. 
  3332.  
  3333. Make this call before calling file system functions that require full path 
  3334. names. 
  3335.  
  3336.  
  3337. ΓòÉΓòÉΓòÉ 6.3.11. Devices ΓòÉΓòÉΓòÉ
  3338.  
  3339. The OS/2 operating system enables you to access peripheral devices using file 
  3340. system commands, and treat those devices as file streams of data. These devices 
  3341. include: 
  3342.  
  3343. Character devices        COM, clock, console (keyboard and screen), screen, 
  3344.                          keyboard, printer, null, pointer, and mouse devices. 
  3345.  
  3346. Standard I/O devices     Character devices automatically installed by the 
  3347.                          operating system and recognized by the file system as 
  3348.                          the standard input, standard output, and standard 
  3349.                          error devices. 
  3350.  
  3351. Pseudocharacter devices  An application can attach a device name to a file 
  3352.                          system and use the file system as a pseudocharacter 
  3353.                          device (also called a single-file device). Attaching a 
  3354.                          device name to a file system allows an application to 
  3355.                          open the device associated with the file system as if 
  3356.                          it were a character device (for example, a serial 
  3357.                          port) and read from and write to the device by using 
  3358.                          DosRead and DosWrite. 
  3359.  
  3360.                          In addition, an application can use DosSetFilePtr and 
  3361.                          DosSetFileLocks with a pseudocharacter device. Also, 
  3362.                          pseudocharacter devices can be redirected. 
  3363.  
  3364.                          A file system that can be attached to a 
  3365.                          pseudocharacter device is typically associated with a 
  3366.                          single disk file or with a special storage device, 
  3367.                          such as a tape drive. The file system establishes a 
  3368.                          connection with the device and transfers requests and 
  3369.                          data between the operating system and the device. The 
  3370.                          user perceives this file as a device name for a 
  3371.                          nonexistent device. 
  3372.  
  3373.                          This file is seen as a character device because the 
  3374.                          current drive and directory have no effect on the 
  3375.                          name. A pseudocharacter device name is an ASCII string 
  3376.                          with the name of an OS/2 file in the form: 
  3377.  
  3378.                                                       \dev\dev_name
  3379.                          The "\dev\" is a required part of the name, but there 
  3380.                          is no actual subdirectory named "\dev\". This just 
  3381.                          lets the operating system know that it is a 
  3382.                          pseudocharacter device name. 
  3383.  
  3384. Logical file devices.    The hard disk or floppy disk drives, or the partitions 
  3385.                          on the hard disk or floppy disk drives. 
  3386.  
  3387.  
  3388. ΓòÉΓòÉΓòÉ 6.4. Using File Commands ΓòÉΓòÉΓòÉ
  3389.  
  3390. Files are accessed through the file system using file handles. File handles are 
  3391. returned by DosOpen when the file is opened and are used for all subsequent 
  3392. accesses to the file. Files can be be created, opened, read from, written to, 
  3393. closed, copied, moved, deleted, renamed, and locked. Files can be searched for 
  3394. based on a metacharacter pattern template. 
  3395.  
  3396. Each open file has a file pointer that indicates the current reading or writing 
  3397. location within the file. The file pointer moves automatically with each read 
  3398. or write operation on the file and can be moved manually by the application. 
  3399.  
  3400. The standard file handles-standard input, standard output, and standard 
  3401. error-provide redirectable input and output to applications. The standard file 
  3402. handles can be used to read input from the keyboard and write output to the 
  3403. display. Alternatively, they can be redirected to read input from and write 
  3404. output to a file. To an application reading and writing the standard file 
  3405. handles, there is no difference between the two. 
  3406.  
  3407. Note:  In the example code fragments that follow, error checking was left out 
  3408.        to conserve space. Applications should always check the return code that 
  3409.        the functions return. Control Program functions return an APIRET value. 
  3410.        A return code of 0 indicates success. If a non-zero value is returned, 
  3411.        an error occurred. 
  3412.  
  3413.  
  3414. ΓòÉΓòÉΓòÉ 6.4.1. Creating Files ΓòÉΓòÉΓòÉ
  3415.  
  3416. DosOpen  is used to create files, which are then read from or written to. To 
  3417. create a file, specify FILE_CREATE as the sixth argument in the call to the 
  3418. function. DosOpen then creates the file, if it does not already exist. If the 
  3419. file already exists, the function returns the error value FILE_EXISTED. 
  3420.  
  3421. In the following code fragment, DosOpen creates the file NEWFILE.TXT: 
  3422.  
  3423.     #define INCL_DOSFILEMGR   /* File System values */
  3424.     #include <os2.h>
  3425.  
  3426.     HFILE   hf;
  3427.     ULONG   ulAction;
  3428.     APIRET  rc;
  3429.  
  3430.     rc = DosOpen("NEWFILE.TXT",       /* Name of file to create and open */
  3431.                  &hf,                 /* Address of file handle          */
  3432.                  &ulAction,           /* Action taken                    */
  3433.                  0,                   /* Size of new file                */
  3434.                  FILE_NORMAL,         /* File attributes                 */
  3435.                  FILE_CREATE,         /* Creates the file                */
  3436.                  OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE,
  3437.                  (PEAOP2) NULL);      /* No extended attributes          */
  3438.  
  3439.  
  3440. Creating a New File 
  3441.  
  3442. In this example, DosOpen creates the file and opens it for writing only. Note 
  3443. that the sharing method chosen permits other processes to open the file for any 
  3444. access. The new file is empty (contains no data). 
  3445.  
  3446. When you use DosOpen to create (or replace) a file, you must specify the 
  3447. attributes the new file is to have. In the preceding example, this value is 
  3448. FILE_NORMAL, so the file is created as a normal file. Other possible file 
  3449. attributes include read-only and hidden, which correspond to FILE_READONLY and 
  3450. FILE_HIDDEN, respectively. The possible file attributes are: 
  3451.  
  3452. File Attribute      Defined Constant 
  3453. Normal file         FILE_NORMAL 
  3454. Read-only file      FILE_READONLY 
  3455. Hidden file         FILE_HIDDEN 
  3456. System file         FILE_SYSTEM 
  3457. Subdirectory        FILE_DIRECTORY 
  3458. Archived file       FILE_ARCHIVED. 
  3459.  
  3460. The file attribute affects how other processes access the file. For example, if 
  3461. the file is read-only, no process can open the file for writing. There is one 
  3462. exception-the process that creates the read-only file can write to it 
  3463. immediately after creating it. After closing the file, however, the process 
  3464. cannot reopen it for writing. 
  3465.  
  3466. If you are creating a new file object (a new file or a replacement for an 
  3467. existing one), you must specify the size of the new file in bytes. For example, 
  3468. if you specify 256, the file size is 256 bytes. However, these 256 bytes are 
  3469. undefined. If the file being opened already exists, the file size parameter is 
  3470. ignored. It is up to the application to write valid data to the file. No matter 
  3471. what size you specify, the file pointer is set to point to the beginning of the 
  3472. file so a subsequent call to DosWrite starts writing data at the beginning of 
  3473. the file. 
  3474.  
  3475. Extended attributes can be defined by an application when a file object is 
  3476. created. An application can define an extended attribute for a file when the 
  3477. file is created during a DosOpen call. 
  3478.  
  3479. Applications can also control access to specific regions within a file by 
  3480. calling DosSetFileLocks. 
  3481.  
  3482.  
  3483. ΓòÉΓòÉΓòÉ 6.4.2. Opening Files ΓòÉΓòÉΓòÉ
  3484.  
  3485. Before performing input or output operations on a file, you must open the file 
  3486. and obtain a file handle. You obtain a file handle by using DosOpen. This 
  3487. function opens the specified file and returns a file handle for it. DosOpen 
  3488. can also be used to create new files. 
  3489.  
  3490. DosOpen  establishes a connection between a file object and an application. 
  3491. This connection is in the form of a 32-bit identifier called a file handle, 
  3492. which is used to refer to the file object and any information associated with 
  3493. it. DosOpen returns a handle that is used in other file system calls to gain 
  3494. access to the object. The file object can be a new file, an existing file, or a 
  3495. replacement for an existing file. It can also be a character device, a block 
  3496. device, or the client end of a named pipe. The type of object is determined by 
  3497. the file name you pass to DosOpen. 
  3498.  
  3499. Note:  If the object is a named pipe, it must be in a listening state for 
  3500.        DosOpen to be successful. For more information about opening a named 
  3501.        pipe, see Opening Named Pipes. 
  3502.  
  3503. In the following code fragment, DosOpen opens the existing file SAMPLE.TXT for 
  3504. reading and puts the file handle into the hf variable: 
  3505.  
  3506.     #define INCL_DOSFILEMGR   /* File System values */
  3507.     #include <os2.h>
  3508.  
  3509.     HFILE   hf;
  3510.     ULONG   ulAction;
  3511.     APIRET  rc;
  3512.  
  3513.     rc = DosOpen("SAMPLE.TXT",       /* Name of file to open      */
  3514.                  &hf,                /* Address of file handle    */
  3515.                  &ulAction,          /* Action taken              */
  3516.                  0,                  /* Size of file              */
  3517.                  FILE_NORMAL,        /* File attribute            */
  3518.                  FILE_OPEN,          /* Open the file             */
  3519.                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  3520.                  (PEAOP2) NULL);     /* Extended attribute buffer */
  3521.  
  3522.  
  3523. Opening a File and Obtaining a File Handle 
  3524.  
  3525. If DosOpen successfully opens the file, it copies the file handle to the hf 
  3526. variable and copies a value to the ulAction variable indicating what action was 
  3527. taken (for example, FILE_EXISTED for "existing file opened"). A file size is 
  3528. not needed to open an existing file, so the fourth argument is 0. The fifth 
  3529. argument, FILE_NORMAL, specifies the normal file attribute. The sixth argument, 
  3530. FILE_OPEN, directs DosOpen to open the file if it exists or return an error if 
  3531. it does not exist. The seventh argument directs DosOpen to open the file for 
  3532. reading only and enables other applications to open the file even while the 
  3533. current application has it open. The final argument is a pointer to a structure 
  3534. containing information on extended attributes. If the file has no extended 
  3535. attributes, this argument must be NULL. 
  3536.  
  3537. DosOpen  returns 0 if it successfully opens the file. Applications use the file 
  3538. handle in subsequent functions to read data from the file or to check the 
  3539. status and other file characteristics. If DosOpen fails to open the file, it 
  3540. returns an error value. 
  3541.  
  3542. When you open a file you must specify whether you want to read from the file, 
  3543. write to it, or both read and write. Also, since more than one application 
  3544. might attempt to open the same file, you must also specify whether you want to 
  3545. allow other processes to have access to the file while you have it open. A file 
  3546. that is shared can be shared for reading only, writing only, or reading and 
  3547. writing. A file that is not shared cannot be opened by another application (or 
  3548. more than once by the first application) until it has been closed by the first 
  3549. application. 
  3550.  
  3551. An application defines its file access rights (that is, I/O it needs to perform 
  3552. on a file) by setting the appropriate file access mode field in the file 
  3553. open-mode parameter. An application accesses a file as: 
  3554.  
  3555. o Read-Only 
  3556. o Write-Only 
  3557. o Read/Write. 
  3558.  
  3559. An application defines what I/O operations other processes can perform on a 
  3560. file by setting the appropriate sharing mode field in the OpenMode parameter. 
  3561. Other processes are granted: 
  3562.  
  3563. o Deny Read/Write access 
  3564. o Deny Write access 
  3565. o Deny Read access 
  3566. o Deny Neither Read or Write access (Deny None). 
  3567.  
  3568. File sharing requires cooperation between the sharing processes. For example, 
  3569. if process A calls DosOpen  to open a file with Deny Write sharing and process 
  3570. B calls DosOpen  to open the same file with Read/Write access, the DosOpen call 
  3571. made by process B fails. 
  3572.  
  3573. You indicate whether or not you want to permit another application to access 
  3574. your file by combining an OPEN_ACCESS_ value and an OPEN_SHARE_ value from the 
  3575. following list: 
  3576.  
  3577. File Access and Sharing Rights 
  3578.  
  3579. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3580. ΓöéValue                         ΓöéMeaning                       Γöé
  3581. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3582. ΓöéOPEN_ACCESS_READONLY          ΓöéOpen a file for reading.      Γöé
  3583. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3584. ΓöéOPEN_ACCESS_WRITEONLY         ΓöéOpen a file for writing.      Γöé
  3585. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3586. ΓöéOPEN_ACCESS_READWRITE         ΓöéOpen a file for reading and   Γöé
  3587. Γöé                              Γöéwriting.                      Γöé
  3588. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3589. ΓöéOPEN_SHARE_DENYREADWRITE      ΓöéOpen a file for exclusive use,Γöé
  3590. Γöé                              Γöédenying other processes read  Γöé
  3591. Γöé                              Γöéand write access.             Γöé
  3592. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3593. ΓöéOPEN_SHARE_DENYWRITE          ΓöéDeny other processes write    Γöé
  3594. Γöé                              Γöéaccess to a file.             Γöé
  3595. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3596. ΓöéOPEN_SHARE_DENYREAD           ΓöéDeny other processes read     Γöé
  3597. Γöé                              Γöéaccess to a file.             Γöé
  3598. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3599. ΓöéOPEN_SHARE_DENYNONE           ΓöéOpen a file with no sharing   Γöé
  3600. Γöé                              Γöérestrictions, granting read   Γöé
  3601. Γöé                              Γöéand write access to all       Γöé
  3602. Γöé                              Γöéprocesses.                    Γöé
  3603. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3604.  
  3605. In general, you can combine any access method (read, write, or read and write) 
  3606. with any sharing method (deny reading, deny writing, deny reading and writing, 
  3607. or grant any access). Some combinations have to be handled carefully, however, 
  3608. such as opening a file for writing without denying other processes access to 
  3609. it. 
  3610.  
  3611. Note:  For named pipes, the access and sharing modes must be consistent with 
  3612.        those specified by DosCreateNPipe. 
  3613.  
  3614. Other characteristics of the file handle that can be set: 
  3615.  
  3616. File Handle Characteristics 
  3617.  
  3618. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3619. ΓöéFlag           ΓöéPurpose                       Γöé
  3620. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3621. ΓöéInheritance    ΓöéHandle is inherited by a childΓöé
  3622. Γöé               Γöéprocess created with          Γöé
  3623. Γöé               ΓöéDosExecPgm, or is private to  Γöé
  3624. Γöé               Γöéthe calling process.          Γöé
  3625. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3626. ΓöéWrite-Through  ΓöéActual I/O for synchronous    Γöé
  3627. Γöé               Γöéwrites is not guaranteed as   Γöé
  3628. Γöé               Γöécomplete or is guaranteed as  Γöé
  3629. Γöé               Γöécomplete before the write     Γöé
  3630. Γöé               Γöéreturns.                      Γöé
  3631. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3632. ΓöéFail-Errors    ΓöéMedia errors are reported by  Γöé
  3633. Γöé               Γöéthe system critical error     Γöé
  3634. Γöé               Γöéhandler, or by the            Γöé
  3635. Γöé               Γöéapplication.                  Γöé
  3636. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3637. ΓöéDASD           ΓöéThe file name parameter is theΓöé
  3638. Γöé               Γöéname of a file or device      Γöé
  3639. Γöé               Γöéopened in the normal way, or aΓöé
  3640. Γöé               Γöédrive specification for a     Γöé
  3641. Γöé               Γöéfixed disk or diskette drive. Γöé
  3642. Γöé               ΓöéThe DASD flag can be set for  Γöé
  3643. Γöé               Γöédirect access to an entire    Γöé
  3644. Γöé               Γöédisk or diskette volume,      Γöé
  3645. Γöé               Γöéindependent of the file       Γöé
  3646. Γöé               Γöésystem. When the DASD flag is Γöé
  3647. Γöé               Γöéset, the handle returned by   Γöé
  3648. Γöé               ΓöéDosOpen represents the logicalΓöé
  3649. Γöé               Γöévolume as a single file. To   Γöé
  3650. Γöé               Γöéblock other processes from    Γöé
  3651. Γöé               Γöéaccessing the logical volume, Γöé
  3652. Γöé               Γöéa DosDevIOCtl Category 8,     Γöé
  3653. Γöé               ΓöéFunction 0 call should be madeΓöé
  3654. Γöé               Γöéusing the handle returned by  Γöé
  3655. Γöé               ΓöéDosOpen. The DASD flag should Γöé
  3656. Γöé               Γöébe set only by systems        Γöé
  3657. Γöé               Γöéprograms, not by applications.Γöé
  3658. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3659. ΓöéCache          ΓöéThe file system caches or doesΓöé
  3660. Γöé               Γöénot cache data for I/O        Γöé
  3661. Γöé               Γöéoperations on the file. This  Γöé
  3662. Γöé               Γöéflag is advisory only.        Γöé
  3663. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3664.  
  3665. See the DosOpen material in the Control Program Programming Reference for 
  3666. details of these characteristics. 
  3667.  
  3668. After an object has been opened, its file handle state flags can be queried by 
  3669. calling DosQueryFHState and reset by calling DosSetFHState. See Determining and 
  3670. Setting the State of a File or Device Handle for information on determining the 
  3671. state of a file handle. 
  3672.  
  3673. When a child process inherits a file handle, it also inherits the sharing and 
  3674. access rights of the file. 
  3675.  
  3676. You cannot use metacharacters (global file name characters; * and ?) in file 
  3677. names you supply to DosOpen. 
  3678.  
  3679.  
  3680. ΓòÉΓòÉΓòÉ 6.4.3. Reading from Files ΓòÉΓòÉΓòÉ
  3681.  
  3682. Once you open a file or have a file handle, you can read from and write to the 
  3683. file by using DosRead and DosWrite. 
  3684.  
  3685. DosRead is called with a handle (obtained with DosOpen) for a file, pipe, or 
  3686. device. DosRead copies a specified number of bytes (up to the end of the file) 
  3687. from the file object to the buffer you specify. The operating system returns, 
  3688. in a parameter, the number of bytes actually read (which might not be the same 
  3689. as the number of bytes requested because the end of the file might have been 
  3690. reached). 
  3691.  
  3692. To read from a file, you must open it for reading or for reading and writing. 
  3693.  
  3694. The following code fragment shows how to open the file named SAMPLE.TXT and 
  3695. read the first 512 bytes from it: 
  3696.  
  3697.     #define INCL_DOSFILEMGR   /* File System values */
  3698.     #include <os2.h>
  3699.  
  3700.     #define BUF_SIZE 512
  3701.  
  3702.     HFILE   hf;
  3703.     ULONG   ulAction;
  3704.     BYTE    abBuffer[BUF_SIZE];
  3705.     ULONG   cbRead;
  3706.     APIRET  rc;
  3707.  
  3708.     rc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  3709.                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  3710.                  (PEAOP2) NULL);
  3711.  
  3712.     if (!rc) {
  3713.         DosRead(hf, abBuffer, sizeof(abBuffer), &cbRead);
  3714.         DosClose(hf);
  3715.     }
  3716.  
  3717.  
  3718. Opening and Reading a File 
  3719.  
  3720. If the file does not have 512 bytes, DosRead reads to the end of the file and 
  3721. puts the number of bytes read in the cbRead variable. If the file pointer is 
  3722. already positioned at the end of the file when DosRead is called, the function 
  3723. puts a 0 in the cbRead variable. 
  3724.  
  3725.  
  3726. ΓòÉΓòÉΓòÉ 6.4.4. Writing to Files ΓòÉΓòÉΓòÉ
  3727.  
  3728. Once you open a file or have a file handle, you can read from and write to the 
  3729. file by using DosRead and DosWrite. 
  3730.  
  3731. DosWrite copies bytes from a buffer you specify to a file, device, or pipe. 
  3732.  
  3733. Calling DosWrite with a handle for a file, pipe, or device transfers the number 
  3734. of bytes specified from a buffer location to the object. The system returns, in 
  3735. a parameter, the number of bytes actually written (which in the case of a disk 
  3736. file might not be the same as the number requested because of insufficient disk 
  3737. space). 
  3738.  
  3739. To write to a file, you must first open it for writing or for reading and 
  3740. writing. 
  3741.  
  3742. The following code fragment shows how to open the file SAMPLE.TXT again and 
  3743. write 512 bytes to it: 
  3744.  
  3745.     #define INCL_DOSFILEMGR   /* File System values */
  3746.     #include <os2.h>
  3747.  
  3748.     #define BUF_SIZE 512
  3749.  
  3750.     HFILE   hf;
  3751.     ULONG   ulAction;
  3752.     BYTE    abBuffer[BUF_SIZE];
  3753.     ULONG   cbWritten;
  3754.     APIRET  rc;
  3755.  
  3756.     rc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_CREATE,
  3757.                  OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
  3758.                  (PEAOP2) NULL);
  3759.  
  3760.     if (!rc) {
  3761.         DosWrite(hf, abBuffer, sizeof(abBuffer), &cbWritten);
  3762.         DosClose(hf);
  3763.     }
  3764.  
  3765.  
  3766. Opening and Writing to a File 
  3767.  
  3768. DosWrite writes the contents of the buffer to the file. If it fails to write 
  3769. 512 bytes (for example, if the disk is full), the function puts the number of 
  3770. bytes written in the cbWritten variable. The data is read and written exactly 
  3771. as given; the function does not format the data-that is, they do not convert 
  3772. binary data to decimal strings, or vice versa. 
  3773.  
  3774. The Write-Through Flag 
  3775. If an application requires data to be written in a specific order, setting the 
  3776. Write-Through flag to 1 guarantees that actual I/O for a synchronous write is 
  3777. completed before the DosWrite  returns. If this flag has been set with DosOpen 
  3778. for buffered I/O, and multiple synchronous writes are performed, the system 
  3779. cannot guarantee the actual order in which the data is written. For details on 
  3780. changing the state of the Write-Through flag, see Determining and Setting the 
  3781. State of a File or Device Handle. 
  3782.  
  3783.  
  3784. ΓòÉΓòÉΓòÉ 6.4.5. Moving the File Pointer ΓòÉΓòÉΓòÉ
  3785.  
  3786. Every disk file has a corresponding file pointer that marks the current 
  3787. location in the file. The current location is the byte in the file that will be 
  3788. read from or written to on the next call to DosRead  or DosWrite . Usually, the 
  3789. file pointer is at the beginning of the file when you first open or create the 
  3790. file, and it advances as you read or write to the file. You can, however, 
  3791. change the position of the file pointer at any time by using DosSetFilePtr . 
  3792.  
  3793. DosSetFilePtr  moves the file pointer a specified offset from a given position. 
  3794. You can move the pointer from the beginning of the file, from the end, or from 
  3795. the current position. 
  3796.  
  3797. The following code fragment shows how to move the pointer 200 bytes from the 
  3798. end of the file: 
  3799.  
  3800.     #define INCL_DOSFILEMGR   /* File System values */
  3801.     #include <os2.h>
  3802.  
  3803.     #define HF_STDOUT 1       /* Standard output handle */
  3804.     #define BUF_SIZE 255
  3805.  
  3806.     BYTE abBuf[BUF_SIZE];
  3807.     HFILE hf;
  3808.     ULONG cbRead, cbWritten, ulAction, ulNewPtr;
  3809.  
  3810.     DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  3811.             OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  3812.             (PEAOP2) NULL);
  3813.  
  3814.     DosSetFilePtr(hf, -200, FILE_END, &ulNewPtr);
  3815.  
  3816.     DosRead(hf, &abBuf, sizeof(abBuf), &cbRead);
  3817.  
  3818.     DosWrite(HF_STDOUT, abBuf, cbRead, &cbWritten);
  3819.  
  3820.  
  3821. Moving the File Pointer 
  3822.  
  3823. In this example, DosSetFilePtr  moves the file pointer to the 200th byte from 
  3824. the end of the file. If the file is not that long, the function moves the 
  3825. pointer to the first byte in the file and returns the actual position (relative 
  3826. to the end of the file) in the ulNewPtr variable. 
  3827.  
  3828. You can move the file pointer for disk files only. You cannot use DosSetFilePtr 
  3829. on devices, despite using other file functions (DosOpen, DosRead) to access a 
  3830. device. 
  3831.  
  3832. If a file is read-only, write operations to the file will not be performed. 
  3833.  
  3834. Moving the pointer from the end of the file can be used to determine the size 
  3835. of the file. 
  3836.  
  3837.  
  3838. ΓòÉΓòÉΓòÉ 6.4.6. Closing Files ΓòÉΓòÉΓòÉ
  3839.  
  3840. You can close a file by using DosClose. Since each application has a limited 
  3841. number of file handles that can be open at one time, it is a good practice to 
  3842. close a file after using it. 
  3843.  
  3844. To do so, supply the file handle in DosClose, as shown in the following code 
  3845. fragment: 
  3846.  
  3847.     #define INCL_DOSFILEMGR   /* File System values */
  3848.     #include <os2.h>
  3849.  
  3850.     #define BUF_SIZE 80
  3851.  
  3852.     HFILE   hf;
  3853.     ULONG   ulAction;
  3854.     BYTE    abBuffer[BUF_SIZE];
  3855.     ULONG   cbRead;
  3856.     APIRET  rc;
  3857.  
  3858.     rc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL,
  3859.                  FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  3860.                  (PEAOP2) NULL);
  3861.  
  3862.     if (!rc) {
  3863.         DosRead(hf, abBuffer, sizeof(abBuffer), &cbRead);
  3864.         DosClose(hf);
  3865.     }
  3866.  
  3867.  
  3868. Closing a File 
  3869.  
  3870. If you open a file for writing, DosClose directs the system to flush the file 
  3871. buffer-that is, to write any existing data in the operating system's 
  3872. intermediate file buffer to the disk or device. The system keeps these 
  3873. intermediate file buffers to make file input and output more efficient. For 
  3874. example, it saves data from previous calls to DosWrite until a certain number 
  3875. of bytes are in the buffer then writes the contents of the buffer to the disk. 
  3876.  
  3877. DosClose  also closes the handle to the file (or pipe, or device). If one or 
  3878. more additional handles to a file have been created with DosDupHandle , the 
  3879. internal buffers for the file are not written to disk, and its directory entry 
  3880. is not updated, until DosClose has been called for all the handles. 
  3881.  
  3882. For information on the effects of DosClose called with a named pipe handle, see 
  3883. Named Pipes. 
  3884.  
  3885.  
  3886. ΓòÉΓòÉΓòÉ 6.4.7. Creating Duplicate File or Device Handles ΓòÉΓòÉΓòÉ
  3887.  
  3888. DosDupHandle enables a process to create a duplicate handle for an open file, 
  3889. pipe, or device. 
  3890.  
  3891. The value for the old-file-handle parameter is the handle of an open file, a 
  3892. pipe, or a device. The valid values for the new-file-handle parameter include 
  3893. FFFFH, 0000H (standard input), 0001H (standard output), and 0002H (standard 
  3894. error). Any value other than FFFFH is assumed to be the value of the new file 
  3895. handle. 
  3896.  
  3897. A value of FFFFH causes the system to allocate a new file handle and send it to 
  3898. this location. If the value specified for the new-file-handle parameter is that 
  3899. of a currently open file, the file handle is closed before it is redefined. 
  3900.  
  3901. An agreed upon value for a duplicate file handle can be established between a 
  3902. parent process and a child process. Avoid choosing arbitrary values for the new 
  3903. file handle. 
  3904.  
  3905. The duplicate handle acquires the characteristics of the original. If you move 
  3906. the read/write pointer of the original file handle, for example by calling 
  3907. DosRead , DosWrite , or DosSetFilePtr , the pointer of the duplicate handle is 
  3908. also moved. If the original handle has access to regions in a file that have 
  3909. been locked by DosSetFileLocks , the duplicate also has access. 
  3910.  
  3911. If inheritance was indicated when a file was opened with DosOpen , a parent 
  3912. process can create a duplicate handle for the file and pass it to a child 
  3913. process by means of shared memory. This permits the child to close the 
  3914. duplicate handle without affecting the file handle of the parent. 
  3915.  
  3916. Because a parent process controls the meanings for standard I/O done by any 
  3917. child process it creates, the parent can use DosDupHandle to redefine unnamed 
  3918. pipe handles as standard I/O handles to communicate with a child. The steps 
  3919. involved are: 
  3920.  
  3921. o The parent process creates two pipes and duplicates the read handle of one 
  3922.   pipe as 0000 and the write handle of the other pipe as 0001. 
  3923.  
  3924. o When the child process performs standard I/O, instead of reading from the 
  3925.   keyboard and writing to the display, it reads from and writes to the pipes 
  3926.   created by its parent. 
  3927.  
  3928. o As the owner of the pipe, the parent process uses its read and write handles 
  3929.   to write to the pipe defined to the child as standard input and read from the 
  3930.   pipe defined to the child as standard output. 
  3931.  
  3932.  
  3933. ΓòÉΓòÉΓòÉ 6.4.8. Determining and Setting the State of a File or Device Handle ΓòÉΓòÉΓòÉ
  3934.  
  3935. After a file has been opened, the file handle state flags set with a DosOpen 
  3936. can be queried and reset by calling DosQueryFHState  and DosSetFHState . The 
  3937. handle returned by DosSetFHState  is used for subsequent input and output to 
  3938. the file. 
  3939.  
  3940. The following code fragment calls DosSetFHState to set the File Write-Through 
  3941. flag for an opened file. Writes to the file may go through the file system 
  3942. buffer, but the sectors are to be written before any synchronous write call 
  3943. returns. DosQueryFHState is called first to obtain the file handle state bits. 
  3944. Assume that the appropriate file handle has been placed into FileHandle 
  3945. already. 
  3946.  
  3947.     #define INCL_DOSFILEMGR   /* File System values */
  3948.     #include <os2.h>
  3949.     #include <stdio.h>
  3950.  
  3951.     HFILE   FileHandle;         /* File handle       */
  3952.     ULONG   FileHandleState;    /* File handle state */
  3953.     APIRET  rc;                 /* Return code       */
  3954.  
  3955.     rc = DosQueryFHState(FileHandle, &FileHandleState);
  3956.  
  3957.     if (rc != 0) {
  3958.         printf("DosQueryFHState error: return code = %ld", rc);
  3959.         return;
  3960.     }
  3961.  
  3962.     FileHandleState |= OPEN_FLAGS_WRITE_THROUGH;
  3963.  
  3964.     rc = DosSetFHState(FileHandle, FileHandleState);
  3965.  
  3966.     if (rc != 0) {
  3967.         printf("DosSetFHState error: return code = %ld", rc);
  3968.         return;
  3969.     }
  3970.  
  3971.  
  3972. Setting the State of a File Handle 
  3973.  
  3974. Here are two scenarios involving the use of this function. 
  3975.  
  3976. o An application requires that data be written in a specific order. To 
  3977.   guarantee the order of the data written, it must perform separate synchronous 
  3978.   write operations. The application can call DosSetFHState  to set the 
  3979.   Write-Through flag for the file. This action does not affect any previous 
  3980.   asynchronous writes, whose data can remain in the buffers. 
  3981.  
  3982. o An application cannot handle a certain critical error situation. 
  3983.   DosSetFHState  can be called to reset critical error handling as the 
  3984.   operating system's responsibility. The I/O function that caused the critical 
  3985.   error must be called again so the error can recur, causing control to be 
  3986.   passed to the operating system. In the case where asynchronous I/O is being 
  3987.   done, the precise time the results of this function will be available to the 
  3988.   application is unpredictable. 
  3989.  
  3990.  
  3991. ΓòÉΓòÉΓòÉ 6.4.9. Determining the Handle Type ΓòÉΓòÉΓòÉ
  3992.  
  3993. DosQueryHType enables an application to determine whether a handle is to a 
  3994. file, a pipe, or a device. This function can be used when a file-oriented 
  3995. application needs to modify its behavior, depending on the source of its input. 
  3996. For example, CMD.EXE suppresses writing prompts when its input is from a disk 
  3997. file. 
  3998.  
  3999. The following code fragment determines whether a given file handle refers to a 
  4000. file or a device. Assume that the desired file handle has been placed into 
  4001. FileHandle already. 
  4002.  
  4003.     #define INCL_DOSFILEMGR   /* File System values */
  4004.     #include <os2.h>
  4005.     #include <stdio.h>
  4006.  
  4007.     HFILE   FileHandle;    /* File handle                        */
  4008.     ULONG   HandType;      /* Handle type (returned)             */
  4009.     ULONG   FlagWord;      /* Device driver attribute (returned) */
  4010.     APIRET  rc;            /* Return code                        */
  4011.  
  4012.     rc = DosQueryHType(FileHandle, &HandType, &FlagWord);
  4013.  
  4014.     if (rc != 0) {
  4015.         printf("DosQueryHType error: return code = %ld", rc);
  4016.         return;
  4017.     }
  4018.  
  4019.  
  4020. Determining the Handle Type 
  4021.  
  4022. In the preceding example, DosQueryHType  returns a value that characterizes the 
  4023. type of file handle, and the associated device driver attribute word if handle 
  4024. type indicates that the file handle is associated with a local character device 
  4025.  
  4026.  
  4027. ΓòÉΓòÉΓòÉ 6.4.10. Searching for Files ΓòÉΓòÉΓòÉ
  4028.  
  4029. You can locate files with names that match a given pattern by using 
  4030. metacharacters in DosFindFirst  and DosFindNext . 
  4031.  
  4032. DosFindFirst  searches the current directory and locates the first file name 
  4033. that matches the given pattern. DosFindNext  locates the next matching file 
  4034. name and continues to find additional matches on each subsequent call until all 
  4035. matching names are found. The functions copy the file statistics on each file 
  4036. located to a data structure that you supply. The file information returned by a 
  4037. search includes file dates and times, length of data in the file, file size, 
  4038. file attributes, and file name. 
  4039.  
  4040. To find all files that match the file specification, call DosFindNext 
  4041. repeatedly until the message ERROR_NO_MORE_FILES is returned. Then call 
  4042. DosFindClose  to close the directory handle. 
  4043.  
  4044. The following code fragment shows how to find all file names that have the 
  4045. extension ".C": 
  4046.  
  4047.     #define INCL_DOSFILEMGR   /* File System values */
  4048.     #include <os2.h>
  4049.  
  4050.     HDIR         hdir;
  4051.     ULONG        cFilenames;
  4052.     FILEFINDBUF  findbuf;
  4053.     APIRET       rc;
  4054.  
  4055.     cFilenames = 1;
  4056.     hdir = HDIR_SYSTEM;
  4057.  
  4058.     rc = DosFindFirst("*.C",
  4059.                       &hdir,           /* Directory handle                     */
  4060.                       FILE_NORMAL,     /* File attribute to look for           */
  4061.                       &findbuf,        /* Result buffer                        */
  4062.                       sizeof(findbuf), /* Size of result buffer                */
  4063.                       &cFilenames,     /* Number of matching names to look for */
  4064.                       FIL_STANDARD);   /* Standard level of information        */
  4065.  
  4066.     if (!rc) {
  4067.         do {
  4068.             .
  4069.             .     /* Use file name in findbuf.achName */
  4070.             .
  4071.             rc = DosFindNext(hdir, &findbuf, sizeof(findbuf), &cFilenames);
  4072.  
  4073.         } while (!rc);
  4074.     }
  4075.     DosFindClose(hdir);
  4076.  
  4077.  
  4078. Finding All *.C Files 
  4079.  
  4080. In this example, DosFindNext continues to retrieve matching file names until it 
  4081. returns an error value (it returns ERROR_NO_MORE_FILES when it cannot find any 
  4082. more matching files). 
  4083.  
  4084. To keep track of which files have already been found, both functions use the 
  4085. directory handle, hdir. 
  4086.  
  4087. This directory handle must be set to HDIR_SYSTEM or HDIR_CREATE before the call 
  4088. to DosFindFirst. HDIR_SYSTEM (00000001H) tells the operating system to use the 
  4089. system handle for standard output, which is always available to the requesting 
  4090. process. HDIR_CREATE (FFFFFFFFH) tells the operating system to allocate a new, 
  4091. unused handle. 
  4092.  
  4093. The directory handle returned by DosFindFirst  must be used in subsequent calls 
  4094. to DosFindNext ; it identifies for DosFindNext the name of the file being 
  4095. sought and the current position in the directory. 
  4096.  
  4097. An attribute parameter for DosFindFirst allows hidden and system files, as well 
  4098. as normal files, to be included in searches. 
  4099.  
  4100. After locating the files you need, use DosFindClose to close the directory 
  4101. handle. This ensures that when you search for the same files again, you will 
  4102. start at the beginning of the directory. After DosFindClose is called, a 
  4103. subsequent DosFindNext fails. 
  4104.  
  4105.  
  4106. ΓòÉΓòÉΓòÉ 6.4.11. Searching Paths for Files ΓòÉΓòÉΓòÉ
  4107.  
  4108. DosSearchPath  searches directory paths for the name of a file object. The file 
  4109. specification can include metacharacters (global file name characters). 
  4110.  
  4111. The path string used in the search consists of directory paths separated by 
  4112. semicolons. The caller can supply the path string, or it can supply the name of 
  4113. an environment variable whose value is the path string to be searched. The 
  4114. caller can request that the current working directory be searched before the 
  4115. path string is searched. 
  4116.  
  4117. If the caller specifies an environment variable, DosSearchPath uses DosScanEnv 
  4118. to find the path string. DosScanEnv  searches the environment segment for an 
  4119. environment variable name; for example, DPATH. The result pointer points to the 
  4120. string that is the value of the environment variable. The call to DosScanEnv 
  4121. can be made directly by the application, or it can be invoked by DosSearchPath 
  4122.  
  4123. If the file is found, its full path name is returned, with metacharacters left 
  4124. in place. The results might not be meaningful if a buffer overflow occurs. 
  4125.  
  4126. As an example, assume that a string such as the following exists in the 
  4127. environment: 
  4128.  
  4129.     DPATH=C:\SYSDIR;C:\INIT
  4130. Two methods for searching directory paths to find a file are illustrated below. 
  4131.  
  4132.     #define INCL_DOSFILEMGR   /* File System values */
  4133.     #include <os2.h>
  4134.  
  4135.     #define ResultBufLen 255
  4136.     .
  4137.     .
  4138.     .
  4139.     char  PathRef[255];
  4140.     char  ResultBuffer[ResultBufLen];
  4141.  
  4142.     DosScanEnv("DPATH", &PathRef);
  4143.     DosSearchPath(0,                           /* Path Source Bit = 0 */
  4144.                   PathRef, "MYPROG.INI",
  4145.                   &ResultBuffer, ResultBufLen);
  4146.     DosOpen(ResultBuffer, ... );
  4147.  
  4148.  
  4149. Method 1:  Searching Directory Paths Using DosScanEnv and DosSearchPath 
  4150.  
  4151.     #define INCL_DOSFILEMGR   /* File System values */
  4152.     #include <os2.h>
  4153.  
  4154.     #define ResultBufLen 255
  4155.     .
  4156.     .
  4157.     .
  4158.     char  ResultBuffer[ResultBufLen];
  4159.  
  4160.     DosSearchPath(1,                           /* Path Source Bit = 1 */
  4161.                   "DPATH", "MYPROG.INI",
  4162.                   &ResultBuffer, ResultBufLen);
  4163.     DosOpen(ResultBuffer, ... );
  4164.  
  4165.  
  4166. Method 2:  Searching Directory Paths Using DosSearchPath 
  4167.  
  4168.  
  4169. ΓòÉΓòÉΓòÉ 6.5. Standard File Handles ΓòÉΓòÉΓòÉ
  4170.  
  4171. Every application, when it first starts, has three input and output file 
  4172. handles available to use. These file handles, called the standard input, 
  4173. standard output, and standard error files, enable the application to read input 
  4174. from the keyboard and display output on the screen without opening or preparing 
  4175. the keyboard or screen. 
  4176.  
  4177.  
  4178. ΓòÉΓòÉΓòÉ 6.5.1. Standard Input, Output, and Error File Handles ΓòÉΓòÉΓòÉ
  4179.  
  4180. As the operating system starts an application, it automatically opens the three 
  4181. standard files and makes the file handles-numbered 0, 1, and 2-available to the 
  4182. application. Applications can read from and write to the standard files as soon 
  4183. as they start. 
  4184.  
  4185. Standard Input 
  4186. File handle 0 is the standard input file. This handle can be used to read 
  4187. characters from the keyboard with DosRead. The function reads the specified 
  4188. number of characters unless the user types a turnaround character-that is, a 
  4189. character that marks the end of a line (the default turnaround character is a 
  4190. carriage-return/linefeed character pair). 
  4191.  
  4192. As DosRead reads the characters, it copies them to the buffer you have 
  4193. supplied, as shown in the following code fragment: 
  4194.  
  4195.     #define INCL_DOSFILEMGR   /* File System values */
  4196.     #include <os2.h>
  4197.  
  4198.     #define HF_STDIN 0        /* Standard input handle */
  4199.     #define BUF_SIZE 80
  4200.  
  4201.     BYTE abBuffer[BUF_SIZE];
  4202.     ULONG cbRead;
  4203.  
  4204.     DosRead(HF_STDIN, abBuffer, sizeof(abBuffer), &cbRead);
  4205.  
  4206.  
  4207. Reading from Standard Input 
  4208.  
  4209. In this example, DosRead  copies to the cbRead variable the number of 
  4210. characters read from standard input. The function also copies the turnaround 
  4211. character, or characters, to the buffer. If the function reads fewer than 80 
  4212. characters, the turnaround character is the last one in the buffer. 
  4213.  
  4214. Standard Output 
  4215. File handle 1 is the standard output file. This handle can be used to write 
  4216. characters on the screen with DosWrite . The function writes the characters in 
  4217. the given buffer to the current line. If you want to start a new line, you must 
  4218. place the current turnaround character in the buffer. 
  4219.  
  4220. The following code fragment displays a prompt, reads a string, and displays the 
  4221. string: 
  4222.  
  4223.     #define INCL_DOSFILEMGR   /* File System values */
  4224.     #include <os2.h>
  4225.  
  4226.     #define HF_STDIN  0       /* Standard input handle  */
  4227.     #define HF_STDOUT 1       /* Standard output handle */
  4228.     #define BUF_SIZE 80
  4229.  
  4230.     ULONG cbWritten, cbRead;
  4231.     BYTE abBuffer[BUF_SIZE];
  4232.     static UCHAR szEnterName[] = "Enter a name: ";
  4233.  
  4234.     DosWrite(HF_STDOUT, szEnterName, sizeof(szEnterName), &cbWritten);
  4235.  
  4236.     DosRead(HF_STDIN, abBuffer, sizeof(abBuffer), &cbRead);
  4237.  
  4238.     DosWrite(HF_STDOUT, abBuffer, cbRead, &cbWritten);
  4239.  
  4240.  
  4241. Writing to Standard Output 
  4242.  
  4243. Standard Error 
  4244. File handle 2 is the standard error file. This handle, like the standard output 
  4245. handle, enables applications to write characters on the screen. Most 
  4246. applications use the standard error file to display error messages, enabling 
  4247. the application to redirect standard output to a file without also redirecting 
  4248. error messages to the file. 
  4249.  
  4250.  
  4251. ΓòÉΓòÉΓòÉ 6.5.2. Redirecting Standard File Handles ΓòÉΓòÉΓòÉ
  4252.  
  4253. The standard input, standard output, and standard error files are usually the 
  4254. keyboard and screen, but not always. For example, if you redirect standard 
  4255. output by using the greater-than (>) redirection symbol on the application's 
  4256. command line, all data written to the standard output file goes to the given 
  4257. file. 
  4258.  
  4259. The following command line redirects standard output to the file SAMPLE.TXT and 
  4260. redirects error messages to the file SAMPLE.ERR: 
  4261.  
  4262.     type startup.cmd >sample.txt 2>sample.err
  4263. When a standard file is redirected, its handle is still available but 
  4264. corresponds to the given disk file instead of to the keyboard or screen. You 
  4265. can still use DosRead  and DosWrite  to read from and write to the files. 
  4266.  
  4267. You can use DosDupHandle to redirect a standard file from inside your 
  4268. application. If you duplicate the standard input file handle, your application 
  4269. reads from the specified file rather than from the keyboard. Duplicating the 
  4270. standard output file handle causes output to be directed to a file or device 
  4271. instead of to the standard output device. 
  4272.  
  4273. The following code fragment shows how to use the standard input handle to read 
  4274. from a file: 
  4275.  
  4276.     #define INCL_DOSFILEMGR   /* File System values */
  4277.     #include <os2.h>
  4278.  
  4279.     #define HF_STDIN  0       /* Standard input handle  */
  4280.     #define HF_STDOUT 1       /* Standard output handle */
  4281.     #define BUF_SIZE 80
  4282.  
  4283.     BYTE    abBuffer[BUF_SIZE];
  4284.     HFILE   hf, hfNew;
  4285.     ULONG   cbRead, cbWritten, ulAction;
  4286.     APIRET  rc;
  4287.  
  4288.     rc = DosOpen("SAMPLE.C", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  4289.                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL);
  4290.  
  4291.     if (!rc) {
  4292.         hfNew = 0;      /* Duplicates standard input */
  4293.         DosDupHandle(hf, &hfNew);
  4294.         DosRead(HF_STDIN, abBuffer, sizeof(abBuffer), &cbRead);
  4295.         DosWrite(HF_STDOUT, abBuffer, cbRead, &cbWritten);
  4296.     }
  4297.  
  4298.  
  4299. Duplicating the Standard Input Handle 
  4300.  
  4301.  
  4302. ΓòÉΓòÉΓòÉ 6.6. Summary of Functions and Data Structures Used in File Object Management ΓòÉΓòÉΓòÉ
  4303.  
  4304. Following are the OS/2 functions and data structures used in file object 
  4305. management. 
  4306.  
  4307. File Management Functions 
  4308.  
  4309. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  4310. ΓöéFile Functions          Γöé                                    Γöé
  4311. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4312. ΓöéDosClose                ΓöéCloses a file handle.               Γöé
  4313. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4314. ΓöéDosCopy                 ΓöéCopies a file or subdirectory.      Γöé
  4315. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4316. ΓöéDosDelete               ΓöéDeletes a file.                     Γöé
  4317. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4318. ΓöéDosEditName             ΓöéTransforms a file name.             Γöé
  4319. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4320. ΓöéDosMove                 ΓöéMoves a file or subdirectory.       Γöé
  4321. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4322. ΓöéDosOpen                 ΓöéGets a handle to a file, pipe, or   Γöé
  4323. Γöé                        Γöédevice.                             Γöé
  4324. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4325. ΓöéDosRead                 ΓöéReads from a file, pipe, or device. Γöé
  4326. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4327. ΓöéDosSetFileInfo          ΓöéSets information for an open file.  Γöé
  4328. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4329. ΓöéDosSetFileLocks         ΓöéLocks an unlocks a range in a file. Γöé
  4330. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4331. ΓöéDosSetFilePtr           ΓöéMoves the position of the file      Γöé
  4332. Γöé                        Γöépointer.                            Γöé
  4333. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4334. ΓöéDosSetFileSize          ΓöéChanges the size of a file.         Γöé
  4335. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4336. ΓöéDosSetPathInfo          ΓöéSets information for a file or      Γöé
  4337. Γöé                        Γöésubdirectory.                       Γöé
  4338. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4339. ΓöéDosSetVerify            ΓöéEnables write verification.         Γöé
  4340. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4341. ΓöéDosWrite                ΓöéWrites data to a file, pipe, or     Γöé
  4342. Γöé                        Γöédevice.                             Γöé
  4343. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4344. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4345. ΓöéFile Handle Functions   Γöé                                    Γöé
  4346. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4347. ΓöéDosDupHandle            ΓöéDuplicates a file handle.           Γöé
  4348. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4349. ΓöéDosQueryFHState         ΓöéGets the file handle state.         Γöé
  4350. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4351. ΓöéDosQueryHType           ΓöéGets the handle type.               Γöé
  4352. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4353. ΓöéDosSetFHState           ΓöéSets the file handle state.         Γöé
  4354. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4355. ΓöéDosSetMaxFH             ΓöéSets the maximum number of file     Γöé
  4356. Γöé                        Γöéhandles.                            Γöé
  4357. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4358. ΓöéFile Query Functions    Γöé                                    Γöé
  4359. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4360. ΓöéDosEnumAttribute        ΓöéGets the name and size of a file    Γöé
  4361. Γöé                        Γöéobject's extended attributes.       Γöé
  4362. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4363. ΓöéDosQueryFileInfo        ΓöéGets information for an open file.  Γöé
  4364. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4365. ΓöéDosQueryPathInfo        ΓöéGets information for a file or      Γöé
  4366. Γöé                        Γöésubdirectory.                       Γöé
  4367. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4368. ΓöéDosQuerySysInfo         ΓöéGets values of system variables.    Γöé
  4369. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4370. ΓöéDosQueryVerify          ΓöéDetermines whether or not write     Γöé
  4371. Γöé                        Γöéverification is enabled.            Γöé
  4372. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4373. ΓöéDirectory Search        Γöé                                    Γöé
  4374. Γöé(FileFind) Functions    Γöé                                    Γöé
  4375. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4376. ΓöéDosFindClose            ΓöéEnds a search for matching file     Γöé
  4377. Γöé                        Γöéobjects.                            Γöé
  4378. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4379. ΓöéDosFindFirst            ΓöéBegins a search for matching file   Γöé
  4380. Γöé                        Γöéobjects.                            Γöé
  4381. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4382. ΓöéDosFindNext             ΓöéContinues a search for matching fileΓöé
  4383. Γöé                        Γöéobjects.                            Γöé
  4384. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4385. ΓöéDirectory and Disk      Γöé                                    Γöé
  4386. ΓöéFunctions               Γöé                                    Γöé
  4387. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4388. ΓöéDosCreateDir            ΓöéCreates a subdirectory.             Γöé
  4389. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4390. ΓöéDosDeleteDir            ΓöéDeletes an empty subdirectory.      Γöé
  4391. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4392. ΓöéDosQueryCurrentDir      ΓöéGets the current directory.         Γöé
  4393. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4394. ΓöéDosQueryCurrentDisk     ΓöéGets the current drive.             Γöé
  4395. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4396. ΓöéDosSetCurrentDir        ΓöéSets the current directory.         Γöé
  4397. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4398. ΓöéDosSetDefaultDisk       ΓöéSets the default drive.             Γöé
  4399. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4400. ΓöéEnvironment and Search  Γöé                                    Γöé
  4401. ΓöéPath Functions          Γöé                                    Γöé
  4402. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4403. ΓöéDosScanEnv              ΓöéScans environment variable.         Γöé
  4404. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4405. ΓöéDosQueryPathInfo        ΓöéGets information for a file or      Γöé
  4406. Γöé                        Γöésubdirectory.                       Γöé
  4407. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4408. ΓöéDosSearchPath           ΓöéSearches along a specified path.    Γöé
  4409. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4410. ΓöéDosSetPathInfo          ΓöéSets information for a file or      Γöé
  4411. Γöé                        Γöésubdirectory.                       Γöé
  4412. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  4413.  
  4414. File Management Data Structures 
  4415.  
  4416. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  4417. ΓöéData Structure          ΓöéDescription                         Γöé
  4418. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4419. ΓöéDENA1                   ΓöéLevel 1 info. returned from         Γöé
  4420. Γöé                        ΓöéDosEnumAttribute.                   Γöé
  4421. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4422. ΓöéFDATE                   ΓöéA sub-structure used in the         Γöé
  4423. Γöé                        ΓöéFILEFINDBUF and the FILESTATUS      Γöé
  4424. Γöé                        Γöéstructures. Used to contain         Γöé
  4425. Γöé                        Γöéinformation about various dates     Γöé
  4426. Γöé                        Γöéassociated with the file (creation, Γöé
  4427. Γöé                        Γöélast change, and so on).            Γöé
  4428. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4429. ΓöéFILEFINDBUF             ΓöéUsed by DosFindFirst and DosFindNextΓöé
  4430. Γöé                        Γöéto return information about files.  Γöé
  4431. Γöé                        ΓöéThere are also variations of the    Γöé
  4432. Γöé                        Γöédata structure called FILEFINDBUF2, Γöé
  4433. Γöé                        ΓöéFILEFINDBUF3, and FILEFINDBUF4.     Γöé
  4434. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4435. ΓöéFILELOCK                ΓöéUsed by DosSetFileLocks to indicate Γöé
  4436. Γöé                        Γöéthe range to lock within the file.  Γöé
  4437. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4438. ΓöéFILESTATUS              ΓöéUsed when querying and setting      Γöé
  4439. Γöé                        Γöéinformation about a file, such as   Γöé
  4440. Γöé                        Γöéthe file's dates, times, and size.  Γöé
  4441. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4442. ΓöéFTIME                   ΓöéA sub-structure of FILEFINDBUF and  Γöé
  4443. Γöé                        ΓöéFILESTATUS. Contains information    Γöé
  4444. Γöé                        Γöéabout the time the file was created,Γöé
  4445. Γöé                        Γöélast changed, and so on.            Γöé
  4446. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  4447. ΓöéVOLUMELABEL             ΓöéA sub-structure of the FSINFO data  Γöé
  4448. Γöé                        Γöéstructure. It contains the volume's Γöé
  4449. Γöé                        Γöélabel.                              Γöé
  4450. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  4451.  
  4452.  
  4453. ΓòÉΓòÉΓòÉ 7. File Names ΓòÉΓòÉΓòÉ
  4454.  
  4455. File names are the identifiers used by the file system to uniquely identify 
  4456. files on a disk. All file systems have specific rules for constructing names of 
  4457. file objects. Different file systems can have different rules for naming file 
  4458. objects. 
  4459.  
  4460. The OS/2 FAT file system supports the DOS naming conventions. The OS/2 High 
  4461. Performance File System (HPFS) supports a superset of the DOS naming 
  4462. conventions, allowing for long file names and characters illegal under DOS. 
  4463. Although different file systems can have different rules for naming file 
  4464. objects, all OS/2 file systems require that full path names consist of 
  4465. directory and file names separated by backslashes (\). 
  4466.  
  4467. The OS/2 operating system views path names as ASCII strings and does not 
  4468. restrict file systems to the DOS file name format. Compatibility with existing 
  4469. DOS applications requires that all installable file systems support a superset 
  4470. of the 8.3 file name format used in the FAT file system. 
  4471.  
  4472. The following topics are related to the information in this chapter: 
  4473.  
  4474. o File Systems 
  4475. o File Management 
  4476. o Extended Attributes 
  4477. o Device I/O 
  4478.  
  4479.  
  4480. ΓòÉΓòÉΓòÉ 7.1. File-Naming Conventions ΓòÉΓòÉΓòÉ
  4481.  
  4482. File name conventions are the rules used to form file names in a given file 
  4483. system. Although each installable file system (IFS) can have specific rules 
  4484. about how individual components in a directory or file name are formed, all 
  4485. file systems follow the same general conventions for combining components. For 
  4486. example, although the FAT file system requires that file and directory names 
  4487. have the 8.3 file name format, and HPFS supports names of up to 255 characters 
  4488. long, both file systems use the backslash (\) character to separate directory 
  4489. names and the file name when forming a path. 
  4490.  
  4491. When creating names for directories and files, or when processing names 
  4492. supplied by the user, an application must follow these general rules: 
  4493.  
  4494. o Process a path as a NULL-terminated string. An application can determine 
  4495.   maximum length for a path by using DosQuerySysInfo. 
  4496.  
  4497. o Use any character in the current code page for a name, but do not use a path 
  4498.   separator, a character in the range 0 through 31, or any character explicitly 
  4499.   prohibited by the file system. 
  4500.  
  4501.   The following characters are reserved by the operating system. Do not use 
  4502.   them in directory or file names. 
  4503.  
  4504.         <   >   :   "   /   \   |
  4505.  
  4506.   Although a name can contain characters in the extended character set (128 - 
  4507.   255), an application must be able to switch code pages if necessary to access 
  4508.   the corresponding file. 
  4509.  
  4510. o Compare names without regard to case. Names such as "ABC", "Abc", and "abc" 
  4511.   are considered to be the same. 
  4512.  
  4513. o Use the backslash (\) or the forward slash (/) to separate components in a 
  4514.   path. No other character is accepted as a path separator. 
  4515.  
  4516. o Use the dot (.) as a directory component in a path to represent the current 
  4517.   directory. 
  4518.  
  4519. o Use two dots (..) as a directory component in a path to represent the parent 
  4520.   of the current directory. 
  4521.  
  4522. o Use a period (.) to separate components in a directory name or file name. 
  4523.   Unless explicitly defined by a file system, no restrictions are placed on the 
  4524.   number of components in a name. 
  4525.  
  4526.  
  4527. ΓòÉΓòÉΓòÉ 7.1.1. File Names in the FAT File System ΓòÉΓòÉΓòÉ
  4528.  
  4529. Valid file names in the OS/2 FAT file system have the following form: 
  4530.  
  4531.     [drive:][directory\]filename[extension]
  4532. The drive parameter must name an existing drive and can be any letter from A 
  4533. through Z. The drive letter must be followed by a colon (:). 
  4534.  
  4535. The directory parameter specifies the directory that contains the file's 
  4536. directory entry. The directory name must be followed by a backslash (\) to 
  4537. separate it from the file name. If the specified directory is not the current 
  4538. directory, directory must include the names of all the directories in the path, 
  4539. separated by backslashes. The root directory is specified by using a backslash 
  4540. at the beginning of the name. 
  4541.  
  4542. For example, if the directory ABC is in the directory SAMPLE, and SAMPLE is in 
  4543. the root directory, the directory specification is: 
  4544.  
  4545.     \SAMPLE\ABC.
  4546.  
  4547. A directory name can also have an extension, which is any combination of up to 
  4548. three letters, digits, or special characters, preceded by a period (.). 
  4549.  
  4550. The filename and extension parameters specify the file. 
  4551.  
  4552. FAT File-Naming Rules 
  4553. For file objects managed by the FAT file system, the following rules apply: 
  4554.  
  4555. o File names are limited to 8 characters before and three characters after a 
  4556.   single dot. This is referred to as the 8.3 file name format. 
  4557.  
  4558.   The 8 characters before the dot are blank-filled. Embedded blanks are 
  4559.   significant, trailing blanks and blanks immediately preceding the dot are not 
  4560.   significant. Trailing blanks are truncated. 
  4561.  
  4562.   For example, "FILE.A" is really "FILE   .A  ". "FILE.A" and "FILE   .A  " are 
  4563.   treated as the same file by the operating system and refer to the same file. 
  4564.   Also, "FILE.TXT  " and "FILE.TXT" are treated as the same file. 
  4565.  
  4566.   Blanks elsewhere in the name are significant-"F I L E.TXT" is not the same as 
  4567.   "FILE.TXT". 
  4568.  
  4569. o Names are not case sensitive. This means that "FILE.TXT" and "file.txt" refer 
  4570.   to the same file. Lowercase and uppercase characters are folded together for 
  4571.   name comparison purposes. 
  4572.  
  4573. o Names returned by file system functions are in uppercase. This means that if 
  4574.   "file.txt" is created, DosFindFirst returns "FILE.TXT". 
  4575.  
  4576. o Directory and file names can be any combination of up to eight letters, 
  4577.   digits, or the following special characters: 
  4578.  
  4579.         $   %   '   -   _   @   {   }   ~   `  !   #   (   )
  4580.   File extensions can be any combination of up to three letters, digits, or 
  4581.   special characters, preceded by a period. 
  4582.  
  4583. o Invalid characters for directory names, file names, and volume labels are: 
  4584.  
  4585.    - the range 0 - 1Fh 
  4586.  
  4587.    - and the characters: 
  4588.  
  4589.               <   >   |   +   =   :   ;   ,   .   "   /   \   [   ]
  4590.  
  4591.  
  4592. ΓòÉΓòÉΓòÉ 7.1.2. File Names in the High Performance File System ΓòÉΓòÉΓòÉ
  4593.  
  4594. In HPFS, file names can be up to 255 characters long (one must be a terminating 
  4595. NULL, "\0"). Directory names can also be 255 characters long, but the length of 
  4596. the complete path, including drive, directories, and file name, cannot exceed 
  4597. 260 characters. 
  4598.  
  4599. Certain characters that are illegal in the FAT file system are legal in HPFS 
  4600. file names: 
  4601.  
  4602.     +   =   ;   ,   [   ]
  4603. Also, blank spaces can be used anywhere in an HPFS file name or directory name, 
  4604. but blank spaces and periods at the end of a file name are ignored. 
  4605. Additionally, the period (.) is a valid file name character and can be used as 
  4606. many times as desired. There is no requirement that HPFS file names have 
  4607. extensions; however, many applications still create and use them. 
  4608.  
  4609. An HPFS file name can be all uppercase, all lowercase, or mixed case. The case 
  4610. is preserved for directory listings but is ignored in file searches and all 
  4611. other system operations. Therefore, in a given directory, there cannot be more 
  4612. than one file with the same name when the only difference is case. 
  4613.  
  4614. File-Naming Rules for Installable File Systems 
  4615. For file objects managed by OS/2 installable file systems, the following rules 
  4616. apply: 
  4617.  
  4618. o Each element of a full path name residing on a disk managed by an installable 
  4619.   file system can consist of up to 255 characters. File names can be up to 255 
  4620.   characters long (one of the characters must be a terminating NULL, "\0"). 
  4621.   Directory names can also be 255 characters long, but the length of the 
  4622.   complete path, including drive, directories, and file name, cannot exceed 260 
  4623.   characters. For example, in the path name "c:\XXX...XXX\YYY", "XXX...XXX" can 
  4624.   include up to 255 characters. This is referred to as long file names. 
  4625.  
  4626. o Names are not case sensitive. 
  4627.  
  4628. o File name case as specified at create time is preserved. This means that if 
  4629.   the file "file.TXT" is created, DosFindFirst returns "file.TXT".  File name 
  4630.   case may be modified using DosMove. 
  4631.  
  4632. o Blanks immediately preceding a dot are significant. This means that 
  4633.   "FILE.TXT" and "FILE   .TXT" refer to different files. 
  4634.  
  4635. o Trailing blanks are truncated.  This means that "FILE.TXT  " is the same as 
  4636.   "FILE.TXT". 
  4637.  
  4638. o Blanks elsewhere in the name are significant.  This means that "F I L E.TXT" 
  4639.   is not the same as "FILE.TXT". 
  4640.  
  4641. o For compatibility reasons, trailing dots on component names are discarded. 
  4642.   For Example, "\FILE.TXT...TEXT...\A..B...\C." becomes 
  4643.   "\FILE.TXT...TEXT\A..B\C". This processing includes semaphore, queue, pipe, 
  4644.   module, shared memory names, and device names. 
  4645.  
  4646. o The set of legal characters is expanded to include 
  4647.  
  4648.         +   =   ;   ,   [   ]
  4649.   as well as all characters legal for the FAT file system. 
  4650.  
  4651. o If an installable file system uses a component separator within a file name, 
  4652.   it must be a dot (.). There are no restrictions on the number of components 
  4653.   which can be allowed within a file name. 
  4654.  
  4655.  
  4656. ΓòÉΓòÉΓòÉ 7.1.3. Long File Names ΓòÉΓòÉΓòÉ
  4657.  
  4658. Programs that recognize long file names must indicate this by including the 
  4659. NEWFILES statement in their module definition file. This statement directs the 
  4660. linker to set a bit in the executable file header. It indicates that the module 
  4661. supports long file names. This bit is meaningless in a DOS Session and on 
  4662. versions of the OS/2 operating system prior to Version 1.2. Programs written 
  4663. for OS/2 Version 1.2 (and all later versions) installable file systems should 
  4664. set this bit. Bound programs that have this bit set can see files with long 
  4665. file names in OS/2 mode, but only files with 8.3 file name format in DOS 
  4666. Sessions. 
  4667.  
  4668. This bit has meaning when attached to program modules, not when attached to 
  4669. DLLs. Whether the program recognizes long file names format is entirely 
  4670. dependent on the value of its NEWFILES bit and the effect of the bit extends 
  4671. into any calls to DLLs. In order to be compatible with all OS/2 file systems, 
  4672. dynamic link libraries must not create internal temporary files or directories 
  4673. that do not comply with 8.3 file naming conventions. In addition, dynamic link 
  4674. libraries cannot return long file names to an application. (The caller might be 
  4675. running on a file system that only supports 8.3 file names and use the returned 
  4676. name to create a file.) 
  4677.  
  4678. OS/2 applications which do not recognize long file names can run with some 
  4679. restrictions. For these programs, long names (including device names) are 
  4680. filtered according to the following rules: 
  4681.  
  4682. o Any name not representable in the 8.3 file name format is not returned from 
  4683.   DosFindFirst or DosFindNext. This is because the application's buffers are 
  4684.   unlikely to be large enough to handle longer names. 
  4685.  
  4686. o Any long file name passed to the file system functions listed below are 
  4687.   rejected in exactly the same way as under previous versions of the OS/2 
  4688.   operating system. It is not acceptable to create and manipulate a name that 
  4689.   you cannot find. 
  4690.  
  4691.    DosOpen 
  4692.    DosDelete 
  4693.    DosMove 
  4694.    DosQueryPathInfo 
  4695.    DosSetPathInfo 
  4696.    DosCreateDir 
  4697.    DosDeleteDir 
  4698.    DosFindFirst 
  4699.    DosFindNext 
  4700.    DosQueryFSAttach 
  4701.    DosFSAttach 
  4702.    DosCopy 
  4703.    DosSearchPath 
  4704.  
  4705. o Long file names can be passed to DosSetCurrentDir and DosQueryCurrrentDir so 
  4706.   that all programs can use all directories. 
  4707.  
  4708. o Long names used with non-file system functions (for example, DosCreateSem) 
  4709.   are not filtered. 
  4710.  
  4711. For files located on file devices managed by the OS/2 FAT file system, long 
  4712. file names are handled differently in OS/2 mode than in DOS mode. In OS/2 mode, 
  4713. the long file name is considered an error. In DOS mode, the name is truncated 
  4714. and is not an error. The DOS mode treatment of file name formats provides 
  4715. compatibility with the PC-DOS environment for applications originally written 
  4716. for PC-DOS. However, if you are writing a family application to run under both 
  4717. the OS/2 operating system and the PC-DOS environment, your application must 
  4718. allow for this difference in operating environments. 
  4719.  
  4720. Because long file names can be input to applications through program command 
  4721. lines, dialog boxes, or function calls, applications must provide their users 
  4722. with rules for how to enter file names. File Names in User Input provides some 
  4723. general guidelines in this matter, that are applicable to both long file names 
  4724. and 8.3 file names. 
  4725.  
  4726.  
  4727. ΓòÉΓòÉΓòÉ 7.1.4. Moving Files with Long Names ΓòÉΓòÉΓòÉ
  4728.  
  4729. The OS/2 Workplace Shell supports copying files with long file names to media 
  4730. that is managed by a non-installable file system (IFS) and for returning these 
  4731. files to IFS media with the long name intact. 
  4732.  
  4733. When a file with a long name is copied to media that does not support long file 
  4734. names, the OS/2 Workplace Shell stores the file's long name in the .LONGNAME 
  4735. extended attribute. When the file is copied back to a disk that does support 
  4736. long file names, the OS/2 Workplace Shell restores the long name from the 
  4737. extended attribute. 
  4738.  
  4739. If the new media does not support extended attributes, files that have long 
  4740. names cannot be moved to the media without having their names modified or 
  4741. truncated. 
  4742.  
  4743. Note:  The behavior described above only applies to the OS/2 Workplace Shell. 
  4744.        The command processors, CMD.EXE and COMMAND.COM, do not automatically 
  4745.        save the long file name; they require the user to enter a new file name 
  4746.        that is legal on the new media. The DosCopy command also does not save 
  4747.        the long file name automatically; the programmer must provide the target 
  4748.        file name to DosCopy and the target file name must be a legal file name 
  4749.        for the target media. 
  4750.  
  4751. If you choose to store and restore the file's long name, you must do it 
  4752. yourself in the manner described above. 
  4753.  
  4754.  
  4755. ΓòÉΓòÉΓòÉ 7.2. Metacharacters in File Names ΓòÉΓòÉΓòÉ
  4756.  
  4757. Metacharacters are characters that can be used to represent placeholders in a 
  4758. file name. The asterisk (*) and the question mark (?) are the two 
  4759. metacharacters. The asterisk matches one or more characters, including blanks, 
  4760. but does not match the period. The question mark matches exactly one character, 
  4761. unless that character is a period. To match a period, the original name must 
  4762. contain a period. Metacharacters are illegal in all but the last component of a 
  4763. path. Metacharacters are also referred to as global file name characters, or as 
  4764. wildcard characters. 
  4765.  
  4766. An application that allows more than one file name on its command line, can 
  4767. accept metacharacters to provide users with a shortcut for entering a long list 
  4768. of names. For instance, metacharacters can be used to reference a set of files 
  4769. with a common base name; to reference all files with an extension of EXE, the 
  4770. user would enter: 
  4771.  
  4772.     *.exe
  4773. Although a name that contains metacharacters is not a complete file name, an 
  4774. application can use functions, such as DosFindFirst and DosEditName, to expand 
  4775. the name (replace the metacharacters) and create one or more valid file names. 
  4776.  
  4777. Metacharacters have two sets of semantics: 
  4778.  
  4779. o As search metacharacters, which are used to select the files that are 
  4780.   returned to the user when the user searches the disk for a file. 
  4781.  
  4782. o As edit metacharacters, which are used to construct a new file name, given a 
  4783.   source name and a target name specification. 
  4784. Both asterisks and question marks, therefore, have two sets of rules, one for 
  4785. searching for file names and one for editing file names. 
  4786.  
  4787. Search metacharacters are used in commands that search for files or groups of 
  4788. files, like DIR: 
  4789.  
  4790.     dir *.exe
  4791.  
  4792. An application can expand a name with metacharacters to a list of file names by 
  4793. using DosFindFirst and DosFindNext. These functions take a file name template 
  4794. (a name with metacharacters) and return the names of files on the disk that 
  4795. match the pattern in the template. 
  4796.  
  4797. Edit metacharacters are used in commands that can change the names of files; 
  4798. for example, in a global copy command: 
  4799.  
  4800.     copy *.txt  *.old
  4801.  
  4802. An application can create a new file name from an existing name by using the 
  4803. DosEditName function. This function takes a template (a name with 
  4804. metacharacters) and expands it, using characters from an existing name. An 
  4805. asterisk in the template directs the function to copy all characters in the 
  4806. existing name until it locates a character that matches the character following 
  4807. the asterisk. A question mark directs the function to copy one character, 
  4808. unless that character is a period. The period in the template directs the 
  4809. function to look for and move to the next period in the existing name, skipping 
  4810. any characters between the current position and the period. 
  4811.  
  4812.  
  4813. ΓòÉΓòÉΓòÉ 7.2.1. Searching for Files Using Metacharacters ΓòÉΓòÉΓòÉ
  4814.  
  4815. An asterisk (*) matches 0 or more characters, any character, including blank. 
  4816. It does not cross NULL or \, which means it only matches a file name, not an 
  4817. entire path. 
  4818.  
  4819. A question mark (?) matches 1 character, unless what it would match is a period 
  4820. (.) or the terminating NULL, in which case it matches 0 characters. It also 
  4821. does not cross the backslash character (\). 
  4822.  
  4823. Any character, other than asterisks and question marks, matches itself, 
  4824. including a period. 
  4825.  
  4826. Searching is case-insensitive. For example, "FILE.TXT" references the same file 
  4827. named "file.txt". 
  4828.  
  4829. For compatibility reasons, any file name that does not have a dot in it gets an 
  4830. implicit one automatically appended to the end during searching operations. 
  4831. This means that searching for "FILE." would return "FILE". 
  4832.  
  4833. Some file system functions accept file object name specifications using 
  4834. metacharacters. See the descriptions of the individual file system functions in 
  4835. the Control Program Programming Reference for details on the use of 
  4836. metacharacters. 
  4837.  
  4838.  
  4839. ΓòÉΓòÉΓòÉ 7.2.2. Editing File Names Using Metacharacters ΓòÉΓòÉΓòÉ
  4840.  
  4841. Metacharacters in a source name simply match files and behave just like any 
  4842. other search metacharacter. 
  4843.  
  4844. Metacharacters in a target name are copy-edit commands and work as follows: 
  4845.  
  4846. o A question mark (?) copies one character unless the character it would copy 
  4847.   is a period (.), in which case it copies 0 characters. It also copies 0 
  4848.   characters if it is at the end of the source string. 
  4849.  
  4850. o An asterisk (*) copies characters from the source name to the target name 
  4851.   until it finds a source character that matches the character following it in 
  4852.   the target. 
  4853.  
  4854. o A period (.) in the target name causes the source pointer to match the 
  4855.   corresponding "." in the target. They count from the left. 
  4856.  
  4857. Editing is case-insensitive. If a case conflict between the source and editing 
  4858. string arises, the case in the editing string is used, thus: 
  4859.  
  4860.     copy file.txt *E.tmp
  4861. results in file.txt being copied as filE.tmp. 
  4862.  
  4863. DosEditName provides applications with the ability to transform a file object 
  4864. name into another name, using an editing string that contains global 
  4865. characters. 
  4866.  
  4867.  
  4868. ΓòÉΓòÉΓòÉ 7.2.3. Transforming File Names Using Metacharacters ΓòÉΓòÉΓòÉ
  4869.  
  4870. File system functions that an application uses to copy, rename or move file 
  4871. objects do not support the use of global characters. For example, a user can 
  4872. perform a global copy of all files with the extension .EXE by entering the 
  4873. following on the command line: 
  4874.  
  4875.     copy *.exe
  4876.  
  4877. An application, however, cannot perform a similar global copy operation by 
  4878. making a single call to DosCopy or DosMove. These functions operate on a 
  4879. single, specific file object. 
  4880.  
  4881. DosEditName, however, provides applications with the ability to transform an 
  4882. element of a full path name into another name, using an editing string that 
  4883. contains global characters. For example, for an application to copy all files 
  4884. with an extension of .SRC to files with an extension of .SAM, the application 
  4885. would: 
  4886.  
  4887.  1. Search for all files with the .SRC extension by using DosFindFirst and 
  4888.     DosFindNext, 
  4889.  
  4890.  2. Transform the file names by using DosEditName with an editing string of 
  4891.     "*.SAM", 
  4892.  
  4893.  3. Copy the files with the new extension with DosCopy. 
  4894.  
  4895.  
  4896. ΓòÉΓòÉΓòÉ 7.3. File Names in User Input ΓòÉΓòÉΓòÉ
  4897.  
  4898. Users often supply file names as part of an application's command line or in 
  4899. response to a prompt from the application. Traditionally, users have been able 
  4900. to supply more than one file name by separating the names with certain 
  4901. characters, such as a blank space. In some file systems, however, traditional 
  4902. separators are valid file name characters. This means additional conventions 
  4903. are required to ensure that an application processes all characters in a name. 
  4904.  
  4905. When an application processes arguments (including file names) from its command 
  4906. line, the operating system treats the double quotation mark (") and the caret 
  4907. (^) as quotation characters. All characters between the opening and closing 
  4908. double quotation marks are processed as a single argument. The caret is used to 
  4909. quote characters that would otherwise have some special property. The character 
  4910. immediately following the caret is treated as a normal character; any special 
  4911. characteristics that the character has are to be ignored. For example, the 
  4912. greater-than symbol (>) normally causes a program's output to be redirected to 
  4913. a file or device. Typing "^>" causes the ">" to be included in the command line 
  4914. passed to the application. In both cases, the operating system discards the 
  4915. quotation characters and does not treat them as part of the final argument. 
  4916.  
  4917. When a Presentation Manager (PM) application processes two or more file names 
  4918. from a dialog box or other prompt, it expects the user to enter each file name 
  4919. on a new line. Therefore, a PM application would use a multiple-line entry 
  4920. field to prompt for multiple file names. This often makes the use of quotation 
  4921. characters unnecessary. 
  4922.  
  4923. When an application is started, the operating system constructs a command line 
  4924. for the application. If the command line includes file names, the operating 
  4925. system places a space character between names and marks the end of the list 
  4926. with two NULL characters. Applications that start other applications by using 
  4927. DosExecPgm can also pass arguments by using this convention or by using 
  4928. quotation characters. In practice, most applications receive a command line as 
  4929. a single, NULL-terminated string. Therefore, applications that use DosExecPgm 
  4930. should prepare command lines as a single string, and enclose any file names in 
  4931. quotation marks. 
  4932.  
  4933.  
  4934. ΓòÉΓòÉΓòÉ 7.4. Device Names ΓòÉΓòÉΓòÉ
  4935.  
  4936. Naming conventions for character devices are similar to those for naming files. 
  4937. The OS/2 operating system has reserved certain names for character devices 
  4938. supported by the base device drivers. These device names are listed below: 
  4939.  
  4940. CLOCK$         Clock 
  4941. COM1-COM4      First through fourth serial ports 
  4942. CON            Console keyboard and screen 
  4943. KBD$           Keyboard 
  4944. LPT1           First parallel printer 
  4945. LPT2           Second parallel printer 
  4946. LPT3           Third parallel printer 
  4947. MOUSE$         Mouse 
  4948. NUL            Nonexistent (dummy) device 
  4949. POINTER$       Pointer draw device (mouse screen support) 
  4950. PRN            The default printer, usually LPT1 
  4951. SCREEN$        Screen 
  4952. These names can be used with DosOpen to open the corresponding devices. 
  4953. Reserved device names take precedence over file names; DosOpen checks for a 
  4954. device name before checking for a file name. Do not use a file name which is 
  4955. the same as a reserved device name; the file will never be opened, because the 
  4956. command will open the device instead. 
  4957.  
  4958. COM1 through COM4 are reserved device names only when the ASYNC (RS-232C) 
  4959. device driver is loaded. The same is true for POINTER$ and MOUSE$, which are 
  4960. reserved only when a mouse device driver is loaded. 
  4961.  
  4962. An application can call DosQueryFHState to verify that a file or device has 
  4963. been opened. See Determining and Setting the State of a File or Device Handle 
  4964. for more information on getting the state of a file handle. 
  4965.  
  4966.  
  4967. ΓòÉΓòÉΓòÉ 8. File Systems ΓòÉΓòÉΓòÉ
  4968.  
  4969. An application views a file as a logical sequence of data; OS/2 file systems 
  4970. manage the physical locations of that data on the storage device for the 
  4971. application. The file systems also manage file I/O operations and control the 
  4972. format of the stored information. 
  4973.  
  4974. Applications use the OS/2 file system functions to open, read, write, and close 
  4975. disk files. File system functions also enable an application to use and 
  4976. maintain the disk that contains the files-the volumes, the directories, and the 
  4977. files on the disks of the computer. Applications also use OS/2 file system 
  4978. functions to perform I/O operations to pipes and to peripheral devices 
  4979. connected to the computer, like the printer. 
  4980.  
  4981. The following topics are related to the information in this chapter: 
  4982.  
  4983. o File Names 
  4984. o File Management 
  4985. o Extended Attributes 
  4986. o Device I/O. 
  4987.  
  4988.  
  4989. ΓòÉΓòÉΓòÉ 8.1. About File Systems ΓòÉΓòÉΓòÉ
  4990.  
  4991. A file system is the combination of software and hardware that supports storing 
  4992. information on a storage device. In the OS/2 operating system, the file system 
  4993. specifies how data is organized on the mass storage devices of the computer, 
  4994. such as hard disks and floppy disks. 
  4995.  
  4996. Each drive is assigned a unique letter to distinguish it from other drives. A 
  4997. single hard disk can also be divided into two or more logical drives. A logical 
  4998. drive represents a portion of the hard disk and, like a physical drive, is 
  4999. assigned a unique letter to distinguish it from other physical and logical 
  5000. drives. 
  5001.  
  5002. The file system organizes disks into volumes, directories, and files. A volume 
  5003. is the largest file system unit. It represents all the available storage on the 
  5004. logical drive. An optional volume name identifies the volume. 
  5005.  
  5006. Volumes are subdivided into directories, which contain files and other 
  5007. subdirectories. Each volume has a root directory, which contains file and 
  5008. directory entries. All other subdirectories trace their ancestry back to the 
  5009. root directory. Each directory entry identifies the name, location, and size of 
  5010. a specific file or subdirectory on the disk. A file is one or more bytes of 
  5011. data stored on the disk. Subdirectories provide an additional level of 
  5012. organization and, like the root directory, can contain files and directory 
  5013. entries. 
  5014.  
  5015. The file system also enables users and applications to access certain non-disk 
  5016. devices as if they were files. An example of such a device would be the 
  5017. printer, which can be accessed through the file system by using the printer's 
  5018. logical name, PRN, as a file name. 
  5019.  
  5020.  
  5021. ΓòÉΓòÉΓòÉ 8.1.1. Types of File Systems ΓòÉΓòÉΓòÉ
  5022.  
  5023. The OS/2 operating system has two file systems: the file allocation table (FAT) 
  5024. file system and the High Performance File System (HPFS). These file systems 
  5025. define how information is organized on the storage devices. 
  5026.  
  5027. A user can choose to install either or both file systems. An application must 
  5028. be able to work with any file system. The OS/2 operating system provides a 
  5029. common set of file system functions that are not dependent on a particular file 
  5030. system. 
  5031.  
  5032. Both of these file systems support: 
  5033.  
  5034. o Existing logical file and directory structure 
  5035. o Existing naming conventions 
  5036. o Multiple logical volumes (partitions) 
  5037. o Multiple and different storage devices 
  5038. o Redirection or connection to remote file systems 
  5039. o Extended attributes 
  5040. o Metacharacter file-name processing. 
  5041. Additionally, HPFS supports: 
  5042.  
  5043. o Long file names 
  5044. o An extendable application interface. 
  5045. The High Performance File System is an example of a class of file systems 
  5046. called installable file systems. Installable file systems are installed by the 
  5047. user (by changing CONFIG.SYS) and are loaded by the operating system during 
  5048. system initialization. 
  5049.  
  5050. The OS/2 operating system permits users to have multiple file systems active at 
  5051. the same time; for example a FAT file system for one hard disk and HPFS for 
  5052. another. 
  5053.  
  5054.  
  5055. ΓòÉΓòÉΓòÉ 8.1.1.1. FAT File System ΓòÉΓòÉΓòÉ
  5056.  
  5057. The OS/2 FAT file system is based on the DOS FAT file system. This file system, 
  5058. also used in previous releases of the OS/2 operating system and in PC-DOS, 
  5059. controls storage of data files for hard and floppy disks. 
  5060.  
  5061. The FAT file system is hierarchical, supporting multiple directories on the 
  5062. disk. Each directory can contain one or more files or subdirectories. 
  5063.  
  5064. The FAT file system uses the 8.3 file name convention. Under this convention, 
  5065. the file name consists of a file name of up to eight characters, a separating 
  5066. period (.),  and a file name extension of up to three characters. 
  5067.  
  5068.  
  5069. ΓòÉΓòÉΓòÉ 8.1.1.2. Installable File Systems ΓòÉΓòÉΓòÉ
  5070.  
  5071. An installable file system is a file system in which software is installed when 
  5072. the operating system is started. The OS/2 operating system supports installable 
  5073. file systems and permits users to have multiple file systems active at the same 
  5074. time. 
  5075.  
  5076. Users install a file system by specifying the file system components in the 
  5077. CONFIG.SYS file. The file system software consists of device drivers and 
  5078. dynamic link libraries. The device drivers access storage devices; the dynamic 
  5079. link libraries control the format of information on a device and manage the 
  5080. flow of data to and from the device. The user must use the DEVICE= command to 
  5081. specify the device driver and the IFS= command to specify the dynamic link 
  5082. library. 
  5083.  
  5084. Installable file system drivers are loaded during system initialization when an 
  5085. IFS= statement is encountered in the CONFIG.SYS file. The operating system 
  5086. loads the device driver and dynamic link library and initializes a specific 
  5087. device for use with a file system. 
  5088.  
  5089. These file systems can support file and directory structures different from the 
  5090. FAT file system. 
  5091.  
  5092. An example of an installable file system might be a file system designed 
  5093. specifically for use on a network server. Another example of an installable 
  5094. file system is the High Performance File System (HPFS), which is included with 
  5095. the OS/2 operating system. 
  5096.  
  5097.  
  5098. ΓòÉΓòÉΓòÉ 8.1.1.3. High Performance File System ΓòÉΓòÉΓòÉ
  5099.  
  5100. The High Performance File System (HPFS) is an installable file system. It is a 
  5101. hierarchical system and supports multiple directories. In many cases, accessing 
  5102. files under HPFS is faster than accessing similar files under the FAT file 
  5103. system. During installation of the OS/2 operating system, users can install the 
  5104. HPFS on the hard disk they use to start their computer. 
  5105.  
  5106. Features of HPFS include: 
  5107.  
  5108. o Caching of directories, data, and file system data structures 
  5109. o Multi-threaded I/O operations 
  5110. o Write-behind logic 
  5111. o Optional write-through 
  5112. o Strategic allocation of directory structures 
  5113. o Highly contiguous file allocation 
  5114. o Enhanced recoverability 
  5115. o Extended attribute support 
  5116. o Long file name support 
  5117. o Starting the OS/2 operating system from an HPFS disk. 
  5118. File names under HPFS can contain 255 characters (one must be the terminating 
  5119. NULL, "\0") and can contain characters that are not valid for the FAT file 
  5120. system-for example, spaces. Each element of a path name residing on an HPFS 
  5121. disk can also have up to 255 characters. The total path including drive, 
  5122. directories, and file name cannot exceed 260 characters (259 with the 
  5123. terminating NULL). For more information on long file name support by 
  5124. installable file systems see Long File Names. 
  5125.  
  5126. HPFS provides extremely fast access to very large disk volumes. HPFS uses a 
  5127. memory cache divided into blocks of 2KB. Data that is read from and written to 
  5128. the disk is transferred through this cache. Frequently-used data will often be 
  5129. found in the cache, thereby saving the time that a disk-read operation would 
  5130. require. When a user request specifies data that is not present in the cache, 
  5131. HPFS selects the least-recently-used block, writes the data within that block 
  5132. to disk, if necessary, and then fills the block with the requested data. 
  5133.  
  5134. When a write-data request is received, it usually is not necessary that the 
  5135. data be immediately written to the disk. HPFS will copy such data into the 
  5136. block cache without actually performing the disk-write operation. When the data 
  5137. is in the cache, it is written to disk as a background activity (referred to as 
  5138. lazy writing) which enables the typical user-write operation to occur much 
  5139. faster than in file systems where all write operations are synchronous. 
  5140.  
  5141. The High Performance File System consists of: 
  5142.  
  5143. o The High Performance File System driver, HPFS.IFS 
  5144. o The High Performance File System lazy-write utility, CACHE.EXE 
  5145. o The High Performance File System lazy-write startup program, STARTLW.DLL 
  5146. o The High Performance File System utilities, UHPFS.DLL. 
  5147. The user determines the amount of lazy-write support by setting the following 
  5148. parameters on the command line that calls CACHE.EXE: 
  5149.  
  5150. o MaxAge: 
  5151.  
  5152.   When the data in a cache block exceeds the specified time the block is queued 
  5153.   for writing to the disk. This reduces the amount of data lost due to 
  5154.   inopportune system shutdowns. 
  5155.  
  5156. o DiskIdle and BufferIdle 
  5157.  
  5158.   When no user I/O request (non-lazy-write) has been made for DiskIdle number 
  5159.   of milliseconds, all cache blocks (in oldest-first order) that have not been 
  5160.   touched for BufferIdle number of milliseconds are queued for writing to disk. 
  5161.   This enables HPFS to write out user data during times of relative disk 
  5162.   inactivity and to reduce the need for rewriting heavily used cached blocks. 
  5163.  
  5164. STARTLW.DLL contains the code that starts the lazy-write thread. 
  5165.  
  5166.  
  5167. ΓòÉΓòÉΓòÉ 8.1.1.4. Local and Remote File Systems ΓòÉΓòÉΓòÉ
  5168.  
  5169. Installable file systems work with a variety of storage devices. A file system 
  5170. on a local device such as a disk drive or virtual drive is called a local file 
  5171. system. A file system on a remote device, such as a disk drive on another 
  5172. computer, is called a remote file system. An application can establish a 
  5173. connection to a local or a remote file system by using DosFSAttach. 
  5174.  
  5175. For a local file system, the operating system uses a block device driver, which 
  5176. accesses disk hardware, to handle input and output to the device. The operating 
  5177. system automatically connects most (if not all) local file systems when it 
  5178. starts. However, an application can attach and detach additional file systems 
  5179. as needed. 
  5180.  
  5181. For a remote file system, the operating system uses a device driver that 
  5182. typically accesses a communications or network device. Usually, the actual 
  5183. storage device is located on another computer, and the two computers 
  5184. communicate requests and data through a network connection. An application can 
  5185. associate a remote file system with a drive letter by using DosFSAttach. Once 
  5186. the connection is made, the application can access directories and files on the 
  5187. remote device simply by using the assigned drive letter, treating the remote 
  5188. device as if it were on the same computer. 
  5189.  
  5190.  
  5191. ΓòÉΓòÉΓòÉ 8.1.2. Recognizing DOS and OS/2 File Objects ΓòÉΓòÉΓòÉ
  5192.  
  5193. The OS/2 FAT file system recognizes file objects created by the DOS FAT file 
  5194. system. This means that applications running under the OS/2 operating system 
  5195. (these include both OS/2 applications and DOS applications running in a DOS 
  5196. Session) can access file objects created by applications running under DOS. 
  5197.  
  5198. Because the OS/2 FAT file system supports the same directory structure as the 
  5199. DOS FAT file system, applications running under DOS can access files and 
  5200. directories created by the OS/2 FAT file system. 
  5201.  
  5202. However, the High Performance File System (HPFS) does not support the same 
  5203. directory structure as the DOS FAT file system.  Therefore, the DOS FAT file 
  5204. system will not recognize file objects created by HPFS. This means that if you 
  5205. start the computer with DOS, applications running under DOS cannot access files 
  5206. and directories on HPFS disks. 
  5207.  
  5208. DOS applications running in a DOS Session under the OS/2 operating system can 
  5209. recognize files and directories on both FAT and HPFS disks. A request from a 
  5210. DOS Session to read a file on a FAT disk is handled by the OS/2 FAT file 
  5211. system. Similarly, a request from a DOS Session to read a file on an HPFS disk 
  5212. is handled by the OS/2 High Performance File System. 
  5213.  
  5214.  
  5215. ΓòÉΓòÉΓòÉ 8.1.3. Storage Devices and File Systems ΓòÉΓòÉΓòÉ
  5216.  
  5217. OS/2 file systems store information on mass storage devices. These devices are 
  5218. usually hard disks or floppy diskettes, but can be other media, such as CD-ROM. 
  5219.  
  5220. Each drive (or device) is assigned a unique letter to distinguish it from other 
  5221. drives. On most personal computers, drive A is the first floppy disk drive, 
  5222. drive B is the second floppy disk drive, drive C is the first hard disk drive, 
  5223. and drive D is the second hard disk drive. 
  5224.  
  5225. A single hard disk can be divided into two or more partitions, each of which 
  5226. are then viewed as a separate logical drive. A logical drive, like a physical 
  5227. drive, is assigned a unique letter to distinguish it from other physical and 
  5228. logical drives. FDISK is the OS/2 utility used to partition physical storage 
  5229. devices; see the description of the FDISK utility in the online OS/2 Command 
  5230. Reference. 
  5231.  
  5232. A personal computer running the OS/2 operating system can have up to 26 logical 
  5233. disk drives. 
  5234.  
  5235. Each logical storage device can be managed by a different file system. The file 
  5236. system attached to a storage device manages that device. A user attaches a file 
  5237. system to a storage device by: 
  5238.  
  5239. o Loading the file system driver during system initialization (by including an 
  5240.   IFS= statement in CONFIG.SYS). 
  5241.  
  5242. o Formatting the storage device by using the format options for the file 
  5243.   system. 
  5244. During installation of the OS/2 operating system, users have the option of 
  5245. formatting hard disks with the FAT file system or with the High Performance 
  5246. File System (HPFS). If the user chooses to use the HPFS, an IFS= statement is 
  5247. added to the CONFIG.SYS file so that HPFS is loaded automatically during each 
  5248. system startup. During formatting, the file system driver is associated with 
  5249. the logical storage device or drive letter of the hard disk. 
  5250.  
  5251. When an application calls a file system function, the operating system directs 
  5252. the request to: 
  5253.  
  5254. o The installable file system managing the storage device, or 
  5255. o The FAT file system, if no installable file system is loaded and attached to 
  5256.   the storage device. 
  5257.  
  5258. The file system used to format the storage media manages that media each time 
  5259. the system is started, as long as the file system is loaded during system 
  5260. start-up. The operating system directs file system requests for a storage media 
  5261. to the file system that formatted the media. If no file system recognizes the 
  5262. format of the media, the OS/2 FAT file system attempts to manage that media. 
  5263. This might occur when the file system used to format the storage media is not 
  5264. loaded during system startup (the IFS= statement was removed from the 
  5265. CONFIG.SYS file after OS/2 installation). If the OS/2 FAT file system cannot 
  5266. recognize the media format (the media might have a different directory 
  5267. structure), the user receives an error when attempting to access the media. 
  5268.  
  5269. For example, assume a system is configured with diskette drive A and hard disk 
  5270. drives C and D. During OS/2 installation, the user elects to format drive C 
  5271. using HPFS. Drive C is, then, managed by HPFS. Drive D was formatted with the 
  5272. FAT file system, so it is managed by the OS/2 FAT file system, as is diskette 
  5273. drive A (removable media cannot be formatted using HPFS). When an application 
  5274. calls DosOpen to open a file on drive C, the operating system directs the 
  5275. request to HPFS. When an application calls DosOpen to open a file on drive A, 
  5276. the operating system directs the request to the OS/2 FAT file system. 
  5277.  
  5278. If HPFS is not loaded during system startup, the FAT file system will receive 
  5279. file system requests made for drive C. However, because HPFS supports a 
  5280. different directory structure than the FAT file system does, the OS/2 FAT file 
  5281. system cannot recognize file objects on the disk. The user will receive an 
  5282. error when attempting to gain access to the disk. 
  5283.  
  5284. Users can determine which file system was used to format a storage device by 
  5285. using the CHKDSK utility. CHKDSK displays a message indicating which file 
  5286. system manages the specified drive. For more information on FORMAT and CHKDSK, 
  5287. see the online OS/2 Command Reference. 
  5288.  
  5289.  
  5290. ΓòÉΓòÉΓòÉ 8.1.4. File System Utilities ΓòÉΓòÉΓòÉ
  5291.  
  5292. Utilities for each file system are in a single dynamic link library. The 
  5293. utilities that the operating system calls are based on the file system that 
  5294. recognizes the volume on which the utility is to be run. The dynamic link 
  5295. library for each file system has the following utilities: 
  5296.  
  5297. FORMAT         Disk formatter 
  5298. CHKDSK         File system validation and repair 
  5299. RECOVER        File recovery 
  5300. SYS            System installation. 
  5301.  
  5302.  
  5303. ΓòÉΓòÉΓòÉ 8.1.5. OS/2 Boot Manager ΓòÉΓòÉΓòÉ
  5304.  
  5305. The OS/2 Boot Manager enables different operating systems to co-reside on the 
  5306. same computer. The user selects the operating system to boot when the computer 
  5307. is turned on. For example, DOS, AIX, and the OS/2 operating system can 
  5308. co-reside on the same machine. There can also be a previous version of the OS/2 
  5309. operating system on the machine co-existing with the current version of the 
  5310. operating system. 
  5311.  
  5312. Each operating system has its own partition and each partition is managed by 
  5313. the appropriate file system for the operating system that owns it. A DOS 
  5314. partition has a FAT file system. An OS/2 partition can have either a FAT file 
  5315. system or HPFS. An AIX partition will use the AIX file system to manage its 
  5316. partition. 
  5317.  
  5318. Note:  FAT partitions that follow HPFS partitions on the same physical disk 
  5319.        cannot be accessed when using DOS because DOS stops at the first 
  5320.        partition it does not recognize. 
  5321.  
  5322. For information on installing and using the Boot Manager see the OS/2 2.0 
  5323. Installation Guide. 
  5324.  
  5325.  
  5326. ΓòÉΓòÉΓòÉ 8.2. Using File Systems ΓòÉΓòÉΓòÉ
  5327.  
  5328. In order to take advantage of the capabilities of OS/2 file systems, 
  5329. application developers must be able to manage the file systems. 
  5330.  
  5331. Most of the file system functions work with either the FAT file system or the 
  5332. High Performance File System (HPFS). 
  5333.  
  5334. Note:  In the example code fragments that follow, error checking was left out 
  5335.        to conserve space. Applications should always check the return code that 
  5336.        the functions return. Control Program functions return an APIRET value. 
  5337.        A return code of 0 indicates success. If a non-zero value is returned, 
  5338.        an error occurred. 
  5339.  
  5340.  
  5341. ΓòÉΓòÉΓòÉ 8.2.1. Attaching and Detaching File Systems ΓòÉΓòÉΓòÉ
  5342.  
  5343. A file system driver that uses a block device driver for I/O operations to a 
  5344. local or remote (virtual disk) device is called a local file system. A file 
  5345. system driver that accesses a remote system without a block device driver is 
  5346. called a remote file system. 
  5347.  
  5348. An application, typically a network application, can call DosFSAttach to: 
  5349.  
  5350. o Attach a drive to a remote file system 
  5351. o Detach a drive from a remote file system 
  5352. o Attach a pseudocharacter device name to a local or remote file system 
  5353. o Detach a pseudocharacter device name from a local or remote file system. 
  5354. DosFSAttach establishes or breaks the connection between a drive or device and 
  5355. a file system. If an attachment is successful, all requests to that drive or 
  5356. name are routed to the specified file system. If a detachment is successful, 
  5357. the operating system will no longer recognize the drive or name in a file 
  5358. system call. 
  5359.  
  5360. DosFSAttach does not support: 
  5361.  
  5362. o Redirection of drive letters representing local drives 
  5363. o Attachment to drives or devices that are not in the system's name space. 
  5364.   (DosFSCtl can be used to attach to drives or devices not in the system's name 
  5365.   space.) 
  5366.  
  5367.   A name space is a set of names that are known to the file system. For 
  5368.   example, CON and PRN are always in the OS/2 file system's name space. 
  5369.  
  5370. The following code fragment attaches a drive to a remote file system driver 
  5371. (FSD). Assume that the FSD does not require any user-supplied data arguments. 
  5372.  
  5373.     #define INCL_DOSFILEMGR   /* File System values */
  5374.     #include <os2.h>
  5375.     #include <stdio.h>
  5376.  
  5377.     UCHAR   DeviceName[8]; /* Device name or drive letter string */
  5378.     UCHAR   FSDName[40];   /* FSD name                           */
  5379.     PVOID   DataBuffer;    /* Attach argument data               */
  5380.     ULONG   DataBufferLen; /* Buffer length                      */
  5381.     ULONG   OpFlag;        /* Attach or detach                   */
  5382.     APIRET  rc;            /* Return code                        */
  5383.  
  5384.     strcpy(DeviceName,"Y:");
  5385.                         /* Drive letter with which to attach the */
  5386.                         /* file system driver                    */
  5387.  
  5388.     strcpy(FSDName,"\\lan03\\src");
  5389.  
  5390.     DataBuffer = 0;     /* Assume that no user-supplied data     */
  5391.                         /* arguments are required                */
  5392.  
  5393.     DataBufferLen = 0;  /* No data buffer supplied               */
  5394.  
  5395.     OpFlag = 0;         /* Indicate Attach request               */
  5396.  
  5397.     rc = DosFSAttach(DeviceName, FSDName, DataBuffer, DataBufferLen, OpFlag);
  5398.  
  5399.     if (rc != 0) {
  5400.         printf("DosFSAttach error: return code = %ld", rc);
  5401.         return;
  5402.     }
  5403.  
  5404. Attaching a Drive to a Remote File System Driver 
  5405.  
  5406.  
  5407. ΓòÉΓòÉΓòÉ 8.2.2. Obtaining Information about an Attached File System ΓòÉΓòÉΓòÉ
  5408.  
  5409. To obtain information about block devices, and all character and 
  5410. pseudocharacter devices, including the type of device and the name of the file 
  5411. system driver the device is attached to, use DosQueryFSAttach. 
  5412.  
  5413. The information can be used to determine if the operating system recognizes 
  5414. that a particular file system is attached to a storage device. This is 
  5415. important to an application that must guarantee such a state. An application of 
  5416. this type must handle the situation where the file system driver that formatted 
  5417. a certain disk was not loaded during system startup.  (The user might have 
  5418. omitted the IFS= statement in the CONFIG.SYS. file). In such a situation, the 
  5419. data on the disk could be destroyed because the wrong file system was attached 
  5420. to the disk by default. 
  5421.  
  5422. The following code fragment returns information about an attached file system. 
  5423.  
  5424.     #define INCL_DOSFILEMGR   /* File System values */
  5425.     #include <os2.h>
  5426.     #include <stdio.h>
  5427.  
  5428.     UCHAR       DeviceName[8];   /* Device name or drive letter string */
  5429.     ULONG       Ordinal;         /* Ordinal of entry in name list      */
  5430.     ULONG       FSAInfoLevel;    /* Type of attached FSD data required */
  5431.     FSQBUFFER2  DataBuffer;      /* Returned data buffer               */
  5432.     ULONG       DataBufferLen;   /* Buffer length                      */
  5433.     APIRET      rc;              /* Return code                        */
  5434.  
  5435.     strcpy(DeviceName,"Y:");     /* Logical drive of the attached file system */
  5436.  
  5437.     FSAInfoLevel = 1;
  5438.  
  5439.     DataBufferLen = sizeof(FSQBUFFER2);    /* Length of data buffer */
  5440.  
  5441.     rc = DosQueryFSAttach(DeviceName, Ordinal, FSAInfoLevel,
  5442.                         &DataBuffer, &DataBufferLen);
  5443.  
  5444.     if (rc != 0) {
  5445.         printf("DosQueryFSAttach error: return code = %ld", rc);
  5446.         return;
  5447.     }
  5448.  
  5449.  
  5450. Obtaining Information about an Attached File System 
  5451.  
  5452. In this example, information was requested about the drive whose name was 
  5453. specified within the DeviceName variable. After the DosQueryFSAttach call, the 
  5454. DataBuffer structure contained a set of information describing the specified 
  5455. attached file system, and the DataBufferLen variable contained the size of 
  5456. information within the structure. 
  5457.  
  5458.  
  5459. ΓòÉΓòÉΓòÉ 8.2.3. Obtaining Information about a File System ΓòÉΓòÉΓòÉ
  5460.  
  5461. An application can retrieve information about the file system on a given drive 
  5462. by using DosQueryFileInfo. The file system information includes information on 
  5463. the amount of free storage space on the disk. The storage space is given in 
  5464. number of allocation units (clusters) on the disk. Each cluster has an 
  5465. associated number of sectors; each sector contains a given number of bytes. A 
  5466. typical disk has 512 bytes for each sector and 4 sectors for each cluster. 
  5467. DosSetFSInfo enables an application to change the volume identifier for the 
  5468. disk in the given drive. 
  5469.  
  5470. The following code fragment obtains information about the file system that is 
  5471. associated with a particular logical drive. 
  5472.  
  5473.     #define INCL_DOSFILEMGR   /* File System values */
  5474.     #include <os2.h>
  5475.     #include <stdio.h>
  5476.  
  5477.     ULONG   DriveNumber;     /* Drive number                 */
  5478.     ULONG   FSInfoLevel;     /* File system data required    */
  5479.     UCHAR   FSInfoBuf[40];   /* File system info buffer      */
  5480.     ULONG   FSInfoBufSize;   /* File system info buffer size */
  5481.     APIRET  rc;              /* Return code                  */
  5482.  
  5483.     DriveNumber = 3;              /* Specify drive C                      */
  5484.  
  5485.     FSInfoLevel = FSIL_ALLOC;     /* Indicate that file system allocation */
  5486.                                   /* information is requested             */
  5487.  
  5488.     FSInfoBufSize = 40;           /* Size of return data buffer           */
  5489.  
  5490.     rc = DosQueryFSInfo(DriveNumber, FSInfoLevel, FSInfoBuf, FSInfoBufSize);
  5491.  
  5492.     if (rc != 0) {
  5493.         printf("DosQueryFSInfo error: return code = %ld", rc);
  5494.         return;
  5495.     }
  5496.  
  5497.  
  5498. Obtaining Information about the File System 
  5499.  
  5500. In this example, the data buffer FSInfoBuf is used to receive information about 
  5501. space allocation within the specified file system. 
  5502.  
  5503.  
  5504. ΓòÉΓòÉΓòÉ 8.2.4. Obtaining Information about a File ΓòÉΓòÉΓòÉ
  5505.  
  5506. An application can retrieve and set information about a specific file by using 
  5507. DosQueryFileInfo and DosSetFileInfo. File information consists of the dates and 
  5508. times that the file was created, last accessed, and last written to; the size 
  5509. (in bytes) of the file; the number of sectors (or clusters) the file occupies; 
  5510. and the file attributes. 
  5511.  
  5512. The following code fragment obtains file information for a specified file. The 
  5513. example obtains the Level 1 information set for the file. The Level 1 
  5514. information set for a file includes the dates and times of creation, last 
  5515. access, and last writing. It also includes information about the size of the 
  5516. file and the file's standard attributes. Assume that the handle of the desired 
  5517. file has been placed into FileHandle already. 
  5518.  
  5519.     #define INCL_DOSFILEMGR   /* File System values */
  5520.     #include <os2.h>
  5521.     #include <stdio.h>
  5522.  
  5523.     HFILE        FileHandle;      /* File handle                 */
  5524.     ULONG        FileInfoLevel;   /* Level of file info required */
  5525.     FILESTATUS3  FileInfoBuf;     /* File info buffer            */
  5526.     ULONG        FileInfoBufSize; /* File data buffer size       */
  5527.     APIRET       rc;              /* Return code                 */
  5528.  
  5529.     FileInfoLevel = 1;    /* Indicate that Level 1 information is desired */
  5530.  
  5531.     FileInfoBufSize = sizeof(FILESTATUS3);
  5532.                           /* Size of the buffer that will                 */
  5533.                           /* receive the Level 1 information              */
  5534.  
  5535.     rc = DosQueryFileInfo(FileHandle, FileInfoLevel, &FileInfoBuf,
  5536.                           FileInfoBufSize);
  5537.  
  5538.     if (rc != 0) {
  5539.         printf("DosQueryFileInfo error: return code = %ld", rc);
  5540.         return;
  5541.     }
  5542.  
  5543.  
  5544. Obtaining Information about a File 
  5545.  
  5546. In this example, Level 1 file information is placed into the FileInfoBuf 
  5547. buffer. 
  5548.  
  5549.  
  5550. ΓòÉΓòÉΓòÉ 8.2.5. Communicating with a File System ΓòÉΓòÉΓòÉ
  5551.  
  5552. An extended standard interface between an application and a file system driver 
  5553. is provided by DosFSCtl. This function is similar to DosDevIOCtl, which 
  5554. provides a standard interface between an application and a device driver. An 
  5555. application sends a request to the file system driver by specifying a 
  5556. particular function code. Data is exchanged through data areas and parameter 
  5557. lists. 
  5558.  
  5559. DosFSCtl can be used to establish open connections to file system drivers that 
  5560. are not attached to a name in the operating system's name space. (A name space 
  5561. is a set of names that are known to the file system. For example, CON and PRN 
  5562. are always in the OS/2 file system's name space.) 
  5563.  
  5564. The following code fragment demonstrates how a process can communicate with a 
  5565. file system driver (FSD). Assume that the calling process has placed an 
  5566. appropriate file handle into FileHandle. Assume that the specified file system 
  5567. recognizes a function code of hex 8100, and that the function code accepts an 
  5568. ASCII string as input, requires no specific command parameter list, and returns 
  5569. a string of ASCII characters to the caller. 
  5570.  
  5571.     #define INCL_DOSFILEMGR   /* File System values */
  5572.     #include <os2.h>
  5573.     #include <stdio.h>
  5574.  
  5575.     UCHAR   DataArea[100];    /* Data area                           */
  5576.     ULONG   DataLengthMax;    /* Max. length of Data area            */
  5577.     ULONG   DataLengthInOut;  /* Data area length, in and out        */
  5578.     PVOID   ParmList;         /* Parameter list                      */
  5579.     ULONG   ParmLengthMax;    /* Max. length of Parameter list       */
  5580.     ULONG   ParmLengthInOut;  /* Parameter list length, in and out   */
  5581.     ULONG   FunctionCode;     /* Function code                       */
  5582.     PSZ     RouteName;        /* Path or FSD name                    */
  5583.     HFILE   FileHandle;       /* File handle                         */
  5584.     ULONG   RouteMethod;      /* Method for routing                  */
  5585.     APIRET  rc;               /* Return code                         */
  5586.  
  5587.     FunctionCode = 0x8100;    /* Indicate the function to request    */
  5588.                               /* of the file system                  */
  5589.  
  5590.     strcpy(DataArea,"PARM1: 98");
  5591.                               /* ASCII string to pass to file system */
  5592.  
  5593.     DataLengthMax = 100;      /* Tell the file system the maximum    */
  5594.                               /* amount of data it can return        */
  5595.  
  5596.     DataLengthInOut = strlen(DataArea);
  5597.                               /* On input, this is the number of     */
  5598.                               /* bytes sent to the file system       */
  5599.  
  5600.     ParmList = 0;             /* In this example, assume that no     */
  5601.     ParmLengthMax = 0;        /* specific command parameter list     */
  5602.     ParmLengthInOut = 0;      /* is required by the file system      */
  5603.                               /* for this function code              */
  5604.  
  5605.     RouteMethod = 1;          /* Indicate that the file handle       */
  5606.     RouteName = 0;            /* directs routing (this implies       */
  5607.                               /* that the RouteName variable is      */
  5608.                               /* unused in this example)             */
  5609.  
  5610.     rc = DosFSCtl(DataArea, DataLengthMax, &DataLengthInOut,
  5611.                   ParmList, ParmLengthMax, &ParmLengthInOut,
  5612.                   FunctionCode, RouteName, FileHandle,
  5613.                   RouteMethod);
  5614.  
  5615.     if (rc != 0) {
  5616.         printf("DosFSCtl error: return code = %ld", rc);
  5617.         return;
  5618.     }
  5619.  
  5620.  
  5621. Communicating with a File System Driver 
  5622.  
  5623. In this example, the the DataArea buffer is used to store the ASCII string sent 
  5624. by the file system in response to the function request, and the DataLengthInOut 
  5625. variable is used to store the number of bytes placed in the buffer by the file 
  5626. system. 
  5627.  
  5628.  
  5629. ΓòÉΓòÉΓòÉ 8.2.6. Preparing File Systems for System Shutdown ΓòÉΓòÉΓòÉ
  5630.  
  5631. At any time during normal system operation, data destined for a disk might be 
  5632. in a cache. If this information is not written to disk before the system 
  5633. powered-off, the disk can become corrupted. To prevent this, applications call 
  5634. DosShutdown to ensure that the operating system writes the data in the cache to 
  5635. the disk and prevents any further data from being cached. The user can then 
  5636. safely power-off the system. 
  5637.  
  5638. Note:  This call prepares all file systems and device drivers for system 
  5639.        shutdown. Therefore, it must be called only when system shutdown is 
  5640.        about to occur. The user and applications will no longer have access to 
  5641.        their storage devices. 
  5642.  
  5643. The following code fragment locks out changes to all file systems, and writes 
  5644. system buffers to the disk in preparation for turning off power to the system. 
  5645.  
  5646.     #define INCL_DOSFILEMGR   /* File System values */
  5647.     #include <os2.h>
  5648.     #include <stdio.h>
  5649.  
  5650.     ULONG   Reserved;   /* Reserved, must be zero        */
  5651.     APIRET  rc;         /* Return code                   */
  5652.  
  5653.     Reserved = 0;       /* Reserved, must be set to zero */
  5654.  
  5655.     rc = DosShutdown(Reserved);
  5656.  
  5657.     if (rc != 0) {
  5658.         printf("DosShutdown error: return code = %ld", rc);
  5659.         return;
  5660.     }
  5661.  
  5662.  
  5663. Preparing to Turn Off Power to the System 
  5664.  
  5665.  
  5666. ΓòÉΓòÉΓòÉ 8.2.7. Writing Cache Buffers ΓòÉΓòÉΓòÉ
  5667.  
  5668. DosResetBuffer is used to write to disk (flush) the file system's cache buffers 
  5669. for a specific file handle. When called with a value of hex FFFF for the file 
  5670. handle, DosResetBuffer writes all files belonging to the requesting process to 
  5671. disk (this usage should be administered with care, so the user is not burdened 
  5672. with insertion and removal of a large number of removable media volumes). 
  5673.  
  5674. When DosResetBuffer is called for single file handle, the directory entry for 
  5675. the file is updated as if the file had been closed. However, the file remains 
  5676. open. 
  5677.  
  5678. DosResetBuffer can also be called with the name of a named pipe. The process 
  5679. that calls DosResetBuffer is blocked at one end of the pipe until all data it 
  5680. has written has been successfully read by the process at the other end of the 
  5681. pipe. This enables communicating processes to synchronize their dialogs. 
  5682.  
  5683. The following code fragment opens a file, writes some data to the file's 
  5684. buffer, then writes the file's system buffer to the disk. 
  5685.  
  5686.  
  5687.     #define INCL_DOSFILEMGR   /* File System values */
  5688.     #include <os2.h>
  5689.     #include <stdio.h>
  5690.  
  5691.     #define OPEN_FILE 0x01
  5692.     #define CREATE_FILE 0x10
  5693.     #define FILE_ARCHIVE 0x20
  5694.     #define FILE_EXISTS OPEN_FILE
  5695.     #define FILE_NOEXISTS CREATE_FILE
  5696.     #define DASD_FLAG 0
  5697.     #define INHERIT 0x80
  5698.     #define WRITE_THRU 0
  5699.     #define FAIL_FLAG 0
  5700.     #define SHARE_FLAG 0x10
  5701.     #define ACCESS_FLAG 0x02
  5702.  
  5703.     #define FILE_NAME "test.dat"
  5704.     #define FILE_SIZE 800L
  5705.     #define FILE_ATTRIBUTE FILE_ARCHIVE
  5706.     #define EABUF 0L
  5707.  
  5708.     HFILE   FileHandle;
  5709.     ULONG   Wrote;
  5710.     ULONG   Action;
  5711.     PSZ     FileData[100];
  5712.     APIRET  rc;              /* Return code */
  5713.  
  5714.     Action = 2;
  5715.     strcpy(FileData, "Data...");
  5716.  
  5717.     rc = DosOpen(FILE_NAME,                      /* File path name          */
  5718.                  &FileHandle,                    /* File handle             */
  5719.                  &Action,                        /* Action taken            */
  5720.                  FILE_SIZE,                      /* File primary allocation */
  5721.                  FILE_ATTRIBUTE,                 /* File attribute          */
  5722.                  FILE_EXISTS | FILE_NOEXISTS,    /* Open function type      */
  5723.                  DASD_FLAG | INHERIT |           /* Open mode of the file   */
  5724.                  WRITE_THRU | FAIL_FLAG |
  5725.                  SHARE_FLAG | ACCESS_FLAG,
  5726.                  EABUF);                         /* No extended attributes  */
  5727.  
  5728.     if (rc != 0) {
  5729.         printf("DosOpen error: return code = %ld", rc);
  5730.         return;
  5731.     }
  5732.  
  5733.     rc = DosWrite(FileHandle,           /* File handle   */
  5734.                   (PVOID) FileData,     /* User buffer   */
  5735.                   sizeof(FileData),     /* Buffer length */
  5736.                   &Wrote);              /* Bytes written */
  5737.  
  5738.     if (rc != 0) {
  5739.         printf("DosWrite error: return code = %ld", rc);
  5740.         return;
  5741.     }
  5742.  
  5743.     rc = DosResetBuffer(FileHandle);    /* File handle   */
  5744.  
  5745.     if (rc != 0) {
  5746.         printf("DosResetBuffer error: return code = %ld", rc);
  5747.         return;
  5748.     }
  5749.  
  5750.  
  5751. Writing the Buffers to the Device 
  5752.  
  5753.  
  5754. ΓòÉΓòÉΓòÉ 8.3. Summary of Functions and Data Structures Used in File System Management ΓòÉΓòÉΓòÉ
  5755.  
  5756. Following are the OS/2 functions and data structures used in file system 
  5757. management. 
  5758.  
  5759. File System Functions 
  5760.  
  5761. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  5762. ΓöéFunction                ΓöéDescription                         Γöé
  5763. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5764. ΓöéDosFSAttach             ΓöéAttaches a file system to a device. Γöé
  5765. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5766. ΓöéDosFSCtl                ΓöéCommunicates with a file system.    Γöé
  5767. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5768. ΓöéDosQueryFSAttach        ΓöéObtains information about an        Γöé
  5769. Γöé                        Γöéattached file system.               Γöé
  5770. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5771. ΓöéDosQueryFileInfo        ΓöéObtains volume information.         Γöé
  5772. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5773. ΓöéDosResetBuffer          ΓöéWrites (flushes) cache buffers to   Γöé
  5774. Γöé                        Γöédisk.                               Γöé
  5775. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5776. ΓöéDosSetFSInfo            ΓöéSets volume information.            Γöé
  5777. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5778. ΓöéDosShutdown             ΓöéPrepares file system for system     Γöé
  5779. Γöé                        Γöéshutdown.                           Γöé
  5780. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  5781.  
  5782. File System Data Structures 
  5783.  
  5784. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  5785. ΓöéData Structure          ΓöéDescription                         Γöé
  5786. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5787. ΓöéFSALLOCATE              ΓöéUsed by a DosQueryFileInfo level 1  Γöé
  5788. Γöé                        Γöécall;  returns the size of the      Γöé
  5789. Γöé                        Γöévolume and the number of free bytes.Γöé
  5790. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5791. ΓöéFSINFO                  ΓöéUsed by a DosQueryFileInfo level 2  Γöé
  5792. Γöé                        Γöécall;  returns the serial ID and    Γöé
  5793. Γöé                        Γöélabel of the volume.                Γöé
  5794. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  5795. ΓöéFSQBUFFER2              ΓöéUsed by DosQueryFSAttach;  returns  Γöé
  5796. Γöé                        Γöéwhich file system is managing an    Γöé
  5797. Γöé                        Γöéattachable device.                  Γöé
  5798. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  5799.  
  5800.  
  5801. ΓòÉΓòÉΓòÉ 9. Memory Management ΓòÉΓòÉΓòÉ
  5802.  
  5803. This chapter describes the memory management features and functions of the OS/2 
  5804. operating system. The key features of OS/2 memory management are paged virtual 
  5805. memory and a 32-bit linear (flat) address space that is mapped through page 
  5806. tables to physical memory. An OS/2 application can allocate memory for its own 
  5807. use or to be shared with other applications. 
  5808.  
  5809. The following topics are related to the information in this chapter: 
  5810.  
  5811. o Exception Handling 
  5812. o Program Execution and Control 
  5813. o Semaphores 
  5814. o Queues. 
  5815.  
  5816.  
  5817. ΓòÉΓòÉΓòÉ 9.1. About Memory Management ΓòÉΓòÉΓòÉ
  5818.  
  5819. The OS/2 operating system offers developers a 32-bit, linear (flat) memory 
  5820. address space. The OS/2 operating system uses a paged memory structure. The 
  5821. operating system allocates, protects, and manipulates memory in terms of pages. 
  5822.  
  5823.  
  5824. ΓòÉΓòÉΓòÉ 9.1.1. Process Address Space ΓòÉΓòÉΓòÉ
  5825.  
  5826. The OS/2 memory allocation functions return a 32-bit pointer to the allocated 
  5827. memory object. While a 32-bit pointer is sufficient to address the entire 4 
  5828. gigabyte global address space, applications can access only the first 512MB of 
  5829. linear memory, called the process address space. Of this 512MB process address 
  5830. space, a minimum of 64MB is reserved for shared memory regions, leaving 448MB. 
  5831. Of this 448MB, some will be used by the application itself and a small amount 
  5832. will be taken by operating system overhead. The remainder is available for 
  5833. allocation. The amount of memory that can actually be committed and used is, of 
  5834. course, determined by the physical memory and hard disk space available on the 
  5835. machine. 
  5836.  
  5837. Keep in mind that the amount of memory that can be committed for actual use is 
  5838. limited by the amount of physical memory and free hard disk space that is 
  5839. available on the computer on which the application is executing. 
  5840.  
  5841.  
  5842. ΓòÉΓòÉΓòÉ 9.1.2. Memory Objects ΓòÉΓòÉΓòÉ
  5843.  
  5844. Applications allocate and manipulate memory in terms of memory objects. A 
  5845. memory object consists of one or more pages of memory. An OS/2 application can 
  5846. allocate any number of memory objects, within the following limits: 
  5847.  
  5848. o the physical memory in the system 
  5849. o the free hard disk space on the hard disk containing the swap file 
  5850. o the 512MB process address space limit (see Process Address Space). 
  5851. When requesting memory, the size of the memory object is rounded up to the next 
  5852. higher multiple of 4KB. An application can suballocate a memory object into 
  5853. memory blocks whose size can range from 1 byte to the size of the memory 
  5854. object. 
  5855.  
  5856. Memory objects have the following characteristics: 
  5857.  
  5858. o They are not relocatable. 
  5859. o They are allocated in units of 4KB. One 4KB unit is called a page. 
  5860. o They can be larger than 64KB in size. 
  5861.  
  5862.  
  5863. ΓòÉΓòÉΓòÉ 9.1.3. Memory Pages ΓòÉΓòÉΓòÉ
  5864.  
  5865. The operating system allocates and commits memory objects in pages. A memory 
  5866. page is a 4KB (4096 bytes) piece of memory. Memory access protection is also 
  5867. done on a page-basis, rather than the segment-based protection used in previous 
  5868. versions of the operating system. 
  5869.  
  5870. A page range is a linearly contiguous group of pages within a memory object. A 
  5871. page range can be: 
  5872.  
  5873. o the entire memory object, 
  5874. o part of the memory object, or 
  5875. o a single page within a memory object. 
  5876.  
  5877. If an application requests 512 bytes of memory, it will receive a 32-bit 
  5878. pointer to a 4KB page. All 4096 bytes are available to the application, even 
  5879. though the request specified only 512 bytes. If an application requests 62000 
  5880. bytes, it will receive a pointer to a 65536-byte (64KB, 16-page) object. Again, 
  5881. all 65536 bytes are available for use. 
  5882.  
  5883. Each page in the virtual address space of the process is either free 
  5884. (unallocated), private (available only to the process that allocated it), or 
  5885. shared (memory that is shared between processes). 
  5886.  
  5887. Each page within a memory object can be in one of two states, either 
  5888. uncommitted (that is, the linear address range has been reserved, but is not 
  5889. yet backed by physical storage) or committed (physical storage has been 
  5890. allotted for the logical address range). 
  5891.  
  5892. Access to a committed page is controlled by the page's access protection 
  5893. attribute. These protection attributes are read access, write access, execute 
  5894. access (on the 80386, this is the same as read access), and guard page access. 
  5895.  
  5896. An uncommitted page is not accessible. 
  5897.  
  5898.  
  5899. ΓòÉΓòÉΓòÉ 9.1.4. Memory Overcommitment and Swapping ΓòÉΓòÉΓòÉ
  5900.  
  5901. Memory overcommitment occurs when applications allocate and commit more memory 
  5902. than is actually available in the computer. The operating system handles memory 
  5903. overcommitment by copying memory to the system swap file, SWAPPER.DAT, on the 
  5904. hard disk then reusing the memory for another allocation. The operating system 
  5905. copies as many pages of memory as are necessary to make room for the new 
  5906. allocation. The swapped memory can be retrieved the next time it is accessed; 
  5907. at that time, some other memory might be written to the swap file. 
  5908.  
  5909. The operating system selects the memory to swap based on when it was last used. 
  5910. The page that is least-recently-used, that is, the page that has gone the 
  5911. longest since its last access, is the page chosen to swap to disk. 
  5912.  
  5913. Swapping is transparent to an application, although excessive swapping can 
  5914. cause an application to run slowly. 
  5915.  
  5916. Through swapping, the OS/2 operating system enables applications to allocate 
  5917. more memory than actually exists in the computer, bounded only by the amount of 
  5918. free space on the hard disk that contains the swap file. 
  5919.  
  5920.  
  5921. ΓòÉΓòÉΓòÉ 9.1.5. User Configuration of Memory Swapping ΓòÉΓòÉΓòÉ
  5922.  
  5923. Although an application cannot control swapping, the user can specify whether 
  5924. the system can swap memory by including the MEMMAN command in the CONFIG.SYS 
  5925. file. 
  5926.  
  5927. If the MEMMAN command specifies SWAP, the operating system writes selected 
  5928. memory pages to the SWAPPER.DAT file whenever insufficient physical memory 
  5929. exists to satisfy an allocation request. This is the default choice. If the 
  5930. MEMMAN command specifies NOSWAP, the operating system does not swap memory. 
  5931.  
  5932. Note:  Be aware that disabling swapping will severely limit the number of 
  5933.        applications that the user will be able to run concurrently; if there is 
  5934.        not enough physical memory present, the operating system might not even 
  5935.        boot. 
  5936.  
  5937. The exact amount of memory available to an application depends on the amount of 
  5938. physical memory in the machine and the amount of free disk space on the 
  5939. partition that contains the SWAPPER.DAT file. The location of the SWAPPER.DAT 
  5940. file can be specified by including the SWAPPATH command in the CONFIG.SYS file. 
  5941. The SWAPPATH command specifies the location of SWAPPER.DAT and the amount of 
  5942. free space to reserve on the disk. The operating system adjusts the size of 
  5943. SWAPPER.DAT as necessary, leaving other files on the drive and the requested 
  5944. free space untouched. 
  5945.  
  5946.  
  5947. ΓòÉΓòÉΓòÉ 9.1.6. Memory Allocation and Commitment ΓòÉΓòÉΓòÉ
  5948.  
  5949. When an application asks the operating system to allocate memory, a linear 
  5950. address range is reserved. The range is not backed by physical memory until the 
  5951. memory is committed. Commitment assigns physical memory to the linear address 
  5952. range. 
  5953.  
  5954. A memory object that is allocated, but not committed is called a sparse memory 
  5955. object. A sparse memory object must be committed before it can be used. An 
  5956. attempt to read from or write to uncommitted memory will cause an access 
  5957. violation. 
  5958.  
  5959. An application can ask the operating system to commit the memory at the same 
  5960. time it is allocated, thus making it immediately usable, or the memory can be 
  5961. committed at a later time. If the application commits the memory at the same 
  5962. time the memory is allocated, the entire memory object is committed. If the 
  5963. application commits the memory at a later time, it can commit the entire sparse 
  5964. memory object or only commit a portion of it. 
  5965.  
  5966. When multiple pages are committed at the same time (a page range), the pages 
  5967. will have sequential linear addresses. 
  5968.  
  5969. Managing Memory Allocation and Commitment 
  5970. The recommended way to manage memory is to make a large memory allocation early 
  5971. in program execution, then to commit or suballocate memory as the need occurs. 
  5972.  
  5973. The initial allocation should be for as much space as you expect to use during 
  5974. program execution. Allocation without commitment does not actually use any 
  5975. physical memory, so there is no waste involved in allocating several megabytes. 
  5976.  
  5977. After the memory object is allocated, the application uses one of two ways to 
  5978. manage the memory object: 
  5979.  
  5980. o commit and decommit the memory as it is required 
  5981. o set up the memory object as a heap and suballocate memory from the heap. 
  5982. Committing and decommitting memory gives the application more control over the 
  5983. process, but the application will have to keep track of which pages are 
  5984. committed and which pages are not. When suballocating memory from a heap, the 
  5985. application can have the operating system track commitment and decommitment of 
  5986. physical memory pages, so the application does not have to. If you want 
  5987. DosSubAllocMem to manage the commitment of the pages spanned by the heap, all 
  5988. of the pages spanned by the memory object must be uncommitted initially. 
  5989.  
  5990. Remember, no matter how much memory is originally allocated, the amount that an 
  5991. application will ultimately be able to commit and use is limited by the amount 
  5992. of physical memory and free disk space available on the machine. 
  5993.  
  5994. Applications are not limited to a single large allocation of memory-other 
  5995. memory allocations can be made as necessary during execution-but large 
  5996. allocations and small commitments or suballocations are the most efficient way 
  5997. to manage memory. 
  5998.  
  5999.  
  6000. ΓòÉΓòÉΓòÉ 9.1.7. Memory Resizing and Reallocation ΓòÉΓòÉΓòÉ
  6001.  
  6002. In earlier versions of the operating system, an application could increase or 
  6003. decrease the size of an allocated memory segment by reallocating the segment. 
  6004.  
  6005. Memory objects cannot be resized. Instead, an application should allocate a 
  6006. sparse memory object of whatever size might be necessary, then commit or 
  6007. decommit portions of the object. 
  6008.  
  6009. If the amount of memory required cannot be determined at the time the memory is 
  6010. allocated, the application should allocate a sparse memory object large enough 
  6011. to meet the largest memory requirement. The application can then change the 
  6012. amount of committed memory as necessary. 
  6013.  
  6014. For example, if you anticipate your application will use around 512KB of memory 
  6015. for most purposes, but might use 5MB under certain circumstances, you might 
  6016. take the following steps: 
  6017.  
  6018. o During program initialization, use DosAllocMem to allocate 5MB. 
  6019.  
  6020. o Commit the first 512KB (or some part of it) using DosSetMem. 
  6021.  
  6022. o Proceed with normal processing. 
  6023.  
  6024. o If extra memory is required occasionally, commit it and decommit it using 
  6025.   DosSetMem. 
  6026.  
  6027. o When the situation arises that the application requires the full 5MB, commit 
  6028.   it at that time, using DosSetMem, then decommit it after you are finished 
  6029.   with it, also using DosSetMem. 
  6030.  
  6031. o When the application is finished with the memory, use DosFreeMem to release 
  6032.   the memory back to the system. 
  6033.  
  6034.  
  6035. ΓòÉΓòÉΓòÉ 9.1.8. Memory Protection ΓòÉΓòÉΓòÉ
  6036.  
  6037. When an application allocates a memory object, it can specify the type of 
  6038. access to allow to the object. Memory access protection provides a program with 
  6039. control over the type of access that its threads have to a page of memory. 
  6040.  
  6041. Access protection can only be defined for committed pages of memory and is 
  6042. initially set at the time the memory is committed. Different pages within the 
  6043. same memory object can have different access attributes and access attributes 
  6044. can be changed on a page-by-page basis at any time. 
  6045.  
  6046. An application can request any combination of the following access protection 
  6047. attributes: 
  6048.  
  6049. Memory Access Protection Attributes 
  6050.  
  6051. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  6052. ΓöéAccess              ΓöéDefined Constant    ΓöéDescription         Γöé
  6053. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6054. ΓöéRead Access         ΓöéPAG_READ            ΓöéThe object can be   Γöé
  6055. Γöé                    Γöé                    Γöéread from, but not  Γöé
  6056. Γöé                    Γöé                    Γöéwritten to.         Γöé
  6057. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6058. ΓöéWrite Access        ΓöéPAG_WRITE           ΓöéThe object can be   Γöé
  6059. Γöé                    Γöé                    Γöéwritten to.  On the Γöé
  6060. Γöé                    Γöé                    Γöé80386               Γöé
  6061. Γöé                    Γöé                    Γöémicroprocessor,     Γöé
  6062. Γöé                    Γöé                    Γöéwrite access impliesΓöé
  6063. Γöé                    Γöé                    Γöéboth read and       Γöé
  6064. Γöé                    Γöé                    Γöéexecute access.     Γöé
  6065. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6066. ΓöéExecute Access      ΓöéPAG_EXECUTE         ΓöéThis is equivalent  Γöé
  6067. Γöé                    Γöé                    Γöéto read access on   Γöé
  6068. Γöé                    Γöé                    Γöéthe 80386.          Γöé
  6069. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6070. ΓöéGuard Page Access   ΓöéPAG_GUARD           ΓöéCauses a            Γöé
  6071. Γöé                    Γöé                    Γöéguard-page-entered  Γöé
  6072. Γöé                    Γöé                    Γöéexception to be     Γöé
  6073. Γöé                    Γöé                    Γöéraised in a process Γöé
  6074. Γöé                    Γöé                    Γöéthat attempts to    Γöé
  6075. Γöé                    Γöé                    Γöéaccess the memory.  Γöé
  6076. Γöé                    Γöé                    ΓöéThis exception can  Γöé
  6077. Γöé                    Γöé                    Γöébe ignored or       Γöé
  6078. Γöé                    Γöé                    Γöéhandled by the      Γöé
  6079. Γöé                    Γöé                    Γöéapplication's       Γöé
  6080. Γöé                    Γöé                    Γöéexception handler,  Γöé
  6081. Γöé                    Γöé                    Γöéif one is           Γöé
  6082. Γöé                    Γöé                    Γöéregistered.         Γöé
  6083. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6084.  
  6085. The guard page attribute is intended to provide automatic stack growth and 
  6086. stack limit checking. An application can also use it in other data structures, 
  6087. such as arrays. For example, if an application is using an array of 4096 bytes 
  6088. (one page), the application can allocate and commit two pages, one with read 
  6089. and write access and one designated as a guard page. If the application tries 
  6090. to write past the end of the array a page guard exception will be generated. 
  6091.  
  6092. Any reference-read, write, or execute-to a guard page causes an access 
  6093. violation (page fault) to be generated. This fault causes a Guard Page Entered 
  6094. exception to occur for the thread that referred to the guard page. The 
  6095. exception can be handled by the exception handler of the process, if one is 
  6096. registered. If the process does not have an exception handler registered, the 
  6097. operating system's default exception handler will handle the exception. The 
  6098. default action by the system exception handler is to convert the page from a 
  6099. guard page to a committed page, then try to mark the next page in memory as a 
  6100. guard page. If the system is not successful in marking the next page as a guard 
  6101. page, an Unable-To-Grow-Stack exception occurs. The thread is allowed to 
  6102. continue execution, but must be aware that it has at most 4KB of stack 
  6103. remaining. 
  6104.  
  6105.  
  6106. ΓòÉΓòÉΓòÉ 9.1.9. Obtaining Information about a Page Range ΓòÉΓòÉΓòÉ
  6107.  
  6108. DosQueryMem is used to obtain information about a range of pages within the 
  6109. virtual address space of the current process. 
  6110.  
  6111. Each page in the virtual address space of a process is either free, private, or 
  6112. shared. 
  6113.  
  6114. Each page within a memory object can be in one of two states, either committed 
  6115. or uncommitted. 
  6116.  
  6117. A committed page has its access controlled by an access protection attribute. 
  6118. These protection attributes are read protection (PAG_READ), write protection 
  6119. (PAG_WRITE), execute protection (PAG_EXECUTE), and guard page protection 
  6120. (PAG_GUARD). 
  6121.  
  6122.  
  6123. ΓòÉΓòÉΓòÉ 9.1.10. Protection Violations ΓòÉΓòÉΓòÉ
  6124.  
  6125. The operating system fully utilizes the memory protection capabilities of the 
  6126. 80386 microprocessor. The operating system grants an application access to a 
  6127. memory object only if the object has been explicitly allocated by the 
  6128. application or made available for use by the application. 
  6129.  
  6130. If an application attempts to access memory that it is not assigned, the system 
  6131. interrupts the application and executes the exception handling routine for 
  6132. protection violations. Protection violations can be handled by the application 
  6133. (in its own exception handling routines) or by the operating system. If the 
  6134. protection violation is handled by the operating system, the system exception 
  6135. handling routine determines the cause of the exception, displays an error 
  6136. message, and then terminates the application. 
  6137.  
  6138. It is usually not possible for an application to recover from a protection 
  6139. violation. Therefore, programmers should ensure that all pointers are valid. 
  6140. Because protection violations commonly occur during application debugging, each 
  6141. message displayed for a protection violation includes the contents of the 
  6142. registers when the violation occurred. If the violation occurred as a result of 
  6143. passing an invalid pointer to a memory function, an error code is returned by 
  6144. the memory function. 
  6145.  
  6146. In earlier versions of the operating system, protection violations could be 
  6147. used to find bugs when an application accessed memory that was not allocated to 
  6148. the application. This approach will no longer work because memory objects can 
  6149. be larger than the size requested by the application because the memory objects 
  6150. are allocated on 4KB page boundaries. For example, a pointer to the 513th byte 
  6151. of a 512 byte memory object is valid and does not cause a protection violation. 
  6152. This means that programmers cannot always rely on protection violations to spot 
  6153. memory addressing errors. 
  6154.  
  6155.  
  6156. ΓòÉΓòÉΓòÉ 9.1.11. Memory Suballocation and Using Heaps ΓòÉΓòÉΓòÉ
  6157.  
  6158. There are times when a process requires only small amounts of memory rather 
  6159. than an entire memory object. It would be wasteful to allocate an entire page 
  6160. of memory when only a few bytes are necessary, so a mechanism is provided for 
  6161. applications to allocate a large block of memory and then suballocate portions 
  6162. of the memory as necessary to fulfill small requests from an application. This 
  6163. is done by creating a heap. 
  6164.  
  6165. A heap is a region of storage within a memory object from which an application 
  6166. can allocate blocks of memory. A memory block is a piece of memory within a 
  6167. heap. The size of the memory block is rounded up to the next higher multiple of 
  6168. 8 bytes. 
  6169.  
  6170. Because the operating system allocates a 4KB page for each memory allocation, 
  6171. using a heap to suballocate amounts of memory smaller than 4KB is more 
  6172. efficient than using DosAllocMem. 
  6173.  
  6174. When an application creates a heap, it can have the operating system track the 
  6175. committing and decommitting of memory within the heap. When the application 
  6176. commits and decommits memory itself, it has to keep track of the access state 
  6177. of each page as they are accessed. 
  6178.  
  6179. Applications use DosSubSetMem to initialize a memory object for suballocation, 
  6180. then use DosSubAllocMem and DosSubFreeMem to allocate and free the memory. 
  6181.  
  6182. Memory is still committed in pages when an application uses suballocation. If 
  6183. the application suballocates 512 bytes, 4096 bytes will be committed. Accessing 
  6184. the 513th byte will not cause a protection violation, but you could be 
  6185. accessing memory that was suballocated by another thread in the process. 
  6186.  
  6187.  
  6188. ΓòÉΓòÉΓòÉ 9.1.12. Shared Memory ΓòÉΓòÉΓòÉ
  6189.  
  6190. Shared memory is memory that two or more applications can read from and write 
  6191. to. Shared memory is prepared in such a way that any application can receive a 
  6192. pointer to the memory and access the data. Applications must explicitly request 
  6193. access to shared memory; the shared memory is protected from applications that 
  6194. are not granted access. 
  6195.  
  6196. There are two kinds of shared memory:  named and unnamed. For named shared 
  6197. memory, any application that knows the name of the shared memory can access it. 
  6198. For unnamed shared memory, a pointer to the shared memory must be passed from 
  6199. the process that created the shared memory to the process being given access. 
  6200. Access can be granted to any application; it is not necessary that the process 
  6201. being granted access be related (parent-child) to the application that created 
  6202. the shared memory. 
  6203.  
  6204. Since memory sharing is done by sharing linear addresses, the linear address 
  6205. range of the shared memory object is reserved in all process address spaces. 
  6206.  
  6207. There are two basic methods of managing shared memory: 
  6208.  
  6209. o In one method, two or more applications share the same memory at the same 
  6210.   time. These applications read from and write to the memory object, usually 
  6211.   controlling access to the memory by using a semaphore. 
  6212.  
  6213. o In the other method of managing shared memory, one application prepares data 
  6214.   in memory, then passes that memory to another application for further 
  6215.   processing. The first application releases the memory after passing it along, 
  6216.   so that only one application accesses the memory at a time. 
  6217.  
  6218.  
  6219. ΓòÉΓòÉΓòÉ 9.2. Using Memory Management ΓòÉΓòÉΓòÉ
  6220.  
  6221. This section describes how to use the OS/2 memory management functions and 
  6222. configuration commands to control the use of memory for OS/2 applications. 
  6223.  
  6224. Note:  In the example code fragments that follow, error checking was left out 
  6225.        to conserve space. Applications should always check the return code that 
  6226.        the functions return. Control Program functions return an APIRET value. 
  6227.        A return code of 0 indicates success. If a non-zero value is returned, 
  6228.        an error occurred. 
  6229.  
  6230.  
  6231. ΓòÉΓòÉΓòÉ 9.2.1. Allocating Private Memory ΓòÉΓòÉΓòÉ
  6232.  
  6233. An application can allocate regions of storage within the virtual address space 
  6234. of the process. Such an allocated region is called a memory object. 
  6235.  
  6236. DosAllocMem is used to allocate a memory object. You specify a variable to 
  6237. receive the pointer that will address the new object, the amount of memory 
  6238. needed, and the allocation attributes and access protection attributes of the 
  6239. new memory object. When choosing the size of the memory object to allocate, 
  6240. remember that the maximum size of the memory object is defined when it is 
  6241. allocated, and memory objects cannot be resized. 
  6242.  
  6243. When applications call DosAllocMem, the operating system reserves a range of 
  6244. private pages large enough to fulfill the specified allocation request from the 
  6245. private virtual address space of the subject process. 
  6246.  
  6247. DosAllocMem will reserve this linear space and return zero if the allocation 
  6248. was successful. If it was unsuccessful, DosAllocMem will return an error code. 
  6249. An application should always test the return value before attempting to use the 
  6250. memory. 
  6251.  
  6252. The following code fragment requests an allocation of 512 bytes. Remember that 
  6253. 4096 bytes will actually be allocated for this request: 
  6254.  
  6255.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6256.     #include <os2.h>
  6257.  
  6258.     PBYTE   pb;
  6259.     APIRET  rc;
  6260.  
  6261.     rc = DosAllocMem((PVOID *) &pb, 512, fALLOC);
  6262.          /* pb receives the base address of the 4KB memory object     */
  6263.  
  6264.     if (!rc) {           /* If the allocation was successful, rc == 0 */
  6265.         *pb = 3000;      /* Use the allocated memory                  */
  6266.     }
  6267.  
  6268.  
  6269. Requesting 512 Bytes of Memory 
  6270.  
  6271. In this example, DosAllocMem returns a 32-bit pointer to a 4096 byte committed 
  6272. memory object and allows the application to write to and read from the memory. 
  6273. This pointer is valid only for the 4096 bytes allocated by the system. An 
  6274. attempt to use the pointer outside the allocated memory will cause a protection 
  6275. violation. 
  6276.  
  6277.  
  6278. ΓòÉΓòÉΓòÉ 9.2.2. Committing and Decommitting Page Ranges ΓòÉΓòÉΓòÉ
  6279.  
  6280. If an application allocates a sparse memory object, no physical memory location 
  6281. is committed for the object. Memory in a sparse object must be committed before 
  6282. it can be used. DosSetMem is used to commit or decommit a range of previously 
  6283. allocated pages in a private or shared memory object. Applications can make 
  6284. specific address ranges within a memory object valid or invalid. Commitment and 
  6285. decommitment always take place in multiples of one or more pages. 
  6286.  
  6287. Applications can also use DosSetMem to change the access protection attributes 
  6288. of a range of pages within a memory object. 
  6289.  
  6290. The following code fragment requests allocation of 2MB of uncommitted memory 
  6291. and then commits 4096 bytes of the memory: 
  6292.  
  6293.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6294.     #include <os2.h>
  6295.  
  6296.     APIRET  rc;
  6297.     PBYTE   pb;
  6298.  
  6299.     /* Allocate 16KB object */
  6300.     rc = DosAllocMem((PVOID *) &pb, 2097152, PAG_READ | PAG_WRITE);
  6301.  
  6302.     /* Commit 4KB           */
  6303.     rc = DosSetMem(pb, 4096, PAG_COMMIT | PAG_DEFAULT);
  6304.  
  6305.  
  6306. Allocating Uncommitted Memory and Committing Part of It 
  6307.  
  6308. An application can also allocate a large committed object and then decommit 
  6309. portions of it as they are no longer needed. Decommitment, like commitment, is 
  6310. done on page boundaries; an application can decommit no less than a 4096 byte 
  6311. page. 
  6312.  
  6313. The following code fragment allocates 16384 bytes of committed memory and then 
  6314. decommits the first 4096 bytes of the memory: 
  6315.  
  6316.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6317.     #include <os2.h>
  6318.  
  6319.     APIRET  rc;
  6320.     PBYTE   pb;
  6321.  
  6322.     rc = DosAllocMem((PVOID *) &pb, 16384, fALLOC);    /* Allocate 16 K object */
  6323.  
  6324.     rc = DosSetMem(pb, 4096, PAG_DECOMMIT);            /* Decommit 4KB         */
  6325.  
  6326.  
  6327. Allocating Committed Memory and Decommitting Part of It 
  6328.  
  6329. After memory is decommitted, an attempt to access the decommitted memory will 
  6330. cause a protection violation. 
  6331.  
  6332. You cannot pass an argument that crosses multiple memory objects. The function 
  6333. will return an error. 
  6334.  
  6335.  
  6336. ΓòÉΓòÉΓòÉ 9.2.3. Establishing Access Protection ΓòÉΓòÉΓòÉ
  6337.  
  6338. When an OS/2 application commits a memory object, it specifies the types of 
  6339. access permitted for the memory object. This can be done at the same time the 
  6340. memory object is allocated, with DosAllocMem, or at a later time, using 
  6341. DosSetMem. 
  6342.  
  6343. Any combination of read, write, execute, or guard-page access can be set, but 
  6344. at least read or write access must be specified when the memory object is 
  6345. committed; it is not possible to commit an object with no access protection 
  6346. attributes. 
  6347.  
  6348. The application can also use DosSetMem to change the access permission of pages 
  6349. within a previously committed memory object. An application can permit read 
  6350. access to one page of the memory object and write access to the rest. 
  6351.  
  6352. When using DosSetMem, all the pages in the range being changed must be either 
  6353. committed or decommitted. 
  6354.  
  6355. The following code fragment commits a region of two pages within a previously 
  6356. allocated memory object, and sets read-only access rights for the region. 
  6357. Assume that the base address for DosSetMem was previously obtained by the 
  6358. process. 
  6359.  
  6360.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6361.     #include <os2.h>
  6362.     #include <stdio.h>
  6363.  
  6364.     PVOID   BaseAddress;      /* Pointer to the range of pages to be changed */
  6365.     ULONG   RegionSize;       /* Size, in bytes, of the region to be changed */
  6366.     ULONG   AttributeFlags;   /* Flag describing the page range              */
  6367.     APIRET  rc;               /* Return code                                 */
  6368.  
  6369.     RegionSize = 8192;        /* Specify a two-page region                   */
  6370.  
  6371.     AttributeFlags = PAG_COMMIT | PAG_READ;
  6372.  
  6373.     rc = DosSetMem(BaseAddress, RegionSize, AttributeFlags);
  6374.  
  6375.     if (rc != 0) {
  6376.         printf("DosSetMem error: return code = %ld", rc);
  6377.         return;
  6378.     }
  6379.  
  6380.  
  6381. Setting Read-Only Access for a Region 
  6382.  
  6383.  
  6384. ΓòÉΓòÉΓòÉ 9.2.4. Querying Memory Object Information ΓòÉΓòÉΓòÉ
  6385.  
  6386. DosQueryMem is used to determine the allocation state and access protection for 
  6387. a specified memory object. The application can query an entire memory object or 
  6388. a range of pages within an object. 
  6389.  
  6390. The following code fragment uses DosQueryMem to ensure that memory is committed 
  6391. before the application attempts to use the memory: 
  6392.  
  6393.     #define  INCL_DOSMEMMGR   /* Memory Manager values  */
  6394.     #include <os2.h>
  6395.     #define HF_STDOUT 1       /* Standard output handle */
  6396.  
  6397.     PBYTE   pb;       /* Base address of an allocated object */
  6398.     ULONG   ulSize, flFlags, ulWritten;
  6399.     APIRET  rc;       /* Return Code                         */
  6400.  
  6401.     ulSize = 4096;
  6402.  
  6403.     rc = DosQueryMem(pb, &ulSize, &flFlags);     /* Queries first 4096 bytes */
  6404.  
  6405.     if (flFlags & PAG_COMMIT) {            /* If memory is committed, use it */
  6406.         rc = DosWrite(HF_STDOUT, "\r\n 4KB is committed.\r\n", 21, &ulWritten);
  6407.     }
  6408.  
  6409.  
  6410. Determining the Allocation State of a Memory Object 
  6411.  
  6412.  
  6413. ΓòÉΓòÉΓòÉ 9.2.5. Freeing Memory ΓòÉΓòÉΓòÉ
  6414.  
  6415. When memory object is no longer needed, the application uses the DosFreeMem 
  6416. function to release the memory. 
  6417.  
  6418. If applications do not release memory, the operating system either swaps the 
  6419. memory to the hard disk (if swapping is enabled) or uses memory that could be 
  6420. used by other applications. If the operating system swaps the memory to the 
  6421. hard disk, the SWAPPER.DAT swap file could become very large. Therefore, 
  6422. applications should release memory as soon as it is no longer needed. Any 
  6423. memory that is still allocated when the application ends is released by the 
  6424. operating system. 
  6425.  
  6426. DosFreeMem frees a private or shared memory object from the virtual address 
  6427. space of the process. The released pages are returned to the system. 
  6428.  
  6429. The following code fragment allocates 8192 bytes of committed memory and then 
  6430. releases the memory: 
  6431.  
  6432.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6433.     #include <os2.h>
  6434.  
  6435.     PBYTE   pb;
  6436.     APIRET  rc;
  6437.  
  6438.     rc = DosAllocMem((PVOID *) &pb, 8192, fALLOC);    /* Allocate 8KB object */
  6439.         .
  6440.         .
  6441.         .
  6442.     rc = DosFreeMem(pb);                              /* Free the object     */
  6443.  
  6444.  
  6445. Allocating and Freeing Memory 
  6446.  
  6447.  
  6448. ΓòÉΓòÉΓòÉ 9.3. Using Suballocation and Heaps ΓòÉΓòÉΓòÉ
  6449.  
  6450. This section describes how you can use DosAllocMem, DosSubSetMem, 
  6451. DosSubAllocMem, DosSubFreeMem, and DosSubUnsetMem to manage a memory heap. 
  6452.  
  6453.  
  6454. ΓòÉΓòÉΓòÉ 9.3.1. Suballocating Memory ΓòÉΓòÉΓòÉ
  6455.  
  6456. DosAllocMem can be used to create a memory heap. 
  6457.  
  6458. Before an application can allocate small portions of the heap, it must use the 
  6459. DosSubSetMem function to set up the memory for suballocation. The size of the 
  6460. heap is rounded up to the next higher multiple of 8 bytes. 
  6461.  
  6462. Then, the application uses DosSubAllocMem to allocate sections of the heap and 
  6463. the DosSubFreeMem function to release the memory. 
  6464.  
  6465. DosSubAllocMem returns a 32-bit pointer to a block of memory. The pointer can 
  6466. be used to access the memory without further modification. 
  6467.  
  6468. The following code fragment sets up 8192 bytes for suballocation and then 
  6469. allocates two small blocks of memory: 
  6470.  
  6471.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6472.     #include <os2.h>
  6473.  
  6474.     APIRET  rc;
  6475.     PBYTE   pbBase, pb1, pb2;
  6476.  
  6477.     rc = DosAllocMem((PVOID *) &pbBase, 8192, fALLOC); /* Allocate 8 K object   */
  6478.  
  6479.     rc = DosSubSetMem(pbBase, DOSSUB_INIT, 8192);      /* Set up object         */
  6480.                                                        /* for suballocation     */
  6481.  
  6482.     rc = DosSubAllocMem(pbBase, (PVOID *) &pb1, 100);  /* Suballocate 100 bytes */
  6483.  
  6484.     rc = DosSubAllocMem(pbBase, (PVOID *) &pb2, 500);  /* Suballocate 500 bytes */
  6485.  
  6486.     rc = DosSubFreeMem(pbBase, pb1, 100);              /* Free 1st suballocation*/
  6487.  
  6488.     rc = DosSubAllocMem(pbBase, (PVOID *) &pb1, 50);   /* Suballocate 50 bytes  */
  6489.  
  6490.  
  6491. Suballocating Memory 
  6492.  
  6493.  
  6494. ΓòÉΓòÉΓòÉ 9.3.2. Increasing the Size of a Heap ΓòÉΓòÉΓòÉ
  6495.  
  6496. DosSubSetMem can also be used to increase the size of a previously initialized 
  6497. heap. The heap size can be increased up to the size of the memory object that 
  6498. contains it. 
  6499.  
  6500. The size of the heap is rounded up to the next higher multiple of 8 bytes. 
  6501.  
  6502. The following code fragment increases the size of a heap. Assume that a memory 
  6503. object was previously allocated for the heap, and that the Offset variable was 
  6504. previously loaded with the virtual address of the memory object. 
  6505.  
  6506.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6507.     #include <os2.h>
  6508.     #include <stdio.h>
  6509.  
  6510.     PVOID   Offset;   /* Address of the heap to be used for suballocation */
  6511.     ULONG   Flags;    /* Flags describing the memory object being resized */
  6512.     ULONG   Size;     /* Size in bytes to increase the size of the heap   */
  6513.     APIRET  rc;       /* Return code                                      */
  6514.  
  6515.     Size = 20000;     /* Indicate a heap size increase of 20000 bytes     */
  6516.  
  6517.     Flags = DOSSUB_GROW | DOSSUB_SPARSE_OBJ;
  6518.  
  6519.     rc = DosSubSetMem(Offset, Flags, Size);
  6520.  
  6521.     if (rc != 0) {
  6522.         printf("DosSubSetMem error: return code = %ld", rc);
  6523.         return;
  6524.     }
  6525.  
  6526.  
  6527. Increasing the Size of Suballocated Memory 
  6528.  
  6529. In this example, the heap is incremented, and that memory commitment is managed 
  6530. internally within subsequent DosSubAllocMem calls. 
  6531.  
  6532. When using DosSubSetMem to increase the size of the heap, the Flags parameter 
  6533. must have the same setting as when the heap was initialized. 
  6534.  
  6535. Note:  Do not call DosSetMem to change the allocation attribute or access 
  6536.        protection attributes of any pages spanned by a memory object that the 
  6537.        suballocation functions are managing. Otherwise, unpredictable results 
  6538.        could occur. 
  6539.  
  6540. Call DosSubUnsetMem when finished with the heap that was set up with 
  6541. DosSubSetMem. This enables the suballocation function to free the resources 
  6542. that it uses to manage the heap. When you are through with the memory object 
  6543. that the heap was part of, use DosFreeMem to free the memory object. 
  6544.  
  6545.  
  6546. ΓòÉΓòÉΓòÉ 9.3.3. Allocating a Block of Memory from a Heap ΓòÉΓòÉΓòÉ
  6547.  
  6548. DosSubAllocMem allocates a block of memory from a heap that was previously 
  6549. initialized by DosSubSetMem. This is used when an application needs an area of 
  6550. memory that is smaller than an entire heap. 
  6551.  
  6552. The size of the memory block is rounded up to the next higher multiple of 8 
  6553. bytes. 
  6554.  
  6555. The following code fragment allocates a block of memory from a heap that was 
  6556. previously initialized by DosSubSetMem. Assume that the Offset variable has 
  6557. been set to the address of the initialized heap already. 
  6558.  
  6559.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6560.     #include <os2.h>
  6561.     #include <stdio.h>
  6562.  
  6563.     PVOID    Offset;        /* The heap to suballocate from                */
  6564.     PPVOID   BlockOffset;   /* Pointer to the variable where the offset of */
  6565.                             /* the suballocated memory block is returned   */
  6566.     ULONG    Size;          /* Size in bytes of the memory block requested */
  6567.     APIRET   rc;            /* Return code                                 */
  6568.  
  6569.     Size = 102;             /* Ask for 102 bytes.  This will be rounded    */
  6570.                             /* to 104 bytes (a multiple of 8 bytes).       */
  6571.  
  6572.     rc = DosSubAllocMem(Offset, &BlockOffset, Size);
  6573.  
  6574.     if (rc != 0) {
  6575.         printf("DosSubAllocMem error: return code = %ld", rc);
  6576.         return;
  6577.     }
  6578.  
  6579.  
  6580. Allocating a Block of Memory from a Heap 
  6581.  
  6582. In this example, the address of the allocated block (from the heap) is stored 
  6583. in the BlockOffset variable. 
  6584.  
  6585. Remember to call DosSubFreeMem to free this block of memory when you are 
  6586. finished with it. 
  6587.  
  6588.  
  6589. ΓòÉΓòÉΓòÉ 9.3.4. Freeing Memory Blocks ΓòÉΓòÉΓòÉ
  6590.  
  6591. DosSubFreeMem frees a block of memory that was previously allocated by 
  6592. DosSubAllocMem. 
  6593.  
  6594. Call DosSubFreeMem to free a block of memory in the heap when you are finished 
  6595. with that memory block. 
  6596.  
  6597. The following code fragment frees a block of memory that was previously 
  6598. allocated from a heap. DosSubFreeMem returns the block to the heap. Assume that 
  6599. the Offset variable has been previously set to the address of the initialized 
  6600. heap, and that the BlockOffset variable has been previously set to the address 
  6601. of the block to be returned to the heap. 
  6602.  
  6603.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6604.     #include <os2.h>
  6605.     #include <stdio.h>
  6606.  
  6607.     PVOID   Offset;        /* Offset of the heap to which the          */
  6608.                            /* block is to be freed                     */
  6609.     PVOID   BlockOffset;   /* Offset of memory block to be freed       */
  6610.     ULONG   Size;          /* Size in bytes of block to be freed       */
  6611.     APIRET  rc;            /* Return code                              */
  6612.  
  6613.     Size = 102;            /* Return 102 bytes.  This will be rounded  */
  6614.                            /* to 104 bytes (a multiple of 8 bytes).    */
  6615.  
  6616.     rc = DosSubFreeMem(Offset, BlockOffset, Size);
  6617.  
  6618.     if (rc != 0) {
  6619.         printf("DosSubFreeMem error: return code = %ld", rc);
  6620.         return;
  6621.     }
  6622.  
  6623.  
  6624. Freeing a Block of Memory from a Heap 
  6625.  
  6626.  
  6627. ΓòÉΓòÉΓòÉ 9.3.5. Ending the Use of the Heap ΓòÉΓòÉΓòÉ
  6628.  
  6629. DosSubUnsetMem terminates the use of a heap within a memory object. All calls 
  6630. to DosSubSetMem must eventually be followed by a call to DosSubUnsetMem. This 
  6631. enables the suballocation function to free the resources that it uses to manage 
  6632. the heap. 
  6633.  
  6634. The application must call DosSubUnsetMem before it frees the memory object that 
  6635. contains this heap (with DosFreeMem). 
  6636.  
  6637. The following code fragment shows the termination of a heap. Assume that the 
  6638. address of the heap was placed into Offset already. 
  6639.  
  6640.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6641.     #include <os2.h>
  6642.     #include <stdio.h>
  6643.  
  6644.     PVOID   Offset;   /* Offset of the heap whose use is being terminated */
  6645.     APIRET  rc;       /* Return code                                      */
  6646.  
  6647.     rc = DosSubUnsetMem(Offset);
  6648.  
  6649.     if (rc != 0) {
  6650.         printf("DosSubUnsetMem error: return code = %ld", rc);
  6651.         return;
  6652.     }
  6653.  
  6654.  
  6655. Ending the Use of a Heap 
  6656.  
  6657.  
  6658. ΓòÉΓòÉΓòÉ 9.4. Using Shared Memory ΓòÉΓòÉΓòÉ
  6659.  
  6660. This section describes how you can use DosAllocSharedMem, DosGiveSharedMem, 
  6661. DosGetSharedMem, and DosGetNamedSharedMem to use shared memory. 
  6662.  
  6663.  
  6664. ΓòÉΓòÉΓòÉ 9.4.1. Using Named Shared Memory ΓòÉΓòÉΓòÉ
  6665.  
  6666. An application uses DosAllocSharedMem to allocate shared memory. When 
  6667. allocating the shared memory, an application can assign a unique name to the 
  6668. memory. Any application that has the name of the shared memory can use 
  6669. DosGetNamedSharedMem to retrieve a pointer to the memory. This makes it 
  6670. possible for two or more applications to share memory at the same time. 
  6671.  
  6672. The name of a shared memory object has the following form: 
  6673.  
  6674.     \sharemem\name
  6675. The "\sharemem\" is required. The "name" parameter can be any name that 
  6676. conforms to the rules for an OS/2 file name. No file is actually created for 
  6677. the memory object. There is no actual "\sharemem\" subdirectory. 
  6678.  
  6679. The following code fragment allocates 65536 bytes of named shared memory with 
  6680. the name "\sharemem\mymem". 
  6681.  
  6682.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6683.     #include <os2.h>
  6684.  
  6685.     APIRET  rc;
  6686.     CHAR    szMem[] = { "\\sharemem\\mymem" };
  6687.     PULONG  pb;
  6688.  
  6689.     rc = DosAllocSharedMem((PVOID *) &pb, szMem, 65536, fALLOC);
  6690.  
  6691.     *pb = 2762;
  6692.  
  6693.  
  6694. Allocating Named Shared Memory 
  6695.  
  6696. Once the named memory is allocated, any other process can retrieve a pointer to 
  6697. the named memory by using DosGetNamedSharedMem. 
  6698.  
  6699. The following code fragment retrieves a pointer to the named memory allocated 
  6700. above: 
  6701.  
  6702.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6703.     #include <os2.h>
  6704.     #define HF_STDOUT 1       /* Standard output handle */
  6705.  
  6706.     APIRET  rc;
  6707.     CHAR    szMem[] = { "\\sharemem\\mymem" };
  6708.     PULONG  pb2;
  6709.     ULONG   ulWritten;
  6710.  
  6711.     rc = DosGetNamedSharedMem((PVOID *) &pb2, szMem, PAG_READ | PAG_WRITE);
  6712.  
  6713.     if (*pb2 == 2762)
  6714.         rc = DosWrite(HF_STDOUT, "\r\n Success!\r\n", 13, &ulWritten);
  6715.  
  6716.  
  6717. Getting a Pointer to Named Shared Memory 
  6718.  
  6719.  
  6720. ΓòÉΓòÉΓòÉ 9.4.2. Using Unnamed Shared Memory ΓòÉΓòÉΓòÉ
  6721.  
  6722. An application can allocate unnamed shared memory by using DosAllocSharedMem 
  6723. with the object name set to NULL and the memory options set to OBJ_GIVEABLE or 
  6724. OBJ_GETTABLE. Sharing unnamed memory is more difficult than sharing named 
  6725. memory because the application allocating the memory must somehow pass a 
  6726. pointer to another application. This is typically done by using some form of 
  6727. interprocess communication, such as a queue or a named pipe. 
  6728.  
  6729. If an application allocates shared memory with the OBJ_GETTABLE option, it can 
  6730. pass a pointer to another application. The second application can then gain 
  6731. access to the shared memory by using DosGetSharedMem to validate the passed 
  6732. pointer. If an application allocates shared memory with the OBJ_GIVEABLE 
  6733. option, the process that allocates the memory can validate the pointer in 
  6734. another process with DosGiveSharedMem. The allocating process must still pass a 
  6735. pointer to the second process, but the second process need not use 
  6736. DosGetSharedMem. 
  6737.  
  6738. The following code fragment allocates 24576 bytes (24KB) of unnamed shared 
  6739. memory: 
  6740.  
  6741.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6742.     #include <os2.h>
  6743.  
  6744.     APIRET  rc;
  6745.     PBYTE   pb;
  6746.  
  6747.     rc = DosAllocSharedMem((PVOID *) &pb, (PSZ) NULL, 24576,
  6748.                            fALLOC | OBJ_GETTABLE);
  6749.  
  6750. Allocating 24576 Bytes of Unnamed Shared Memory 
  6751.  
  6752. Once the memory is allocated, the process can pass the memory pointer to a 
  6753. second process via interprocess communication. Once the second process receives 
  6754. the pointer, it can validate the memory with DosGetSharedMem, as shown in the 
  6755. following code: 
  6756.  
  6757.     #define  INCL_DOSMEMMGR   /* Memory Manager values */
  6758.     #include <os2.h>
  6759.  
  6760.     APIRET  rc;
  6761.     PBYTE  pb2;
  6762.  
  6763.     rc = DosGetSharedMem(pb2, PAG_READ | PAG_WRITE);
  6764.  
  6765. Validating Shared Memory 
  6766.  
  6767.  
  6768. ΓòÉΓòÉΓòÉ 9.5. Summary of Functions Used in Memory Management ΓòÉΓòÉΓòÉ
  6769.  
  6770. Following are the OS/2 functions used in memory management. 
  6771.  
  6772. Memory Management Functions 
  6773.  
  6774. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  6775. ΓöéMemory Functions              Γöé                              Γöé
  6776. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6777. ΓöéDosAllocMem                   ΓöéAllocates a private memory    Γöé
  6778. Γöé                              Γöéobject within the virtual     Γöé
  6779. Γöé                              Γöéaddress space.                Γöé
  6780. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6781. ΓöéDosSetMem                     ΓöéCommits or decommits a range  Γöé
  6782. Γöé                              Γöéof pages within a memory      Γöé
  6783. Γöé                              Γöéobject, or alters their       Γöé
  6784. Γöé                              Γöéprotection.                   Γöé
  6785. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6786. ΓöéDosFreeMem                    ΓöéFrees a private or shared     Γöé
  6787. Γöé                              Γöémemory object from the virtualΓöé
  6788. Γöé                              Γöéaddress space of the process. Γöé
  6789. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6790. ΓöéDosQueryMem                   ΓöéObtains information about a   Γöé
  6791. Γöé                              Γöérange of pages within the     Γöé
  6792. Γöé                              Γöévirtual address space of the  Γöé
  6793. Γöé                              Γöésubject process.              Γöé
  6794. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6795. ΓöéMemory Suballocation FunctionsΓöé                              Γöé
  6796. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6797. ΓöéDosSubSetMem                  ΓöéInitializes a heap for        Γöé
  6798. Γöé                              Γöésuballocation, or increases   Γöé
  6799. Γöé                              Γöéthe size of a previously      Γöé
  6800. Γöé                              Γöéinitialized heap.             Γöé
  6801. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6802. ΓöéDosSubAllocMem                ΓöéSuballocates a block of memoryΓöé
  6803. Γöé                              Γöéfrom a heap that was          Γöé
  6804. Γöé                              Γöépreviously initialized by     Γöé
  6805. Γöé                              ΓöéDosSubSetMem.                 Γöé
  6806. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6807. ΓöéDosSubFreeMem                 ΓöéFrees a block of memory that  Γöé
  6808. Γöé                              Γöéwas previously suballocated byΓöé
  6809. Γöé                              ΓöéDosSubAllocMem.               Γöé
  6810. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6811. ΓöéDosSubUnsetMem                ΓöéTerminates the use of a heap. Γöé
  6812. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6813. ΓöéShared Memory Functions       Γöé                              Γöé
  6814. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6815. ΓöéDosAllocSharedMem             ΓöéAllocates a shared memory     Γöé
  6816. Γöé                              Γöéobject within the virtual     Γöé
  6817. Γöé                              Γöéaddress space.                Γöé
  6818. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6819. ΓöéDosGetNamedSharedMem          ΓöéObtains access to an existing Γöé
  6820. Γöé                              Γöénamed shared memory object.   Γöé
  6821. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6822. ΓöéDosGetSharedMem               ΓöéObtains access to an existing Γöé
  6823. Γöé                              Γöéshared memory object.         Γöé
  6824. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  6825. ΓöéDosGiveSharedMem              ΓöéGives a target process access Γöé
  6826. Γöé                              Γöéto an existing shared memory  Γöé
  6827. Γöé                              Γöéobject.                       Γöé
  6828. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6829.  
  6830.  
  6831. ΓòÉΓòÉΓòÉ 10. Message Management ΓòÉΓòÉΓòÉ
  6832.  
  6833. This chapter describes the use of message files to hold an application's text 
  6834. messages to the user. Keeping messages in a message file simplifies changing 
  6835. those messages, for example when maintaining versions of the same application 
  6836. for different countries. 
  6837.  
  6838. The following topic is related to the information in this chapter: 
  6839.  
  6840. National Language Support. 
  6841.  
  6842.  
  6843. ΓòÉΓòÉΓòÉ 10.1. About Message Management ΓòÉΓòÉΓòÉ
  6844.  
  6845. For full-screen applications, text messages-used by an application to display 
  6846. information to the user-can be held in a message file. 
  6847.  
  6848. To keep and maintain messages in a message file, create a separate message file 
  6849. for each national language you intend to support. Use the MKMSGF utility 
  6850. program to create a binary version of a message file, and the MSGBIND utility 
  6851. program to bind the binary file to the application's executable file. Binding 
  6852. the messages to an application's executable file inserts the messages into the 
  6853. .EXE file. This enables faster access (but, of course, a larger .EXE file). 
  6854.  
  6855. The OS/2 operating system provides several functions to assist in message 
  6856. management. Applications can get messages from a message file, substitute 
  6857. variable information into the messages, and write messages to the screen or to 
  6858. a file. 
  6859.  
  6860. Code Page Considerations 
  6861. You can have versions of the message file for each code page you choose to 
  6862. support. When you use MKMSGF to create the message files, the utility will 
  6863. insert the code page information and link together the message files of the 
  6864. different versions. 
  6865.  
  6866. When message files are linked together in this manner, DosGetMessage will 
  6867. search for the appropriate version of the message for the code page that is 
  6868. active at the time the function is called. If there is no version of the 
  6869. message for the current code page, the function will return the first version 
  6870. of the message, no matter which code page it is associated with. 
  6871.  
  6872.  
  6873. ΓòÉΓòÉΓòÉ 10.2. Using Message Management ΓòÉΓòÉΓòÉ
  6874.  
  6875. DosGetMessage retrieves a message from the specified system message file, and 
  6876. inserts variable information into the body of the message. 
  6877.  
  6878. DosInsertMessage inserts variable text-string information into the body of the 
  6879. message, but does not retrieve the message. 
  6880.  
  6881. DosPutMessage sends the message in a buffer, usually to a display screen. 
  6882. DosPutMessage formats the screen buffer to prevent words from being split at 
  6883. the end of a line. 
  6884.  
  6885. DosQueryMessageCP retrieves the message file list of code pages and language 
  6886. identifiers. 
  6887.  
  6888. Note:  In the example code fragments that follow, error checking was left out 
  6889.        to conserve space. Applications should always check the return code that 
  6890.        the functions return. Control Program functions return an APIRET value. 
  6891.        A return code of 0 indicates success. If a non-zero value is returned, 
  6892.        an error occurred. 
  6893.  
  6894.  
  6895. ΓòÉΓòÉΓòÉ 10.2.1. Message Retrieval and String Substitution ΓòÉΓòÉΓòÉ
  6896.  
  6897. DosGetMessage retrieves a message from a system message file, and inserts 
  6898. variable text-string information into the message. 
  6899.  
  6900. In the following code fragment, the message file is "D:\MESSAGE\AUTOMSG.MSG". 
  6901. The third message within the message file contains the string "%1 Error at 
  6902. Station %2". The application calls DosGetMessage to convert this message into 
  6903. the string "Automation Failure Error at Station 69B". 
  6904.  
  6905.     #define INCL_DOSMISC   /* Miscellaneous values */
  6906.     #include <os2.h>
  6907.     #include <stdio.h>
  6908.  
  6909.     UCHAR   *IvTable[2];    /* Table of variables to insert       */
  6910.     ULONG    IvCount;       /* Number of variables                */
  6911.     UCHAR    DataArea[80];  /* Message buffer (returned)          */
  6912.     ULONG    DataLength;    /* Length of buffer                   */
  6913.     ULONG    MsgNumber;     /* Number of the message              */
  6914.     UCHAR    FileName[40];  /* Message file path-name string      */
  6915.     ULONG    MsgLength;     /* Length of message (returned)       */
  6916.     UCHAR    Field1[20];    /* String to substitute into variable */
  6917.                             /* field %1 of the message            */
  6918.     UCHAR    Field2[20];    /* String to substitute into variable */
  6919.                             /* field %2 of the message            */
  6920.     APIRET   rc;            /* Return code                        */
  6921.  
  6922.     strcpy(Field1,"Automation Failure");   /* Define the field with which to  */
  6923.                                            /* perform the first substitution  */
  6924.  
  6925.     strcpy(Field2,"69B");        /* Define the field with which to            */
  6926.                                  /* perform the second substitution           */
  6927.  
  6928.     IvTable[0] = Field1;         /* Set up the array of pointers to           */
  6929.     IvTable[1] = Field2;         /* substitute strings                        */
  6930.  
  6931.     IvCount = 2;                 /* Two variable message fields in message    */
  6932.  
  6933.     DataLength = 80;             /* Data buffer that will receive the         */
  6934.                                  /* complete message is 80 bytes in size      */
  6935.  
  6936.     MsgNumber = 3;               /* Specify the third message in the          */
  6937.                                  /* message file                              */
  6938.  
  6939.     strcpy(FileName,"D:\\MESSAGE\\AUTOMSG.MSG");   /* Path name of the        */
  6940.                                                    /* message file            */
  6941.  
  6942.     rc = DosGetMessage(IvTable, IvCount, DataArea, DataLength,
  6943.                        MsgNumber, FileName, &MsgLength);
  6944.  
  6945.     if (rc != 0) {
  6946.         printf("DosGetMessage error: return code = %ld", rc);
  6947.         return;
  6948.     }
  6949.  
  6950.  
  6951. Retrieving a Message and Substituting Text-Strings for Variables 
  6952.  
  6953. On successful return, the DataArea buffer contains the complete message (with 
  6954. the two variable fields appropriately updated), and the MsgLength variable 
  6955. contains the length of the message that was placed into the DataArea buffer. 
  6956.  
  6957. If an error occurs (that is, if the return code does not equal 0), a message 
  6958. that is related to the error will be placed in the message buffer. See the 
  6959. DosGetMessage API reference in Control Program Programming Reference for a 
  6960. description of the default messages that can be placed into the user's buffer 
  6961. if an error occurs during the processing of these requests. 
  6962.  
  6963.  
  6964. ΓòÉΓòÉΓòÉ 10.2.2. Text String Substitution in Memory ΓòÉΓòÉΓòÉ
  6965.  
  6966. DosInsertMessage inserts variable text-string information into a message that 
  6967. resides within program memory. 
  6968.  
  6969. In the following code fragment, the message resides in a program string 
  6970. variable named Message. The message is the string "%1 Error at Station %2". The 
  6971. application calls DosInsertMessage to convert this message into the string 
  6972. "Automation Failure Error at Station 69B". 
  6973.  
  6974.     #define INCL_DOSMISC   /* Miscellaneous values */
  6975.     #include <os2.h>
  6976.     #include <stdio.h>
  6977.  
  6978.     UCHAR   *IvTable[2];               /* Table of variables to insert         */
  6979.     ULONG    IvCount;                  /* Number of variables                  */
  6980.     UCHAR    MsgInput[40] = "%1 Error at Station %2";     /* The input message */
  6981.     ULONG    MsgInLength;              /* Length of input message              */
  6982.     UCHAR    DataArea[80];             /* Message buffer (returned)            */
  6983.     ULONG    DataLength;               /* Length of updated message buffer     */
  6984.     ULONG    MsgLength;                /* Length of updated message (returned) */
  6985.     UCHAR    Field1[20];               /* String to substitute into variable   */
  6986.                                        /* field %1 of the message              */
  6987.     UCHAR    Field2[20];               /* String to substitute into variable   */
  6988.                                        /* field %2 of the message              */
  6989.     APIRET   rc;                       /* Return code                          */
  6990.  
  6991.     strcpy(Field1,"Automation Failure");    /* Define the field with which to  */
  6992.                                             /* perform the first substitution  */
  6993.  
  6994.     strcpy(Field2,"69B");                   /* Define the field with which to  */
  6995.                                             /* perform the second substitution */
  6996.  
  6997.     IvTable[0] = Field1;                    /* Set up the array of pointers to */
  6998.     IvTable[1] = Field2;                    /* substitute strings              */
  6999.  
  7000.     IvCount = 2;                            /* Two variable message fields in  */
  7001.                                             /* message                         */
  7002.  
  7003.     MsgInLength = strlen(MsgInput);         /* Length of input message         */
  7004.  
  7005.     DataLength = 80;                        /* Data buffer that will receive   */
  7006.                                             /* the complete message is 80      */
  7007.                                             /* bytes in size                   */
  7008.  
  7009.     rc = DosInsertMessage(IvTable, IvCount, MsgInput, MsgInLength,
  7010.                           DataArea, DataLength, &MsgLength);
  7011.  
  7012.     if (rc != 0) {
  7013.         printf("DosInsertMessage error: return code = %ld", rc);
  7014.         return;
  7015.     }
  7016.  
  7017.  
  7018. Substituting Text-Strings for Variables in a String in Memory 
  7019.  
  7020. On successful return, the DataArea buffer contains the complete message (with 
  7021. the two variable fields appropriately updated), and the MsgLength variable 
  7022. contains the length of the message that was placed into the DataArea buffer. 
  7023.  
  7024. If an error occurs (that is, if the return code does not equal 0), a message 
  7025. that is related to the error will be placed in the message buffer. See the 
  7026. DosGetMessage API reference in Control Program Programming Reference for a 
  7027. description of the default messages that can be placed into the user's buffer 
  7028. if an error occurs during the processing of these requests. 
  7029.  
  7030.  
  7031. ΓòÉΓòÉΓòÉ 10.2.3. Writing Messages ΓòÉΓòÉΓòÉ
  7032.  
  7033. DosPutMessage is used to write the message to the screen or to a file on a 
  7034. disk. 
  7035.  
  7036. The following code fragment writes the message string contained in 
  7037. MessageBuffer to the file specified by FileHandle. The message string has 
  7038. already been placed in MessageBuffer using either DosGetMessage or 
  7039. DosInsertMessage. MsgLength was set to the length of the message string by the 
  7040. same call that put the message into MessageBuffer. 
  7041.  
  7042.     #define INCL_DOSMISC   /* Miscellaneous values */
  7043.     #include <os2.h>
  7044.     #include <stdio.h>
  7045.  
  7046.  
  7047.     HFILE   FileHandle;           /* Handle of output file or device */
  7048.     ULONG   MsgLength;            /* Length of message buffer        */
  7049.     UCHAR   MessageBuffer[80];    /* Message buffer                  */
  7050.     APIRET  rc;                   /* Return code                     */
  7051.  
  7052.     rc = DosPutMessage(FileHandle, MsgLength, MessageBuffer);
  7053.  
  7054.     if (rc != 0) {
  7055.         printf("DosPutMessage error: return code = %ld", rc);
  7056.         return;
  7057.     }
  7058.  
  7059.  
  7060. Writing an Edited Message to a File 
  7061.  
  7062. To write a message to the screen, use the standard output file handle. 
  7063.  
  7064.  
  7065. ΓòÉΓòÉΓòÉ 10.2.4. Code Page Information Associated with Message Files ΓòÉΓòÉΓòÉ
  7066.  
  7067. DosQueryMessageCP obtains a list of code page identifiers and language 
  7068. identifiers that are associated with a specified message file. 
  7069.  
  7070. In the following code fragment code page and language identifiers associated 
  7071. with the message file "D:\MESSAGE\AUTOMSG.MSG" are retrieved. 
  7072.  
  7073.     #define INCL_DOSMISC   /* Miscellaneous values */
  7074.     #include <os2.h>
  7075.     #include <stdio.h>
  7076.  
  7077.     UCHAR    BufferArea[20];  /* Buffer for the returned list  */
  7078.     ULONG    BufferLength;    /* Length of the buffer area     */
  7079.     UCHAR    FileName[40];    /* Message file path-name string */
  7080.     ULONG    DataLength;      /* Length of the returned data   */
  7081.     APIRET   rc;              /* Return code                   */
  7082.  
  7083.     strcpy(FileName, "D:\\MESSAGE\\AUTOMSG.MSG");  /* Path name of message file */
  7084.  
  7085.     BufferLength = 20;                             /* Length of buffer area     */
  7086.  
  7087.     rc = DosQueryMessageCp(BufferArea, BufferLength, FileName,
  7088.                            &DataLength);
  7089.  
  7090.     if (rc != 0) {
  7091.         printf("DosQueryMessageCp error: return code = %ld", rc);
  7092.         return;
  7093.     }
  7094.  
  7095.  
  7096. Getting Code Page and Language Identifiers Associated with a Message File 
  7097.  
  7098. On successful return, the BufferArea buffer contains a set of information 
  7099. concerning the code page identifiers and language identifiers that are 
  7100. associated with the message file. 
  7101.  
  7102.  
  7103. ΓòÉΓòÉΓòÉ 10.3. Summary of Functions for Message Management ΓòÉΓòÉΓòÉ
  7104.  
  7105. Following are the OS/2 functions for message management. 
  7106.  
  7107. Message Management Functions 
  7108.  
  7109. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7110. ΓöéFunction            ΓöéDescription                             Γöé
  7111. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7112. ΓöéDosGetMessage       ΓöéRetrieves a message from the specified  Γöé
  7113. Γöé                    Γöésystem message file, and inserts        Γöé
  7114. Γöé                    Γöévariable information into the body of   Γöé
  7115. Γöé                    Γöéthe message.                            Γöé
  7116. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7117. ΓöéDosInsertMessage    ΓöéInserts variable text-string informationΓöé
  7118. Γöé                    Γöéinto the body of a message.             Γöé
  7119. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7120. ΓöéDosPutMessage       ΓöéSends a message to an output file or    Γöé
  7121. Γöé                    Γöédevice.                                 Γöé
  7122. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7123. ΓöéDosQueryMessageCP   ΓöéRetrieves a message file list of code   Γöé
  7124. Γöé                    Γöépages and language identifiers.         Γöé
  7125. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7126.  
  7127.  
  7128. ΓòÉΓòÉΓòÉ 11. Program Execution Control ΓòÉΓòÉΓòÉ
  7129.  
  7130. Multitasking is the ability of the operating system to manage the execution of 
  7131. more than one application at a time. A multitasking operating system, such as 
  7132. OS/2 2.0, enables users to run many applications simultaneously. 
  7133.  
  7134. For the programmer, the OS/2 operating system supports two types of 
  7135. multitasking. An application can start other programs, in separate processes, 
  7136. that will execute concurrently with the application. These programs can be a 
  7137. new copy of the application, a related program that is designed to work with 
  7138. the application, or an unrelated program. Running multiple processes is the 
  7139. first type of multitasking provided for programmers. 
  7140.  
  7141. Running multiple threads is the second type of multitasking supported by the 
  7142. OS/2 operating system. The OS/2 operating system enables applications to run 
  7143. multiple threads of execution within the same process; separate activities can 
  7144. be multitasked within the application. An example of multiple-thread 
  7145. multitasking would be for the application to dispatch a separate subroutine to 
  7146. load a file from the disk, and have the subroutine execute at the same time the 
  7147. main program continues to monitor and respond to user input. 
  7148.  
  7149. This chapter describes processes, threads, and sessions, and the OS/2 functions 
  7150. used to create and manage them. Additionally, there is a section describing CPU 
  7151. scheduling. 
  7152.  
  7153. The following topics are related to the information in this chapter: 
  7154.  
  7155. o Memory 
  7156. o Semaphores 
  7157. o Queues 
  7158. o Pipes 
  7159. o Exception Handling 
  7160. o Debugging. 
  7161.  
  7162.  
  7163. ΓòÉΓòÉΓòÉ 11.1. About Program Execution Control-Thread, Processes, and Sessions ΓòÉΓòÉΓòÉ
  7164.  
  7165. To successfully use multitasking-multiple processes and multiple threads-in 
  7166. your programs, you need to understand the difference between a thread, a 
  7167. process, and a session. 
  7168.  
  7169. A thread is a dispatchable unit of execution that consists of a set of 
  7170. instructions, related CPU register values, and a stack. Each process has at 
  7171. least one thread, called the main thread or thread 1, and can have many threads 
  7172. running simultaneously. The application runs when the operating system gives 
  7173. control to a thread in the process. The thread is the basic unit of execution 
  7174. scheduling. 
  7175.  
  7176. A process is the code, data, and other resources-such as file handles, 
  7177. semaphores, pipes, queues, and so on-of an application in memory. The OS/2 
  7178. operating system considers every application it loads to be a process. System 
  7179. resources are allocated on a per-process basis. 
  7180.  
  7181. A session is one (or more) processes with their own virtual console. (A virtual 
  7182. console is a virtual screen-either a character-based, full screen or a 
  7183. Presentation Manager window-and buffers for keyboard and mouse input.) 
  7184.  
  7185. The OS/2 operating system supports up to 255 concurrent sessions and up to 4095 
  7186. processes. The operating system supports a system-wide maximum of 4095 threads, 
  7187. but the number of threads available in a single process will be lower, and will 
  7188. vary, because of resource usage within the process. 
  7189.  
  7190.  
  7191. ΓòÉΓòÉΓòÉ 11.1.1. Threads ΓòÉΓòÉΓòÉ
  7192.  
  7193. Applications always have at least one thread of execution-thread 1. Using 
  7194. multiple threads of execution, an application can do several things at the same 
  7195. time. 
  7196.  
  7197. For example, a simple Presentation Manager application consists of a single 
  7198. process with two threads: 
  7199.  
  7200. o A user interface thread that listens and responds to user requests, and that 
  7201.   queues work for the second thread 
  7202.  
  7203. o A processing thread that handles lengthy processing. 
  7204.  
  7205. The operating system creates the first thread of execution for a process when 
  7206. it starts the executable file. To create another thread of execution, a thread 
  7207. calls DosCreateThread, specifying the address within the program module where 
  7208. the thread begins asynchronous execution. Although a thread can execute any 
  7209. part of the application, including a part being executed by another thread, 
  7210. threads typically are used to execute separate sections of the application. By 
  7211. using several threads, the system can distribute the available CPU time and 
  7212. enable an application to carry out several tasks simultaneously. For example, 
  7213. an application can load a file and prompt the user for input at the same time. 
  7214.  
  7215. Each thread in a process has a unique stack and register context. Threads 
  7216. shares the resources of the process with the other threads in the process. For 
  7217. example, threads in the same process have access to the memory spaces of other 
  7218. threads within the process. However, threads of one process do not have access 
  7219. to the data spaces of other processes. 
  7220.  
  7221. Each thread has a priority, that determines the amount of CPU time the thread 
  7222. is allocated. Threads inherit the priority of the thread that creates them. The 
  7223. priority of a thread can be changed by the application; see Changing the 
  7224. Priority of a Thread for details. 
  7225.  
  7226. An application can use DosSuspendThread and DosResumeThread to suspend and 
  7227. resume the execution of a given thread. When an application suspends a thread, 
  7228. the thread remains suspended until the application calls DosResumeThread. 
  7229.  
  7230. When an application has more than one thread, it might be necessary to ensure 
  7231. that one thread is finished executing before another thread uses a shared 
  7232. resource, such as a disk file. DosWaitThread causes the application to wait 
  7233. until a specific thread has finished. DosWaitThread can also be used to 
  7234. determine the state of a thread; the function can return immediately with an 
  7235. error value if the identified thread is still running. 
  7236.  
  7237. A thread ends when it calls DosExit. 
  7238.  
  7239.  
  7240. ΓòÉΓòÉΓòÉ 11.1.2. Processes ΓòÉΓòÉΓòÉ
  7241.  
  7242. An OS/2 application that has been loaded into memory and prepared for execution 
  7243. is called a process. As mentioned earlier, a process consists of the code, 
  7244. data, and other resources (for example, open file handles) that belong to the 
  7245. application. Each process has at least one thread, called the main thread or 
  7246. thread 1. 
  7247.  
  7248. When the operating system executes an application, it confirms that the process 
  7249. code and data are in memory and that the main thread's registers and stack are 
  7250. set before starting the application. Each application has access to all 
  7251. resources of the computer, such as memory, disk drives, screen, keyboard, and 
  7252. the CPU itself. The system carefully manages these resources so that 
  7253. applications can access them without conflict. 
  7254.  
  7255. A process can have more than one thread. The operating system creates the first 
  7256. thread of execution for a process when it starts the executable file. More 
  7257. threads can be created with DosCreateThread. Each thread runs independently, 
  7258. with its own stack and register values. Unless the application changes a 
  7259. thread's priority, each thread gets a slice of the CPU in a round-robin 
  7260. strategy. All the threads in a process share the application's globally defined 
  7261. variables and other resources (open file handles, and so on). 
  7262.  
  7263. A process or thread ends when it calls DosExit. The operating system 
  7264. automatically closes any files or other resources left open by the process when 
  7265. the process ends. When a thread ends, however, any open resources remain open 
  7266. until another thread closes them or the process ends. A process can direct the 
  7267. operating system to carry out other actions when the process ends, by using 
  7268. DosExitList to create a list of termination functions. The operating system 
  7269. calls the termination functions, in the order given, when the process is about 
  7270. to end. If the thread has registered any exception handlers, the exception 
  7271. handlers will also be called before the thread terminates. 
  7272.  
  7273.  
  7274. ΓòÉΓòÉΓòÉ 11.1.2.1. Creating Processes ΓòÉΓòÉΓòÉ
  7275.  
  7276. An application can load and execute other applications by using DosExecPgm. The 
  7277. new application, once loaded, is called a child process. The process that 
  7278. starts the new application is called the parent process. 
  7279.  
  7280. A child process is like any other process. It has its own code, data, and 
  7281. threads. The child process inherits the resources-such as file handles, pipes, 
  7282. and queues-that belong to the parent process at the time the child process is 
  7283. created, although not necessarily with the same access rights. The parent 
  7284. process can place restrictions on the access of the child process to these 
  7285. resources: 
  7286.  
  7287. o Files are inherited except for files that were opened with no inheritance 
  7288.   indicated. 
  7289.  
  7290. o Pipes are inherited. 
  7291. Assuming that the parent process gives the child process appropriate access 
  7292. rights, the child process can use the inherited resources without preparing 
  7293. them. For example, if the parent process opens a file for reading and then 
  7294. starts a child process, the child process can read from the file immediately; 
  7295. it does not have to open the file. However, once the child process is created 
  7296. additional resources that the parent process creates are not available to the 
  7297. child process. Similarly, resources the child process creates are not available 
  7298. to the parent process. 
  7299.  
  7300. The parent process also has control over the meanings of standard input, 
  7301. output, and error for the child process. For example, the parent can write a 
  7302. series of records to a file, open the file as standard input, open a listing 
  7303. file as standard output, and then execute a sort program that takes its input 
  7304. from standard input and writes to standard output. 
  7305.  
  7306. Note that memory is not included in the list of things that a child process can 
  7307. inherit from its parent process. The child process is created with its own 
  7308. process address space that is separate and distinct from the memory of the 
  7309. parent process. A new linear address space is built for the new process. The 
  7310. only way for a parent process and a child process to access the same memory is 
  7311. to set up a shared memory area. 
  7312.  
  7313. The executable file of the child process can be started either synchronously or 
  7314. asynchronously to the parent process. If the parent process starts the child 
  7315. process running synchronously, the parent process is suspended and waits until 
  7316. the child process ends before continuing. A child process running 
  7317. asynchronously executes independently of the parent process (that is, both run 
  7318. at the same time). The parent process specifies how the child process is to run 
  7319. by setting a parameter in the call to DosExecPgm. 
  7320.  
  7321. The OS/2 command processor, CMD.EXE, starts most child processes synchronously. 
  7322. The parent process waits for each child process to end before it prompts the 
  7323. user for the next command. The command processor also enables the user to start 
  7324. asynchronous applications by using the DETACH command. When the user detaches 
  7325. an application, the command processor starts the application asynchronously, in 
  7326. the background, and continues to prompt for input. 
  7327.  
  7328.  
  7329. ΓòÉΓòÉΓòÉ 11.1.2.2. Process Termination ΓòÉΓòÉΓòÉ
  7330.  
  7331. A parent process can use DosWaitChild to determine the termination status of a 
  7332. child process that is running independently. The parent process can have one of 
  7333. its threads call DosWaitChild to wait for completion of the child process while 
  7334. other threads of the parent continue processing. 
  7335.  
  7336. If the child has started another process, DosWaitChild waits for the completion 
  7337. of any grandchild processes before returning, but does not report their status. 
  7338. If the specified child process has multiple threads, DosWaitChild returns the 
  7339. result code of the last DosExit request. 
  7340.  
  7341. If there are no child processes, either active or ended with a return code, 
  7342. DosWaitChild returns with an error code. If no child processes have terminated, 
  7343. DosWaitChild can optionally wait until one terminates before returning to the 
  7344. parent. 
  7345.  
  7346.  
  7347. ΓòÉΓòÉΓòÉ 11.1.2.3. Process Exit Lists ΓòÉΓòÉΓòÉ
  7348.  
  7349. Because any process can terminate any other process for which it has a process 
  7350. identifier, applications might lose information if a process terminates the 
  7351. application before it can save its work. To prevent this loss of data, you can 
  7352. create a list of functions to clean up data and files before the operating 
  7353. system terminates the process. This list is called an exit list. The operating 
  7354. system maintains an exit list for each process and calls these functions 
  7355. whenever the application is terminated, whether by another process or by 
  7356. itself. 
  7357.  
  7358. You call DosExitList to add to the exit list a routine that is to be given 
  7359. control when a process is terminated (or finishes its execution). Multiple 
  7360. routines can be added to the list. When the process is terminating, the 
  7361. operating system transfers control to each address on the list. 
  7362.  
  7363. Exit-list functions perform clean-up operations on resources. For example, an 
  7364. exit-list function can be used in a dynamic link library module to free 
  7365. resources or clear flags and semaphores when a client program has ended. 
  7366.  
  7367.  
  7368. ΓòÉΓòÉΓòÉ 11.1.3. Multitasking with Threads and Multitasking with Processes ΓòÉΓòÉΓòÉ
  7369.  
  7370. The creation and termination of a process is relatively slow compared to the 
  7371. creation and termination of a thread, and is more costly in terms of system 
  7372. resources. 
  7373.  
  7374. For example, sharing data and resources between processes requires shared 
  7375. memory and the mechanisms of interprocess communication; threads, on the other 
  7376. hand, have full access to the memory and other resources that belong to the 
  7377. process the threads are part of and can be coordinated using semaphores. For 
  7378. these reasons, thread-to-thread task context switches are faster than 
  7379. process-to-process context switches. 
  7380.  
  7381. Because the operating system can create and execute threads more quickly than 
  7382. processes, the preferred multitasking method for applications is to distribute 
  7383. tasks among threads in the same process instead of among processes. 
  7384.  
  7385.  
  7386. ΓòÉΓòÉΓòÉ 11.1.4. Sessions ΓòÉΓòÉΓòÉ
  7387.  
  7388. The OS/2 operating system uses sessions to help the user move from one 
  7389. application to the next without disrupting the screen display of an 
  7390. application. 
  7391.  
  7392. A session consists of at least one process and a virtual console-buffers for 
  7393. keyboard and mouse input and either a character-based, full screen or a 
  7394. Presentation Manager window. When the system creates a session, the process in 
  7395. the session displays output in the screen or window. The user can view the 
  7396. output and supply input by moving to the session. The user moves to a session 
  7397. by pressing the Alt+Esc key combination, by selecting the title of the session 
  7398. from the Window List, or, for windowed sessions, by clicking the mouse in the 
  7399. session window. 
  7400.  
  7401. A child session is under the control of the session that creates it. The 
  7402. session that starts the child session is called the parent session. Any process 
  7403. in the parent session can exercise control over a child session. 
  7404.  
  7405. An unrelated session is not under the control of the session that started it. 
  7406. The process that creates the unrelated session cannot select it, make it 
  7407. nonselectable, bind it, or terminate it, nor can any other session. 
  7408. DosStartSession does not even return a session identifier when an unrelated 
  7409. session is started. Unrelated sessions are controlled entirely by the user. 
  7410. When the operating system starts new sessions, it starts them as unrelated 
  7411. sessions. 
  7412.  
  7413.  
  7414. ΓòÉΓòÉΓòÉ 11.1.4.1. Creating Sessions ΓòÉΓòÉΓòÉ
  7415.  
  7416. A process creates a new session by using DosStartSession. DosStartSession 
  7417. enables an application to start another session and to specify the name of the 
  7418. application to be started in that session. 
  7419.  
  7420. DosStartSession also specifies which of the five session types is to be 
  7421. started: 
  7422.  
  7423. o Full screen, protect mode, 
  7424. o Text windowed, protect mode, 
  7425. o Presentation Manager (PM), 
  7426. o Full screen DOS Session, or 
  7427. o Windowed DOS Session. 
  7428. Protect mode applications run in full screen and text windowed sessions, PM and 
  7429. AVIO applications run in PM windows, and DOS applications run in full screen 
  7430. DOS Sessions and windowed DOS Sessions. 
  7431.  
  7432. OS/2 applications running in any of the OS/2 session types-full screen, text 
  7433. windowed, and PM-can start sessions of any other type, including DOS Sessions. 
  7434. DOS Session applications cannot start other sessions. 
  7435.  
  7436. An application can start another process in a separate session when the 
  7437. application will not manage any I/O done by the process. For example, an 
  7438. application that starts an unrelated application could start it in a separate 
  7439. session. 
  7440.  
  7441. A session can be started as a related or an unrelated session. A related 
  7442. session is called a child session, and the session starting the child session 
  7443. is called the parent session. An application can control its child sessions by 
  7444. using the session identifier returned by DosStartSession with the 
  7445. DosSetSession, DosSelectSession, and DosStopSession. If an application starts 
  7446. an unrelated session, the new session cannot be controlled by the application. 
  7447. The Related field in the STARTDATA structure specifies whether the new session 
  7448. is related to the session calling DosStartSession. 
  7449.  
  7450. After a process has started a child session, no other process in its session 
  7451. can start a child session until all dependent sessions started by this process 
  7452. have ended. 
  7453.  
  7454. When a session is created, the title specified in the function call (or the 
  7455. application name if no title is specified) is added to the Window List. 
  7456.  
  7457. DosStartSession can be used to start either a foreground or a background 
  7458. session, but a new session can be started in the foreground only when the 
  7459. caller's session, or one of the caller's descendant sessions, is currently 
  7460. executing in the foreground. The foreground session for windowed applications 
  7461. is the session of the application that owns the window focus. 
  7462.  
  7463. Termination Queues 
  7464. The parent session must create a termination queue prior to specifying the 
  7465. queue name in a call to DosStartSession. The operating system will continue to 
  7466. notify the parent session through the specified queue as long as the session 
  7467. calling DosStartSession remains a parent session. In other words, when all the 
  7468. child sessions for a particular parent session terminate, the termination queue 
  7469. is closed by the operating system. An existing queue name must be specified on 
  7470. the next DosStartSession call if the caller wants to continue receiving 
  7471. termination notification messages. 
  7472.  
  7473. The operating system writes a data element to the specified queue when any 
  7474. child session terminates. The queue is posted regardless or who terminates the 
  7475. child session (the child, the parent, or the user) and whether the termination 
  7476. is normal or abnormal. 
  7477.  
  7478. A parent session calls DosReadQueue to receive notification when a child 
  7479. session has terminated. The word that contains the request parameter, returned 
  7480. by DosReadQueue, will be 0. The data element has the following format: 
  7481.  
  7482. Termination Queue Element Format 
  7483.  
  7484. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7485. ΓöéSize      ΓöéDescription                                       Γöé
  7486. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7487. ΓöéWORD      ΓöéSession ID of the child session that terminated   Γöé
  7488. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7489. ΓöéWORD      ΓöéResult code                                       Γöé
  7490. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7491.  
  7492. The process that originally called the DosStartSession request should call 
  7493. DosReadQueue, with the NOWAIT parameter set to 0. This is the only process that 
  7494. has addressability to the notification data element. After reading and 
  7495. processing the data element, the caller must free the segment containing the 
  7496. data element by calling DosFreeMem. 
  7497.  
  7498. When a child session terminates, the result code returned in the termination 
  7499. queue's data element is the result code of the program specified in the 
  7500. DosStartSession call, providing 
  7501.  
  7502. o the program was executed directly, with no intermediate secondary command 
  7503.   processor, or 
  7504. o the program is executed indirectly through a secondary command processor, and 
  7505.   the /C parameter is specified. 
  7506.  
  7507. When a child session is running in the foreground at the time it terminates, 
  7508. the parent session becomes the new foreground session. When a parent session 
  7509. terminates, any child sessions are terminated. When an unrelated session 
  7510. terminates in the foreground, the operating system selects the next foreground 
  7511. session. 
  7512.  
  7513.  
  7514. ΓòÉΓòÉΓòÉ 11.1.4.2. Child Session Control ΓòÉΓòÉΓòÉ
  7515.  
  7516. A session can be either a child session or an unrelated session. A child 
  7517. session is under the control of the processes in the session that creates it 
  7518. (the parent session). A process can select, set, or stop a child session by 
  7519. using DosSelectSession, DosSetSession, or DosStopSession, respectively. 
  7520. DosStartSession returns a unique session identifier for the child session for 
  7521. use in these functions. 
  7522.  
  7523. A session can run in either the foreground or background. A process can create 
  7524. a foreground session only if the creating process or one of its descendant 
  7525. sessions is executing in the current foreground session. A process can move a 
  7526. child session to the foreground by selecting the child session using the 
  7527. session identifier and calling DosSelectSession. A process can make a child 
  7528. session nonselectable by using DosSetSession to change the SelectInd field in 
  7529. the STATUSDATA structure. This prevents the user from selecting the session 
  7530. from the Window List but does not prevent a process from selecting the child 
  7531. session by using DosSelectSession. 
  7532.  
  7533. A process can bind a child session to its own session by using DosSetSession. 
  7534. Binding a session causes that session to move to the foreground whenever the 
  7535. user selects the parent session from the Window List. 
  7536.  
  7537. A parent session can use a session identifier with the DosSetSession function 
  7538. only if the parent session created the child session associated with that 
  7539. identifier. It cannot use identifiers for child sessions created by other 
  7540. parent processes. This is true for all session management functions. 
  7541.  
  7542. Although a child session is related to the session that started it, the 
  7543. processes in the child and original sessions are not related. This means that 
  7544. even though DosStartSession supplies the process identifier of the process in 
  7545. the child session, the process identifier cannot be used with OS/2 functions 
  7546. such as DosSetPriority. 
  7547.  
  7548.  
  7549. ΓòÉΓòÉΓòÉ 11.1.4.3. Child Session Termination ΓòÉΓòÉΓòÉ
  7550.  
  7551. A parent session can stop a child session by using DosStopSession. Stopping the 
  7552. child session terminates the processes in that session. It also stops any 
  7553. sessions related to the child session. If a child session is in the foreground 
  7554. when it is stopped, the parent session becomes the foreground session. 
  7555. DosStopSession breaks any bond that exists between the parent session and the 
  7556. specified child session. 
  7557.  
  7558. A process running in the session specified in the call to DosStopSession can 
  7559. ignore the request to terminate. If this happens, DosStopSession still returns 
  7560. 0 (indicating success). The only way to be certain that the child session has 
  7561. terminated is to wait for notification through the termination queue specified 
  7562. in the call to DosStartSession. The operating system writes a data element into 
  7563. the specified queue when the child session terminates. The process in the 
  7564. parent session must call DosReadQueue to retrieve this data element, which 
  7565. contains the session identifier for the child session and the return value for 
  7566. the process in the child session. Only the process that created the child 
  7567. session can read the data element. 
  7568.  
  7569.  
  7570. ΓòÉΓòÉΓòÉ 11.2. About CPU Scheduling ΓòÉΓòÉΓòÉ
  7571.  
  7572. The OS/2 operating system performs prioritized, preemptive, multitasking. 
  7573. Prioritized means that the operating system does not divide CPU time equally 
  7574. among all threads. All programs do not get equal access to the CPU. A 
  7575. prioritizing, time-slicing strategy is used to allocate access to the CPU among 
  7576. competing threads. Each thread has a priority and the operating system runs the 
  7577. highest priority thread that is ready to run. Programs with higher priorities 
  7578. (a real-time robotic application, for example), are given access to the CPU 
  7579. before programs with lower priorities. If a thread with a higher priority than 
  7580. the currently running thread becomes ready to run, the current thread is 
  7581. stopped immediately, or preempted, and the higher priority thread is given the 
  7582. CPU. The lower priority thread does not get to complete its time slice. Threads 
  7583. of equal priority are given CPU time in a round-robin manner. 
  7584.  
  7585. Preemptive means that the multitasking activity needs no cooperation from the 
  7586. executing programs. The operating system maintains control over executing 
  7587. programs, and stops, or preempts, them when their time slice with the CPU is 
  7588. over or when a higher priority program is ready to run. 
  7589.  
  7590. CPU scheduling is based on four priority classes-Time Critical, Fixed-High, 
  7591. Regular, and Idle-Time. Each class has 32 levels of execution ordering. 
  7592. Scheduling parameters are user-selectable at the time the system is started or 
  7593. can be varied dynamically based on system load. 
  7594.  
  7595. Depending on a thread's priority class and level, the operating system 
  7596. periodically gives each thread in each process a small slice of CPU time. 
  7597. Threads with higher priorities always run before threads having lower 
  7598. priorities. A thread runs until its time is up or until a thread with a higher 
  7599. priority is ready to run. At that time, the operating system preempts the 
  7600. thread and starts another thread. Threads can also voluntarily relinquish the 
  7601. CPU (for example, by calling DosSleep). 
  7602.  
  7603. The amount of time in each time slice is defined by the TIMESLICE command in 
  7604. the CONFIG.SYS file. The TIMESLICE command can be used by the user to customize 
  7605. the size of the time slices that a thread gets. The default is for the 
  7606. operating system to dynamically vary the size of the time slice based on the 
  7607. activity of the thread and the overall system load. 
  7608.  
  7609. When a thread is created (using DosCreateThread), it inherits the priority of 
  7610. the thread that started it. DosSetPriority enables threads to change their 
  7611. priority classes and levels in response to changes in their execution 
  7612. environments. DosSetPriority enables a thread to change its own priority, or 
  7613. the priority of any thread within its process. DosSetPriority also enables 
  7614. changing priorities for the entire process and for descendant processes. Within 
  7615. each class, the priority level of a thread can vary because of a DosSetPriorty 
  7616. request or, if dynamic priority variation is being used, because of action 
  7617. taken by the operating system. 
  7618.  
  7619.  
  7620. ΓòÉΓòÉΓòÉ 11.2.1. Priority Classes ΓòÉΓòÉΓòÉ
  7621.  
  7622. The operating system uses four priority classes to determine when a thread 
  7623. receives a time slice: 
  7624.  
  7625. Priority Classes 
  7626.  
  7627. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7628. ΓöéPriority                      ΓöéDescription                   Γöé
  7629. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7630. ΓöéTime-critical                 ΓöéHighest priority.  For use    Γöé
  7631. Γöé                              Γöéwhen response time is         Γöé
  7632. Γöé                              Γöécritical.                     Γöé
  7633. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7634. ΓöéFixed-high                    ΓöéUsed by threads that provide  Γöé
  7635. Γöé                              Γöéservice to other threads. ThisΓöé
  7636. Γöé                              Γöépriority class is to be used  Γöé
  7637. Γöé                              Γöéwhen it is desirable that the Γöé
  7638. Γöé                              Γöéthread not be too sensitive toΓöé
  7639. Γöé                              Γöéthe foreground/background     Γöé
  7640. Γöé                              Γöéboost provided by dynamic     Γöé
  7641. Γöé                              Γöépriority variation. It is     Γöé
  7642. Γöé                              Γöémeant for programs that need  Γöé
  7643. Γöé                              Γöéto execute before regular     Γöé
  7644. Γöé                              Γöéprograms, but without the     Γöé
  7645. Γöé                              Γöéimmediate response time       Γöé
  7646. Γöé                              Γöérequirement called for by     Γöé
  7647. Γöé                              Γöétime-critical threads.        Γöé
  7648. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7649. ΓöéRegular                       ΓöéDefault priority.  Most       Γöé
  7650. Γöé                              Γöéthreads belong in this class. Γöé
  7651. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7652. ΓöéIdle-time                     ΓöéLowest priority.  This        Γöé
  7653. Γöé                              Γöépriority only gets CPU time   Γöé
  7654. Γöé                              Γöéwhen there is no other work toΓöé
  7655. Γöé                              Γöédo.                           Γöé
  7656. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7657.  
  7658. A time-critical thread always receives a time slice before a fixed-high thread, 
  7659. a fixed-high thread always receives a time slice before a regular thread, and a 
  7660. regular thread always receives a time slice before an idle-time thread. 
  7661.  
  7662. Time-Critical Threads 
  7663. Time-critical threads have the highest priority class and execute before any 
  7664. fixed-high, regular, or idle-time threads. 
  7665.  
  7666. The time-critical class is for threads that must react to events outside the 
  7667. system. For example, in a communications application, a thread responsible for 
  7668. reading data from the communications device needs enough time to read all 
  7669. incoming data. Because more than a regular time slice might be needed, a 
  7670. time-critical classification ensures that the thread gets all the time 
  7671. required. 
  7672.  
  7673. Time-critical threads have a static priority that is not varied by the 
  7674. operating system. They are scheduled among themselves in priority level order, 
  7675. with round-robin scheduling of threads of equal priority. 
  7676.  
  7677. Time-critical threads must be executed quickly, then free the CPU for other 
  7678. work until another time-critical event occurs. This is important to maintain 
  7679. good interactive responsiveness to the user and enable communications and other 
  7680. time  critical applications to run concurrently. The time-critical activity 
  7681. should, when possible, be in a thread separate from the rest of the 
  7682. application, to isolate and minimize the time spent processing at the 
  7683. time-critical level. A good rule of thumb is that a time-critical thread should 
  7684. consist of no more than about 20,000 assembly language instructions. 
  7685.  
  7686. Fixed-High Threads 
  7687. A fixed-high thread has a priority class that is lower than time-critical but 
  7688. executes before any regular or idle-time threads. This class of threads should 
  7689. be used to provide service for other threads where it is desirable that the 
  7690. thread not be too sensitive to the foreground/background boost provided by 
  7691. dynamic priority variation. A messaging thread, would be a good example of this 
  7692. type of thread. 
  7693.  
  7694. The operating system varies the priority of a fixed-high thread around a base 
  7695. value according to the activity of the thread and the system at any point in 
  7696. time. The base value can be set by the thread itself. 
  7697.  
  7698. Regular Threads 
  7699. A regular thread is the class that the majority of threads fall into. No 
  7700. explicit action is necessary by the application to run at this priority, it is 
  7701. the default. 
  7702.  
  7703. The operating system varies the priority level of a regular thread around a 
  7704. base value according to the activity of the thread and the system at any point 
  7705. in time. The base value can be set by the thread itself. 
  7706.  
  7707. Idle-Time Threads 
  7708. An idle-time thread is one with very low priority that executes only when there 
  7709. are no regular, fixed-high, or time-critical threads to execute. Idle-time 
  7710. threads get CPU time only when there is no other work to do. The idle-time 
  7711. class is for threads that need very little CPU time. 
  7712.  
  7713. Idle-time threads have a static priority that is not varied by the operating 
  7714. system. 
  7715.  
  7716.  
  7717. ΓòÉΓòÉΓòÉ 11.2.2. Priority Levels ΓòÉΓòÉΓòÉ
  7718.  
  7719. Within each class, the operating system maintains a priority level for a 
  7720. thread. For each of the four priority classes, there are 32 priority levels-0 
  7721. to 31. A thread with priority level 31 always receives a time slice before a 
  7722. thread with priority level 30, and so on. 
  7723.  
  7724. If two or more threads have the same priority level, the operating system 
  7725. distributes the CPU time equally by using a round-robin scheme; that is, the 
  7726. operating system gives a time slice to first one, then another, and so on, and 
  7727. then goes back to the first. A thread can use DosSetPriority to change its own 
  7728. priority or the priority of any other thread within its process. 
  7729.  
  7730. Although an application can set the priority level of a thread at any time, 
  7731. only applications that use more than one thread or process should do so. The 
  7732. best use of priority is to speed up threads or processes on which other threads 
  7733. or processes depend. For example, an application might temporarily raise the 
  7734. priority of a thread loading a file if another thread is waiting for that file 
  7735. to be loaded. Because the priority of a thread is relative to all other threads 
  7736. in the system, raising the priority of the threads in an application merely to 
  7737. get the extra CPU time adversely affects the overall operation of the system. 
  7738.  
  7739. There are other ways to affect the amount of CPU time a thread is given. A 
  7740. thread can define a critical section of code by using DosEnterCritSec and 
  7741. DosExitCritSec. While inside the critical section of code, a thread cannot be 
  7742. preempted by any other thread within its process (threads in other processes 
  7743. are still given their time slices). Using critical sections enables threads to 
  7744. get more CPU time, while not unduly affecting the rest of the system. 
  7745.  
  7746. The priority class and priority level are set using DosSetPriority. The 
  7747. priority class is changed by passing the new priority class to the function. 
  7748. The priority level, however, is changed by passing a value, called the 
  7749. priority-delta, that is added to the existing priority level to produce the new 
  7750. priority level; changes to the priority level are relative to the current 
  7751. priority level. Specifying a positive priority-delta increases the priority 
  7752. level, enabling the thread to obtain more CPU time than it normally would. A 
  7753. negative priority-delta decreases the priority level, giving the thread less 
  7754. CPU time than it would normally receive. The value is restricted to the valid 
  7755. range, based upon the current priority class of the process. 
  7756.  
  7757. If you change the priority level without changing the priority class, the 
  7758. priority-delta is relative to the current priority level. However, if you 
  7759. change the priority class at the same time that you change the priority level, 
  7760. the priority-delta value is relative to 0. Whenever DosSetPriority is called 
  7761. with a class specification, but no value is specified for priority-delta, the 
  7762. base priority level defaults to 0. 
  7763.  
  7764. The process identifier parameter of DosSetPriority specifies which process is 
  7765. affected by the call. A process can change the priority of itself, of any 
  7766. process that is a descendant of itself, or of one of its threads. 
  7767.  
  7768. A thread can change the priority of any thread within its current process. When 
  7769. a thread changes the priority of threads in a descendant process, however, only 
  7770. those threads running at the default priority will be changed. You cannot 
  7771. change the priority of a thread in a child process that has already changed its 
  7772. priority from the default. 
  7773.  
  7774. The initial thread of execution for an application is given a regular class 
  7775. priority that varies by the system. When a thread is created, it is initially 
  7776. dispatched in the same class and priority as the thread that started it. A 
  7777. child process inherits the priority of the thread in the parent process that 
  7778. creates it. 
  7779.  
  7780.  
  7781. ΓòÉΓòÉΓòÉ 11.2.3. Priority Guidelines ΓòÉΓòÉΓòÉ
  7782.  
  7783. Within the two most common priority classes-time-critical and regular-there are 
  7784. certain broad guidelines recommended for choosing the priority level for a 
  7785. program. 
  7786.  
  7787. o TIME-CRITICAL CLASS 
  7788.  
  7789.   The guidelines for level within the time critical class are set to maximize 
  7790.   the number of different applications that can successfully multitask in an 
  7791.   OS/2 system. The guidelines are described in the following table. 
  7792.  
  7793.   Recommended Priority Levels for Time-Critical Threads 
  7794.  
  7795.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7796.     ΓöéActivity     ΓöéRange of    ΓöéJustification/Comments        Γöé
  7797.     Γöé             ΓöéRecommended Γöé                              Γöé
  7798.     Γöé             ΓöéPriority    Γöé                              Γöé
  7799.     Γöé             ΓöéLevels      Γöé                              Γöé
  7800.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7801.     ΓöéRobotics/RealΓöé20-31       ΓöéOS/2 systems can be used on   Γöé
  7802.     Γöétime process Γöé            Γöémanufacturing lines to controlΓöé
  7803.     Γöécontrol      Γöé            Γöéequipment or in other real    Γöé
  7804.     Γöé             Γöé            Γöétime process control          Γöé
  7805.     Γöé             Γöé            Γöéapplications. In this case a  Γöé
  7806.     Γöé             Γöé            Γöéslow response from the PC     Γöé
  7807.     Γöé             Γöé            Γöécould cause expensive damage  Γöé
  7808.     Γöé             Γöé            Γöéto equipment or even human    Γöé
  7809.     Γöé             Γöé            Γöéinjury. Therefore the highest Γöé
  7810.     Γöé             Γöé            Γöépriority levels should be     Γöé
  7811.     Γöé             Γöé            Γöéreserved for these            Γöé
  7812.     Γöé             Γöé            Γöéapplications.                 Γöé
  7813.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7814.     ΓöéCommunicationΓöé10-19       ΓöéIn communications, the        Γöé
  7815.     Γöé             Γöé            Γöéinability to get the processorΓöé
  7816.     Γöé             Γöé            Γöécould cause a loss of data or Γöé
  7817.     Γöé             Γöé            Γöécommunications sessions.      Γöé
  7818.     Γöé             Γöé            ΓöéTherefore this class of       Γöé
  7819.     Γöé             Γöé            Γöéapplications is next highest. Γöé
  7820.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7821.     ΓöéOther        Γöé0-09        ΓöéOther threads might need to   Γöé
  7822.     Γöé             Γöé            Γöépreempt the foreground in     Γöé
  7823.     Γöé             Γöé            Γöéspecial cases (for example,   Γöé
  7824.     Γöé             Γöé            ΓöéControl-Break). These should  Γöé
  7825.     Γöé             Γöé            Γöébe set below the other 2      Γöé
  7826.     Γöé             Γöé            Γöéclasses.                      Γöé
  7827.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7828.  
  7829.   In general, application performance is not a good reason to make a thread 
  7830.   time critical. 
  7831.  
  7832. o REGULAR CLASS 
  7833.  
  7834.   In cases where explicit priority levels are set, they should follow the 
  7835.   guidelines listed below. 
  7836.  
  7837.   Recommended Priority Levels for Regular Priority Threads 
  7838.  
  7839.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7840.     ΓöéActivity     ΓöéRange of    ΓöéJustification                 Γöé
  7841.     Γöé             ΓöéRecommended Γöé                              Γöé
  7842.     Γöé             ΓöéPriority    Γöé                              Γöé
  7843.     Γöé             ΓöéLevel       Γöé                              Γöé
  7844.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7845.     ΓöéCommunicationΓöé26-31       ΓöéCommunications should take    Γöé
  7846.     Γöé             Γöé            Γöépriority over other backgroundΓöé
  7847.     Γöé             Γöé            Γöéprocessing to increase overlapΓöé
  7848.     Γöé             Γöé            Γöéwith transmission and         Γöé
  7849.     Γöé             Γöé            Γöéprocessing on the partner PC  Γöé
  7850.     Γöé             Γöé            Γöéor host.  This gives the best Γöé
  7851.     Γöé             Γöé            Γöésystem performance.           Γöé
  7852.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7853.     ΓöéOther        Γöé0-25.       ΓöéIf an application has multipleΓöé
  7854.     Γöé             Γöé            Γöéthreads it might be necessary Γöé
  7855.     Γöé             Γöé            Γöéto set them to several        Γöé
  7856.     Γöé             Γöé            Γöédifferent priorities to       Γöé
  7857.     Γöé             Γöé            Γöéoptimize the order in which   Γöé
  7858.     Γöé             Γöé            Γöéthey run. A range of priority Γöé
  7859.     Γöé             Γöé            Γöélevels is provided to         Γöé
  7860.     Γöé             Γöé            Γöéfacilitate this. (The default Γöé
  7861.     Γöé             Γöé            Γöépriority is regular class,    Γöé
  7862.     Γöé             Γöé            Γöélevel = 0.)                   Γöé
  7863.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7864.  
  7865.  
  7866. ΓòÉΓòÉΓòÉ 11.2.4. Dynamic Priority Alteration ΓòÉΓòÉΓòÉ
  7867.  
  7868. The operating system can be configured to dynamically alter the priority of a 
  7869. process. The PRIORITY statement in CONFIG.SYS can be set to either ABSOLUTE or 
  7870. DYNAMIC. If PRIORITY specifies the ABSOLUTE option, all processes receive CPU 
  7871. time based on the priority established by calls to DosSetPriority. If the 
  7872. PRIORITY command in the CONFIG.SYS file specifies the DYNAMIC option, the 
  7873. operating system adjusts process priorities based on system load and process 
  7874. activity, and on whether the process is in the foreground. DYNAMIC is the 
  7875. default setting; if the PRIORITY command is not specified, the system uses 
  7876. DYNAMIC priority. DYNAMIC is designed to gives the best overall system 
  7877. performance under most conditions. 
  7878.  
  7879. When dynamic priority variation is enabled, the operating system grants higher 
  7880. priority to the foreground process than to background processes. System load 
  7881. and process activity are also taken into consideration. The priority of the 
  7882. process consists of a computed priority value that is based upon the display 
  7883. status of the process (foreground or background), and its recent I/O and CPU 
  7884. time usage history. When dynamic priority variation is enabled, I/O priority 
  7885. boosts are generated for keyboard input, window, foreground, processor 
  7886. starvation, device I/O, and DOS Session interrupts. This ensures that the 
  7887. foreground process-the process most likely to be in use-receives enough CPU 
  7888. time to provide quick response to user input. 
  7889.  
  7890.  
  7891. ΓòÉΓòÉΓòÉ 11.2.5. Altering the Size of the Time Slice ΓòÉΓòÉΓòÉ
  7892.  
  7893. The TIMESLICE command in CONFIG.SYS sets the minimum and maximum amount of 
  7894. processor time allocated to processes and programs for both OS/2 and DOS 
  7895. sessions. 
  7896.  
  7897. The first parameter selects the minimum TIMESLICE value in milliseconds. This 
  7898. value is the minimum amount of time a thread is to be processed before yielding 
  7899. the processor to a thread of the same priority level. This value must be an 
  7900. integer greater than or equal to 32. 
  7901.  
  7902. The second parameter selects the maximum TIMESLICE value in milliseconds. The 
  7903. value of this parameter is the maximum amount of time a thread can be processed 
  7904. before yielding processor time. This value must be an integer greater than or 
  7905. equal to the minimum value, and less than 65536. 
  7906.  
  7907. The default is dynamic time slicing, which varies the size of the time slice 
  7908. depending on system load and paging activity. Dynamic time slicing is designed 
  7909. to give the best performance in most situations. 
  7910.  
  7911. For examples and more details of the TIMESLICE command, see the online OS/2 
  7912. Command Reference. 
  7913.  
  7914.  
  7915. ΓòÉΓòÉΓòÉ 11.3. Using Processes ΓòÉΓòÉΓòÉ
  7916.  
  7917. An OS/2 application that has been loaded into memory and prepared for execution 
  7918. is called a process. A process is the code, data, and other resources of the 
  7919. application, such as the open file handles, semaphores, pipes, queues and so 
  7920. on. The OS/2 operating system considers every application it loads to be a 
  7921. process. 
  7922.  
  7923. Each process has at least one thread, called the main thread or thread 1. The 
  7924. application runs when the system scheduler gives control to a thread in the 
  7925. process. For more on thread management, see Using Threads. 
  7926.  
  7927. Note:  In the example code fragments that follow, error checking was left out 
  7928.        to conserve space. Applications should always check the return code that 
  7929.        the functions return. Control Program functions return an APIRET value. 
  7930.        A return code of 0 indicates success. If a non-zero value is returned, 
  7931.        an error occurred. 
  7932.  
  7933.  
  7934. ΓòÉΓòÉΓòÉ 11.3.1. Starting a Child Process ΓòÉΓòÉΓòÉ
  7935.  
  7936. You start a process by calling DosExecPgm. The process you start is a child of 
  7937. the calling, or parent, process and inherits many of the resources owned by the 
  7938. parent process, such as file handles. 
  7939.  
  7940. DosExecPgm creates a process environment from an executable file. The target 
  7941. program is loaded into storage, and it begins execution. 
  7942.  
  7943. The following code fragment starts an application named ABC: 
  7944.  
  7945.     #define INCL_DOSPROCESS       /* Process and thread values */
  7946.     #include <os2.h>
  7947.  
  7948.     CHAR szFailName[CCHMAXPATH];
  7949.     RESULTCODES resc;
  7950.  
  7951.     DosExecPgm(szFailName,           /* Object-name buffer  */
  7952.                sizeof(szFailName),   /* Length of buffer    */
  7953.                EXEC_SYNC,            /* Sync flag           */
  7954.                (PSZ) NULL,           /* Argument string     */
  7955.                (PSZ) NULL,           /* Environment string  */
  7956.                &resc,                /* Address for result  */
  7957.                "ABC.EXE");           /* Name of application */
  7958.  
  7959.  
  7960. Starting a Child Process 
  7961.  
  7962. In this example, ABC runs synchronously (as specified by EXEC_SYNC). This means 
  7963. the parent process temporarily stops while the child process runs. The parent 
  7964. process does not continue until the child process ends. 
  7965.  
  7966.  
  7967. ΓòÉΓòÉΓòÉ 11.3.1.1. Starting an Asynchronous Child Process ΓòÉΓòÉΓòÉ
  7968.  
  7969. To start a child process and enable it to run asynchronously (that is, without 
  7970. suspending the parent process until the child process ends), you use the 
  7971. EXEC_ASYNC constant in a call to DosExecPgm. If you start a process in this 
  7972. way, the function copies the process identifier of the child process to the 
  7973. codeTerminate field of the RESULTCODES structure that is returned by 
  7974. DosExecPgm. You can use this process identifier to check the progress of the 
  7975. child process or to terminate the process. 
  7976.  
  7977. You can also run a child process asynchronously by using DosExecPgm with the 
  7978. EXEC_ASYNCRESULT constant. In addition to causing DosExecPgm to return to the 
  7979. parent process immediately, this constant also directs the operating system to 
  7980. save a copy of the termination status when the child process terminates. This 
  7981. status specifies the reason the child process stopped. The parent process can 
  7982. retrieve the termination status by using DosWaitChild. 
  7983.  
  7984. The following code fragment starts the program SIMPLE.EXE, and then waits for 
  7985. it to finish. It then prints the termination code and the return code. 
  7986.  
  7987.     #define INCL_DOSPROCESS       /* Process and thread values */
  7988.     #include <os2.h>
  7989.     #include <stdio.h>
  7990.  
  7991.     #define START_PROGRAM "SIMPLE.EXE"
  7992.  
  7993.     CHAR         LoadError[100];
  7994.     PSZ          Args;
  7995.     PSZ          Envs;
  7996.     RESULTCODES  ReturnCodes;
  7997.     APIRET       rc;
  7998.  
  7999.     rc = DosExecPgm(LoadError,           /* Object name buffer           */
  8000.                     sizeof(LoadError),   /* Length of object name buffer */
  8001.                     EXEC_SYNC,           /* Asynchronous/Trace flags     */
  8002.                     Args,                /* Argument string              */
  8003.                     Envs,                /* Environment string           */
  8004.                     &ReturnCodes,        /* Termination codes            */
  8005.                     START_PROGRAM);      /* Program file name            */
  8006.  
  8007.     printf("Termination Code %d  Return Code %d \n",
  8008.            ReturnCodes.codeTerminate,
  8009.            ReturnCodes.codeResult);
  8010.  
  8011. ----------------SIMPLE.EXE------------------
  8012.  
  8013.     #define INCL_DOSPROCESS       /* Process and thread values */
  8014.     #include <os2.h>
  8015.     #include <stdio.h>
  8016.  
  8017.     #define RETURN_CODE 0
  8018.  
  8019.     main()
  8020.     {
  8021.         printf("Hello!\n");
  8022.         DosExit(EXIT_PROCESS,     /* End the thread or process */
  8023.                 RETURN_CODE);     /* Result code               */
  8024.     }
  8025.  
  8026.  
  8027. Retrieving the Termination Status of a Child Process 
  8028.  
  8029.  
  8030. ΓòÉΓòÉΓòÉ 11.3.1.2. Starting a Background Process ΓòÉΓòÉΓòÉ
  8031.  
  8032. You can start a child process in the background by specifying the 
  8033. EXEC_BACKGROUND constant in DosExecPgm. A background process runs independently 
  8034. of the parent process and is called a detached process. A detached process 
  8035. should not require any input from the keyboard or output to the video screen, 
  8036. but it can use interprocess communication, such as pipes, queues, and shared 
  8037. memory. 
  8038.  
  8039. The following code fragment starts the program BATCH.EXE in the background. 
  8040.  
  8041.     #define INCL_DOSPROCESS       /* Process and thread values */
  8042.     #include <os2.h>
  8043.     #include <stdio.h>
  8044.  
  8045.     #define START_PROGRAM "BATCH.EXE"
  8046.  
  8047.     CHAR         LoadError[100];
  8048.     PSZ          Args;
  8049.     PSZ          Envs;
  8050.     RESULTCODES  ReturnCodes;
  8051.     APIRET       rc;
  8052.  
  8053.     rc = DosExecPgm(LoadError,           /* Object name buffer           */
  8054.                     sizeof(LoadError),   /* Length of object name buffer */
  8055.                     EXEC_BACKGROUND,     /* Asynchronous/Trace flags     */
  8056.                     Args,                /* Argument string              */
  8057.                     Envs,                /* Environment string           */
  8058.                     &ReturnCodes,        /* Termination codes            */
  8059.                     START_PROGRAM);      /* Program file name            */
  8060.  
  8061.     if (rc != 0) {
  8062.         printf("DosExecPgm error: return code = %ld", rc);
  8063.         return;
  8064.     }
  8065.  
  8066.  
  8067. Starting a Background Child Process 
  8068.  
  8069.  
  8070. ΓòÉΓòÉΓòÉ 11.3.1.3. Setting the Command Line and Environment for a Child Process ΓòÉΓòÉΓòÉ
  8071.  
  8072. When you start a process, it inherits many of the resources of the parent. This 
  8073. includes file handles, such as the standard input and standard output files. A 
  8074. child process also inherits the resources of the screen group, such as the 
  8075. mouse and video modes, and the environment variables of the parent process. 
  8076.  
  8077. The call to DosExecPgm determines the command line and environment that the 
  8078. child process receives. The fourth and fifth parameters of the function are 
  8079. pointers to the command line and the environment, respectively. If these 
  8080. pointers are NULL, the child process receives nothing for a command line and 
  8081. only an exact duplicate of the environment of the parent process. The parent 
  8082. process can modify this information by creating a string (ending with two NULL 
  8083. characters) and passing the address of the string to the function. The command 
  8084. line string must include the name of the application, followed by a NULL 
  8085. character, and the command line arguments, followed by two NULL characters. Any 
  8086. number of arguments can be passed to the child process, as long as the argument 
  8087. string ends with two NULL characters. 
  8088.  
  8089. The following code fragment passes to the child process the string "test 
  8090. -option1 -option2" as its command line: 
  8091.  
  8092.     #define INCL_DOSPROCESS    /* Process and thread values */
  8093.     #include <os2.h>
  8094.  
  8095.     RESULTCODES resc;
  8096.     CHAR szFailName[CCHMAXPATH];
  8097.  
  8098.     CHAR szCommandLine[] = "test\0-option1 -option2\0";
  8099.  
  8100.     DosExecPgm(szFailName,          /* Object-name buffer  */
  8101.                sizeof(szFailName),  /* Length of buffer    */
  8102.                EXEC_SYNC,           /* Sync flag           */
  8103.                szCommandLine,       /* Argument string     */
  8104.                (PSZ) NULL,          /* Environment string  */
  8105.                &resc,               /* Address of result   */
  8106.                "test.exe");         /* Name of application */
  8107.  
  8108.  
  8109. Setting the Command Line Environment for a Child Process 
  8110.  
  8111.  
  8112. ΓòÉΓòÉΓòÉ 11.3.2. Changing the Priority of a Process ΓòÉΓòÉΓòÉ
  8113.  
  8114. Changing the priority of a process is simply a matter of changing the priority 
  8115. of every thread executing in the process. For the details see the section on 
  8116. changing thread priorities, Changing the Priority of a Thread. 
  8117.  
  8118.  
  8119. ΓòÉΓòÉΓòÉ 11.3.3. Obtaining Information about Child Processes ΓòÉΓòÉΓòÉ
  8120.  
  8121. The operating system creates and maintains a Process Information Block for 
  8122. every process. An application can use DosGetThreadInfo to access the Process 
  8123. Information Block. This function returns a pointer to a PIB data structure, 
  8124. which contains the information from the Process Information Block. 
  8125.  
  8126. The following code fragment returns the address of the Process Information 
  8127. Block of the current process. The calling thread can subsequently browse either 
  8128. the PIB block. 
  8129.  
  8130.     #define INCL_DOSPROCESS     /* Process and thread values */
  8131.     #include <os2.h>
  8132.  
  8133.     PTIB     ptib;      /* Address of pointer to Thread Information Block  */
  8134.     PPIB     ppib;      /* Address of pointer to Process Information Block */
  8135.     APIRET  rc;         /* Return code                                     */
  8136.  
  8137.     rc = DosGetInfoBlocks(&ptib, &ppib);
  8138.  
  8139.  
  8140. Obtaining Information about a Child Process 
  8141.  
  8142. DosGetThreadInfo also returns the address of the Thread Information Block of 
  8143. the current thread. 
  8144.  
  8145.  
  8146. ΓòÉΓòÉΓòÉ 11.3.4. Waiting for a Child Process to Terminate ΓòÉΓòÉΓòÉ
  8147.  
  8148. You can synchronize the execution of a process with the execution of one of its 
  8149. child processes by calling DosWaitChild. DosWaitChild does not return until the 
  8150. specified child process terminates. This can be useful, for example, if the 
  8151. parent process needs to ensure that the child process has completed its task 
  8152. before the parent process continues with its own task. 
  8153.  
  8154. In the following code fragment, the parent process starts a child process and 
  8155. then waits for the child process to finish: 
  8156.  
  8157.     #define INCL_DOSPROCESS     /* Process and thread values */
  8158.     #include <os2.h>
  8159.  
  8160.     RESULTCODES resc;
  8161.     PID pidEnded;
  8162.     CHAR szFailName[CCHMAXPATH];
  8163.  
  8164.     CHAR szCommandLine[] = "APP\0test\0";
  8165.  
  8166.     DosExecPgm(szFailName,              /* Failed-name buffer     */
  8167.                sizeof(szFailName),      /* Length of buffer       */
  8168.                EXEC_ASYNC,              /* Sync flag              */
  8169.                szCommandLine,           /* Argument string        */
  8170.                (PSZ) NULL,              /* Environment string     */
  8171.                &resc,                   /* Address of result      */
  8172.                "APP.EXE");              /* Name of application    */
  8173.  
  8174.     DosWaitChild(DCWA_PROCESS,          /* Only the process       */
  8175.                  DCWW_WAIT,             /* Waits until it is done */
  8176.                  &resc,                 /* Puts the result here   */
  8177.                  &pidEnded,             /* PID of ended process   */
  8178.                  resc.codeTerminate);   /* Child to wait for      */
  8179.  
  8180.  
  8181. Waiting for a Child Process to End 
  8182.  
  8183. You can cause a process to wait for all its child processes to end by using the 
  8184. DCWA_PROCESSTREE constant in the call to DosWaitChild. 
  8185.  
  8186.  
  8187. ΓòÉΓòÉΓòÉ 11.3.5. Ending the Current Process ΓòÉΓòÉΓòÉ
  8188.  
  8189. You terminate the current process by calling DosExit. When you exit, the system 
  8190. stops the process and frees any existing resources the process owns. 
  8191.  
  8192. In the following code fragment, DosExit is used to terminate the process if the 
  8193. given file does not exist: 
  8194.  
  8195.     #define INCL_DOSPROCESS     /* Process and thread values */
  8196.     #include <os2.h>
  8197.  
  8198.     #define HF_STDERR 2         /* Standard error handle     */
  8199.  
  8200.     HFILE   hf;
  8201.     ULONG   ulAction, cbWritten;
  8202.     APIRET  rc;
  8203.  
  8204.     rc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL,
  8205.          FILE_OPEN, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE, (PEAOP2) NULL);
  8206.  
  8207.     if (rc) {
  8208.         DosWrite(HF_STDERR, "Cannot open file\r\n", 18, &cbWritten);
  8209.         DosExit(EXIT_PROCESS, rc);
  8210.     }
  8211.  
  8212.  
  8213. Ending the Current Process 
  8214.  
  8215. EXIT_PROCESS directs DosExit to terminate all the threads in a process 
  8216. including the calling thread, thus terminating the process. DosExit includes an 
  8217. error value that is returned to the parent process through the RESULTCODES 
  8218. structure specified in the DosExecPgm call that started the process. If you 
  8219. started the application from the command line, the command processor, CMD.EXE, 
  8220. makes this value available through the ERRORLEVEL variable. If another process 
  8221. started the application, that process can call DosWaitChild to determine the 
  8222. error value. 
  8223.  
  8224. If you want to exit only from a given thread, you can call DosExit with the 
  8225. EXIT_THREAD constant. This will terminate only the calling thread;  other 
  8226. threads in the process are not affected. If the thread you terminate is the 
  8227. last thread in the process, the process also terminates. If the thread consists 
  8228. of a function, the thread terminates when the function returns. 
  8229.  
  8230.  
  8231. ΓòÉΓòÉΓòÉ 11.3.6. Terminating a Process ΓòÉΓòÉΓòÉ
  8232.  
  8233. A process can terminate the execution of a descendant process by calling 
  8234. DosKillProcess. This causes the operating system to send a XCPT_SIGNAL_KILLPROC 
  8235. exception to the target process. The child processes of the target process can 
  8236. also be terminated. 
  8237.  
  8238. The following code fragment terminates the specified process and all child 
  8239. processes belonging to that process: 
  8240.  
  8241.     #define INCL_DOSPROCESS       /* Process and thread values */
  8242.     #include <os2.h>
  8243.  
  8244.     PID pidProcess;
  8245.  
  8246.     DosKillProcess(DKP_PROCESSTREE, pidProcess);
  8247.  
  8248. Terminating a Process 
  8249.  
  8250. In this example, the pidProcess parameter specifies which descendant process to 
  8251. terminate. The process identifier is returned by DosExecPgm in the 
  8252. codeTerminate field of the RESULTCODES structure when you start the child 
  8253. process. 
  8254.  
  8255. The parameter DKP_PROCESSTREE in the example indicates that the specified 
  8256. process, pidProcess, and all of its descendant processes are to be terminated. 
  8257.  
  8258. If you specify DKP_PROCESS in a call to DosKillProcess, only the specified 
  8259. process is terminated. Its child processes, if any, continue to run. 
  8260.  
  8261. The process to be terminated must either be the current process, or it must 
  8262. have been directly created by the current process with DosExecPgm for 
  8263. asynchronous execution. That is, a process can terminate itself and its 
  8264. descendants. 
  8265.  
  8266. The process to be terminated need not still be executing. If it has started its 
  8267. own child processes, but has stopped executing, its children can still be 
  8268. flagged for termination. 
  8269.  
  8270. Obtaining the Termination Status of a Child Process 
  8271. The operating system saves the termination status for a process if the process 
  8272. was started by using the EXEC_ASYNCRESULT constant in the call to DosExecPgm. 
  8273. You can retrieve the termination status of the most recently terminated process 
  8274. by using the DCWW_NOWAIT constant with DosWaitChild and setting the child 
  8275. process identification parameter to 0. The DCWW_NOWAIT constant directs the 
  8276. function to return immediately, without waiting for a process to end. Instead, 
  8277. the function retrieves the termination status from the process that most 
  8278. recently ended. If you specify a child process identification with DCWW_NOWAIT, 
  8279. DosWaitChild returns ERROR_CHILD_NOT_COMPLETE if the child process has not 
  8280. terminated. Once the specified process has ended, DosWaitChild returns its 
  8281. termination code. 
  8282.  
  8283. The following code fragment starts a child session (the program SIMPLE.EXE), 
  8284. and then retrieves the termination status from the process that most recently 
  8285. ended. 
  8286.  
  8287.     #define INCL_DOSPROCESS         /* Process and thread values */
  8288.     #include <os2.h>
  8289.     #include <stdio.h>
  8290.  
  8291.     #define START_PROGRAM "SIMPLE.EXE"
  8292.  
  8293.     CHAR         LoadError[100];
  8294.     PSZ          Args;
  8295.     PSZ          Envs;
  8296.     RESULTCODES  ReturnCodes;
  8297.     ULONG        Pid;           /* Process ID (returned)             */
  8298.     ULONG        Target;        /* Process ID of process to wait for */
  8299.     APIRET       rc;            /* Return code                       */
  8300.  
  8301.     strcpy(Args, "-a2 -l");     /* Pass arguments "-a2" and "-l"     */
  8302.  
  8303.     Target = 0;       /* Process ID for the most recently terminated process   */
  8304.  
  8305.     rc = DosExecPgm(LoadError,            /* Object name buffer                */
  8306.                     sizeof(LoadError),    /* Length of object name buffer      */
  8307.                     EXEC_ASYNCRESULT,     /* Asynchronous/Trace flags          */
  8308.                     Args,                 /* Argument string                   */
  8309.                     Envs,                 /* Environment string                */
  8310.                     &ReturnCodes,         /* Termination codes                 */
  8311.                     START_PROGRAM);       /* Program file name                 */
  8312.  
  8313.     if (rc != 0) {
  8314.         printf("DosExecPgm error: return code = %ld", rc);
  8315.         return;
  8316.     }
  8317.  
  8318.     rc = DosWaitChild(DCWA_PROCESS,       /* Execution options                 */
  8319.                       DCWW_NOWAIT,        /* Wait options                      */
  8320.                       &ReturnCodes,       /* Termination codes                 */
  8321.                       &Pid,               /* Process ID (returned)             */
  8322.                       Target);            /* Process ID of process to wait for */
  8323.     if (rc != 0) {
  8324.         printf("DosWaitChild error: return code = %ld", rc);
  8325.         return;
  8326.     }
  8327.  
  8328.  
  8329. Obtaining the Termination Status of a Child Process 
  8330.  
  8331.  
  8332. ΓòÉΓòÉΓòÉ 11.3.7. Creating an Exit List ΓòÉΓòÉΓòÉ
  8333.  
  8334. You call DosExitList to add to the exit list a routine that is to be given 
  8335. control when a process is terminated (or finishes its execution). Multiple 
  8336. routines can be added to the list. When the process is terminating, the 
  8337. operating system transfers control to each address on the list. 
  8338.  
  8339. If there are multiple addresses on the list, each function gets control in 
  8340. numerical order (with 0 being first and 0FFH being last), based on a value 
  8341. supplied by the application when it calls DosExitList. In case of duplicate 
  8342. entries for this parameter, the routines will be executed in LIFO (last in, 
  8343. first out) order. 
  8344.  
  8345. DosExitList requires a function code that specifies an action and a pointer to 
  8346. the function that is to receive control upon termination. 
  8347.  
  8348. The following code fragment adds the locally defined function SaveFiles to the 
  8349. exit list: 
  8350.  
  8351.     #define INCL_DOSPROCESS         /* Process and thread values */
  8352.     #include <os2.h>
  8353.  
  8354.     #define HF_STDOUT 1             /* Standard output handle    */
  8355.  
  8356.     VOID main(VOID)
  8357.     {
  8358.         .
  8359.         .
  8360.         .
  8361.         DosExitList(EXLST_ADD, (PFNEXITLIST) SaveFiles);
  8362.         .
  8363.         .
  8364.         .
  8365.         DosExit(EXIT_PROCESS, 0);
  8366.     }
  8367.  
  8368.     VOID APIENTRY SaveFiles(ULONG ulTermCode)
  8369.     {
  8370.         ULONG cbWritten;
  8371.  
  8372.         switch (ulTermCode) {
  8373.             case TC_EXIT:
  8374.             case TC_KILLPROCESS:
  8375.                  DosWrite(HF_STDOUT, "Goodbye\r\n", 10, &cbWritten);
  8376.                  break;
  8377.  
  8378.             case TC_HARDERROR:
  8379.             case TC_TRAP:
  8380.                  break;
  8381.  
  8382.         }
  8383.         DosExitList(EXLST_EXIT, 0);
  8384.     }
  8385.  
  8386.  
  8387. Exit List Routines 
  8388.  
  8389. Any function that you add to the list must take one parameter. The function can 
  8390. carry out any task, as shown in the preceding example, but as its last action 
  8391. it must call DosExitList, specifying the EXLST_EXIT constant. An exit-list 
  8392. function must not have a return value and must not call DosExit to terminate. 
  8393.  
  8394. When an exit-list routine receives control, the parameter (located at ESP+4 on 
  8395. the stack) contains an indicator of why the process ended. The values returned 
  8396. are the same as those for termination codes returned by DosWaitChild or 
  8397. DosExecPgm requests. These values are: 
  8398.  
  8399. TC_EXIT (0)           Normal exit 
  8400. TC_HARDERROR (1)      Hard-error halt 
  8401. TC_TRAP (2)           Trap operation for a 16-bit child process 
  8402. TC_KILLPROCESS (3)    Unintercepted DosKillProcess 
  8403. TC_EXCEPTION (4)      Exception operation for a 32-bit child process 
  8404.  
  8405. To execute the exit-list functions, the operating system reassigns thread 1 
  8406. after terminating all other threads in the process. If thread 1 has already 
  8407. exited (for example, if it called DosExit without terminating other threads in 
  8408. the process), the exit-list functions cannot be executed. In general, it is 
  8409. poor practice to terminate thread 1 without terminating all other threads. 
  8410.  
  8411. Before transferring control to the termination routines, the operating system 
  8412. resets the stack to its initial value. Transfer is by way of an assembly 
  8413. language JMP instruction. The routine must be in the address space of the 
  8414. terminating process. The termination routine at that address takes the 
  8415. necessary steps and then calls DosExitList with FunctionOrder=EXLST_EXIT. 
  8416. Control is then transferred to the next address in the invocation order of the 
  8417. exit list. When all such addresses have been processed, the process completes 
  8418. exiting. If a routine on the list does not call DosExitList at the completion 
  8419. of its processing, the process waits, and the operating system prevents 
  8420. termination. 
  8421.  
  8422. During DosExitList processing, the process is in a state of partial 
  8423. termination. All threads of the process are terminated, except for the one 
  8424. executing the exit-list routines. To ensure good response to a user request to 
  8425. end a program, there should be minimal delay in completing termination. 
  8426. Termination routines should be short and fail-safe. 
  8427.  
  8428. You can use DosExitList with the EXLST_REMOVE constant to remove a function 
  8429. from the list. 
  8430.  
  8431. The designer of an exit-list routine must carefully consider which functions 
  8432. will be used by the routine. In general, calls to most OS/2 functions are valid 
  8433. in a DosExitList routine, but certain functions, such as DosCreateThread and 
  8434. DosExecPgm, are not. 
  8435.  
  8436.  
  8437. ΓòÉΓòÉΓòÉ 11.4. Using Threads ΓòÉΓòÉΓòÉ
  8438.  
  8439. A thread is a dispatchable unit of execution that consists of a set of 
  8440. instructions, related CPU register values, and a stack. Every process has at 
  8441. least one thread and can have many threads running at the same time. The 
  8442. application runs when the operating system gives control to a thread in the 
  8443. process. The thread is the basic unit of execution scheduling. 
  8444.  
  8445. Every process has at least one thread, called the main thread or thread 1. To 
  8446. execute different parts of an application simultaneously, you can start several 
  8447. threads. 
  8448.  
  8449. A new thread inherits all the resources currently owned by the process. This 
  8450. means that if you opened a file before creating the thread, the file is 
  8451. available to the thread. Similarly, if the new thread creates or opens a 
  8452. resource, such as another file, that resource is available to the other threads 
  8453. in the process. 
  8454.  
  8455.  
  8456. ΓòÉΓòÉΓòÉ 11.4.1. Creating a Thread ΓòÉΓòÉΓòÉ
  8457.  
  8458. You use DosCreateThread to create a new thread for a process. DosCreateThread 
  8459. requires the address of the code to execute and a variable to receive the 
  8460. identifier of the thread. The address of the code is typically the address of a 
  8461. function that is defined within the application. 
  8462.  
  8463. You can pass one ULONG parameter to the thread when you start it. To pass more 
  8464. information to the thread, pass the address of a data structure. 
  8465.  
  8466. You specify how you want the thread to run when you call DosCreateThread. If 
  8467. bit 1 of the flag parameter in the function call is 0, the thread starts 
  8468. immediately. If bit 1 of the flag parameter is 1, the thread starts suspended 
  8469. and will not run until the application calls DosResumeThread. 
  8470.  
  8471. Each thread maintains its own stack. You specify the size of the stack when you 
  8472. call DosCreateThread. The amount of space needed depends on a number of 
  8473. factors, including the number of function calls the thread makes and the number 
  8474. of parameters and local variables used by each function. If you plan to call 
  8475. OS/2 functions, a reasonable stack size is 8192 bytes (8KB); 4096 bytes (4KB) 
  8476. should be the absolute minimum. If bit 1 of the flag parameter is 0, the 
  8477. operating system uses the default method for initializing the thread's stack. 
  8478. If bit 1 of the flag parameter is 1, memory for the thread's entire stack is 
  8479. pre-committed. 
  8480.  
  8481. The following code fragment creates a thread: 
  8482.  
  8483.     #define INCL_DOSPROCESS         /* Process and thread values */
  8484.     #include <os2.h>
  8485.  
  8486.     #define HF_STDOUT 1             /* Standard output handle    */
  8487.  
  8488.     VOID main(VOID)
  8489.     {
  8490.         ULONG ulBeepLen;
  8491.         TID   tidThread;
  8492.  
  8493.         ulBeepLen = 1000;
  8494.         .
  8495.         DosCreateThread(&tidThread,   /* Thread ID returned by DosCreateThread */
  8496.                         ThreadFunc,   /* Address of the thread function        */
  8497.                         ulBeepLen,    /* Parameter passed to thread            */
  8498.                         0,            /* Immediate execution, default stack    */
  8499.                                       /* initialization                        */
  8500.                         4096);        /* Stack size                            */
  8501.         .
  8502.         .
  8503.         .
  8504.         DosExit(EXIT_PROCESS, 0);
  8505.     }
  8506.  
  8507.     VOID ThreadFunc(ULONG ulBeepLen)
  8508.     {
  8509.         DosBeep(750, ulBeepLen);
  8510.  
  8511.         DosWrite(HF_STDOUT, "Message from new thread\r\n", 25, 0);
  8512.     }
  8513.  
  8514.  
  8515. Creating a Thread 
  8516.  
  8517. A thread continues to run until it calls DosExit, returns control to the 
  8518. operating system, or is terminated by a DosKillThread call. In the preceding 
  8519. example, the thread exits when the function implicitly returns control at the 
  8520. end of the function. 
  8521.  
  8522.  
  8523. ΓòÉΓòÉΓòÉ 11.4.2. Obtaining Information about a Thread ΓòÉΓòÉΓòÉ
  8524.  
  8525. The operating system creates and maintains a Thread Information Block for each 
  8526. thread. An application can use DosGetThreadInfo to access the Thread 
  8527. Information Block. This function returns a pointer to a TIB data structure. 
  8528.  
  8529. The following code fragment returns the address of the Thread Information Block 
  8530. of the current thread. The calling thread can subsequently browse the TIB 
  8531. control block. 
  8532.  
  8533.     #define INCL_DOSPROCESS     /* Process and thread values */
  8534.     #include <os2.h>
  8535.  
  8536.     PTIB     ptib;      /* Address of pointer to Thread Information Block  */
  8537.     PPIB     ppib;      /* Address of pointer to Process Information Block */
  8538.     APIRET  rc;         /* Return code                                     */
  8539.  
  8540.     rc = DosGetInfoBlocks(&ptib, &ppib);
  8541.  
  8542.  
  8543. Obtaining Information about a Thread 
  8544.  
  8545. DosGetThreadInfo also returns the address of the Process Information Block of 
  8546. the current process. 
  8547.  
  8548.  
  8549. ΓòÉΓòÉΓòÉ 11.4.3. Changing the Priority of a Thread ΓòÉΓòÉΓòÉ
  8550.  
  8551. You can use DosSetPriority to change the execution priority of threads in a 
  8552. process. The execution priority defines when or how often a thread receives an 
  8553. execution time slice. Threads with higher priorities receive time slices before 
  8554. those with lower priorities. When a thread that is higher in priority than the 
  8555. currently running thread becomes ready to run, it immediately preempts the 
  8556. lower priority thread (the lower priority thread does not get to complete its 
  8557. time slice). Threads with equal priority receive time slices in a round-robin 
  8558. order. If you raise the priority of a thread, the thread is executed more 
  8559. frequently. 
  8560.  
  8561. You can use DosSetPriority to set the priority for one thread in a process, for 
  8562. all threads in a process (and thus the process itself), or for threads in a 
  8563. child process. 
  8564.  
  8565. A process can change the priority of any thread within itself. When a process 
  8566. changes the priority of threads in a descendant process, however, only those 
  8567. with default priorities are changed. The priority of any thread in a descendant 
  8568. process that has already explicitly changed its priority from the default with 
  8569. DosSetPriority is not changed. 
  8570.  
  8571. In the following code fragment, DosSetPriority lowers the priority of a process 
  8572. to be used as a background process: 
  8573.  
  8574.     #define INCL_DOSPROCESS       /* Process and thread values */
  8575.     #include <os2.h>
  8576.  
  8577.     PTIB ptib;    /* Thread Information Block  */
  8578.     PPIB ppib;    /* Process Information Block */
  8579.  
  8580.     DosGetInfoBlocks(&ptib, &ppib);
  8581.  
  8582.     DosSetPriority(PRTYS_PROCESSTREE, PRTYC_IDLETIME, 0, ppib->pib_ulpid);
  8583.  
  8584.  
  8585. Changing the Priority of a Thread 
  8586.  
  8587. DosGetThreadInfo retrieves the Process Information Blocks and Thread 
  8588. Information Blocks. DosSetPriority then uses the process identifier to change 
  8589. the priority to idle time (idle-time processes receive the least attention by 
  8590. the operating system). 
  8591.  
  8592. If you specify PRTYS_PROCESS when calling DosSetPriority, only the priority of 
  8593. the specified process changes. The priorities of all child processes remain 
  8594. unchanged. 
  8595.  
  8596. If you specify PRTYS_THREAD in the call to DosSetPriority, you must specify a 
  8597. thread identifier as the last parameter.  The priority of the specified thread 
  8598. changes, but the priorities of all other threads in the process remain 
  8599. unchanged. 
  8600.  
  8601. Whenever DosSetPriority is called with a class specification, but no value is 
  8602. specified for priority-delta, the base priority level defaults to 0. 
  8603.  
  8604.  
  8605. ΓòÉΓòÉΓòÉ 11.4.4. Suspending the Current Thread ΓòÉΓòÉΓòÉ
  8606.  
  8607. You can temporarily suspend the execution of the current thread for a set 
  8608. amount of time by using DosSleep. This function suspends execution of the 
  8609. thread for the specified number of milliseconds. DosSleep is useful when you 
  8610. need to delay the execution of a task. For example, you can use DosSleep to 
  8611. delay a response when the user presses a DIRECTION key. The delay provides the 
  8612. user with enough time to observe the results and release the key. 
  8613.  
  8614. The following code fragment uses DosSleep to suspend execution of a thread for 
  8615. 1000 milliseconds (1 second): 
  8616.  
  8617.     #define INCL_DOSPROCESS       /* Process and thread values */
  8618.     #include <os2.h>
  8619.  
  8620.     DosSleep(1000);
  8621.  
  8622.  
  8623. Suspending the Current Thread 
  8624.  
  8625.  
  8626. ΓòÉΓòÉΓòÉ 11.4.5. Suspending and Resuming Execution of a Thread ΓòÉΓòÉΓòÉ
  8627.  
  8628. DosSuspendThread and DosResumeThread are used to temporarily suspend the 
  8629. execution of a thread when it is not needed and resume execution when the 
  8630. thread is needed. 
  8631.  
  8632. These functions are best used when it is necessary for a process to temporarily 
  8633. suspend execution of a thread that is in the middle of a task. For example, 
  8634. consider a thread that opens and reads files from a disk. If other threads in 
  8635. the process do not require input from these files, the process can suspend 
  8636. execution of the thread so that the operating system does not needlessly grant 
  8637. control to it. 
  8638.  
  8639. The specified thread might not be suspended immediately if it has some system 
  8640. resources locked that must be freed first. However, the thread is not permitted 
  8641. to execute further application program instructions until a corresponding 
  8642. DosResumeThread is called. 
  8643.  
  8644. A thread can only suspend another thread that is within its process. 
  8645.  
  8646. DosResumeThread is used to enable the suspended thread to resume execution. 
  8647.  
  8648. The following code fragment temporarily suspends the execution of another 
  8649. thread within the same process. A subsequent call to DosResumeThread restarts 
  8650. the suspended thread. Assume that the thread identifier of the target thread 
  8651. has been placed int ThreadID already. 
  8652.  
  8653.     #define INCL_DOSPROCESS     /* Process and thread values */
  8654.     #include <os2.h>
  8655.     #include <stdio.h>
  8656.  
  8657.     TID     ThreadID;     /* Thread identifier */
  8658.     APIRET  rc;           /* Return code       */
  8659.  
  8660.     rc = DosSuspendThread(ThreadID);
  8661.  
  8662.     if (rc != 0) {
  8663.         printf("DosSuspendThread error: return code = %ld", rc);
  8664.         return;
  8665.     }
  8666.  
  8667.     rc = DosResumeThread(ThreadID);
  8668.  
  8669.     if (rc != 0) {
  8670.         printf("DosResumeThread error: return code = %ld", rc);
  8671.         return;
  8672.     }
  8673.  
  8674.  
  8675. Suspending and Resuming Execution of a Thread 
  8676.  
  8677.  
  8678. ΓòÉΓòÉΓòÉ 11.4.6. Entering Critical Sections ΓòÉΓòÉΓòÉ
  8679.  
  8680. A thread can prevent execution of any of the other threads in its process by 
  8681. calling DosEnterCritSec. This function temporarily prevents a thread from being 
  8682. preempted by other threads within its process. The other threads in the process 
  8683. will not be executed until the current thread calls DosExitCritSec. This 
  8684. enables the calling thread to access a time-critical resource of the process. 
  8685.  
  8686. The following code fragment enters a section that will not be preempted, 
  8687. performs a simple task, and then exits quickly. 
  8688.  
  8689.     #define INCL_DOSPROCESS     /* Process and thread values */
  8690.     #include <os2.h>
  8691.     #include <stdio.h>
  8692.  
  8693.     BOOL    flag;         /* Program control flag */
  8694.     APIRET  rc;           /* Return code          */
  8695.  
  8696.     rc = DosEnterCritSec();
  8697.  
  8698.     if (rc != 0) {
  8699.         printf("DosEnterCritSec error: return code = %ld", rc);
  8700.         return;
  8701.     }
  8702.  
  8703.     flag = TRUE;           /* Set the flag */
  8704.  
  8705.     rc = DosExitCritSec();
  8706.  
  8707.     if (rc != 0) {
  8708.         printf("DosExitCritSec error: return code = %ld", rc);
  8709.         return;
  8710.     }
  8711.  
  8712.  
  8713. Entering and Exiting a Critical Section of Code 
  8714.  
  8715. A count is maintained of the outstanding DosEnterCritSec requests. The count is 
  8716. incremented when a DosEnterCritSec request is made, and decremented when a 
  8717. DosExitCritSec request is made. A DosExitCritSec request will not cause normal 
  8718. thread dispatching to be restored while the count is greater than 0. 
  8719.  
  8720. This count is maintained in a WORD-sized variable. If overflow occurs, the 
  8721. count is set to its maximum value, and an error is returned. The operation is 
  8722. not performed when this occurs. 
  8723.  
  8724. Threads that call DosEnterCritSec must not must not make dynamic link calls 
  8725. within these critical sections. The dynamic link procedure could be using 
  8726. semaphores to serialize a resource. If a thread entering the critical section 
  8727. blocks another thread that already owns the resource which the dynamic link 
  8728. function is about to request, a deadlock occurs. 
  8729.  
  8730. For example, threads of an application are serializing their access to a queue 
  8731. by means of a semaphore. A thread enters a critical section and makes a request 
  8732. to read the queue while another thread already has the semaphore that controls 
  8733. access to the queue. The thread that has the semaphore is now effectively 
  8734. blocked by DosEnterCritSec, and the thread that has requested the queue waits 
  8735. forever to access it. 
  8736.  
  8737. Note:  Thread 1 is the initial thread of execution. It handles all signals 
  8738.        (Ctrl+C, Ctrl+Break, and KillProcess). If a signal occurs while 
  8739.        DosEnterCritSec is active, thread 1 can begin execution to process the 
  8740.        signal. Thread 1 must not access the critical resource that is being 
  8741.        protected by the use of DosEnterCritSec. 
  8742.  
  8743.  
  8744. ΓòÉΓòÉΓòÉ 11.4.7. Waiting for a Thread to Terminate ΓòÉΓòÉΓòÉ
  8745.  
  8746. An application might need to ensure that one thread has finished executing 
  8747. before another thread continues with its own task. For example, one thread 
  8748. might have to finish reading a disk file into memory before another thread can 
  8749. use the information. You can use DosWaitThread to suspend a thread until 
  8750. another thread has terminated. 
  8751.  
  8752. DosWaitThread places the current thread into a wait state until another thread 
  8753. in the current process has terminated. It then returns the thread identifier of 
  8754. the terminating thread. 
  8755.  
  8756. The following code fragment creates three threads. The thread identifier for 
  8757. each thread is returned by DosCreateThread in the atid array. Using &atid[0] as 
  8758. a parameter in the call to DosWaitThread causes the operating system to wait 
  8759. until the thread with that identifier (the thread running Thread2Func) 
  8760. terminates. 
  8761.  
  8762.     #define INCL_DOSPROCESS       /* Process and thread values */
  8763.     #include <os2.h>
  8764.  
  8765.     #define HF_STDOUT 1           /* Standard output handle    */
  8766.  
  8767.     TID atid[3];
  8768.     ULONG cbWritten;
  8769.  
  8770.     DosCreateThread(&atid[0], Thread2Func, 0, 0, 4096);
  8771.     DosCreateThread(&atid[1], Thread3Func, 0, 0, 4096);
  8772.     DosCreateThread(&atid[2], Thread4Func, 0, 0, 4096);
  8773.     DosWaitThread(&atid[0], DCWW_WAIT);
  8774.     DosWrite(HF_STDOUT, "The thread has terminated\r\n", 27, &cbWritten);
  8775.  
  8776.  
  8777. Waiting for a Certain Thread to End 
  8778.  
  8779. If you set the tid parameter to 0 in the call to DosWaitThread, the operating 
  8780. system waits only until the next thread (any thread in the process) terminates. 
  8781. The identifier for the terminated thread is then returned in the tid parameter. 
  8782.  
  8783. After the threads are created as in the preceding example, the following code 
  8784. fragment waits until one of the threads terminates, and then returns its thread 
  8785. identifier: 
  8786.  
  8787.     #define INCL_DOSPROCESS       /* Process and thread values */
  8788.     #include <os2.h>
  8789.  
  8790.     TID tid;
  8791.  
  8792.     tid = 0;
  8793.  
  8794.     DosWaitThread(&tid, DCWW_WAIT);
  8795.  
  8796.  
  8797. Waiting for Any Thread to End 
  8798.  
  8799. The thread identifier of the next thread to terminate after the DosWaitThread 
  8800. call is returned in the tid parameter. 
  8801.  
  8802. You can use DosWaitThread so that you can recover thread resources when the 
  8803. thread terminates, or to synchronize the execution of a thread with the 
  8804. execution of other threads. 
  8805.  
  8806.  
  8807. ΓòÉΓòÉΓòÉ 11.4.8. Ending the Current Thread ΓòÉΓòÉΓòÉ
  8808.  
  8809. To end the execution of the current thread, call DosExit, specifying the action 
  8810. code as 0. It is good practice to end each thread in the application 
  8811. individually. 
  8812.  
  8813. If the thread that is ending is the last thread in the process, or if the 
  8814. request is to terminate all threads in the process, then the process also 
  8815. terminates.  All threads except one are terminated, and that thread executes 
  8816. any routines in the list specified by DosExitList. When this is complete, the 
  8817. resources of the process are released, and the result code that was specified 
  8818. in the DosExit call is passed to any thread that calls DosWaitChild for this 
  8819. process. 
  8820.  
  8821. In the following code fragment, the main routine starts another program, 
  8822. SIMPLE.EXE, and then expects a return code of 3 to be returned. SIMPLE.EXE sets 
  8823. the return code with DosExit. 
  8824.  
  8825.     #define INCL_DOSPROCESS           /* Process and thread values */
  8826.     #include <os2.h>
  8827.     #include <stdio.h>
  8828.  
  8829.     #define START_PROGRAM "SIMPLE.EXE"
  8830.     #define RETURN_OK 3
  8831.  
  8832.     CHAR        LoadError[100];
  8833.     PSZ         Args;
  8834.     PSZ         Envs;
  8835.     RESULTCODES ReturnCodes;
  8836.     APIRET      rc;
  8837.  
  8838.     rc = DosExecPgm(LoadError,                /* Object name buffer           */
  8839.                     sizeof(LoadError),        /* Length of object name buffer */
  8840.                     EXEC_SYNC,                /* Asynchronous/Trace flags     */
  8841.                     Args,                     /* Argument string              */
  8842.                     Envs,                     /* Environment string           */
  8843.                     &ReturnCodes,             /* Termination codes            */
  8844.                     START_PROGRAM);           /* Program file name            */
  8845.  
  8846.     if (ReturnCodes.codeResult == RETURN_OK)  /* Check result code            */
  8847.         printf("Things are ok...");
  8848.     else
  8849.         printf("Something is wrong...");
  8850.  
  8851. ----------------SIMPLE.EXE------------------
  8852.  
  8853.     #define INCL_DOSPROCESS          /* Process and thread values */
  8854.     #include <os2.h>
  8855.     #include <stdio.h>
  8856.  
  8857.     #define RETURN_CODE 3
  8858.  
  8859.     main()
  8860.     {
  8861.         printf("Hello!\n");
  8862.         DosExit(EXIT_THREAD,         /* End thread/process */
  8863.                 RETURN_CODE);        /* Result code        */
  8864.     }
  8865.  
  8866.  
  8867. Ending the Current Thread 
  8868.  
  8869. When you specify DosExit for thread 1 (the initial thread of execution started 
  8870. by the operating system for this process), all of the threads in the process 
  8871. are terminated, and the process is ended. 
  8872.  
  8873.  
  8874. ΓòÉΓòÉΓòÉ 11.4.9. Terminating a Thread ΓòÉΓòÉΓòÉ
  8875.  
  8876. DosKillThread terminates a thread in the current process. DosKillThread enables 
  8877. a thread in a process to terminate any other thread in the process. 
  8878.  
  8879. DosKillThread is used to force a thread within the current process to terminate 
  8880. without causing the entire process to be terminated. 
  8881.  
  8882.     #define INCL_DOSPROCESS       /* Process and thread values */
  8883.     #include <os2.h>
  8884.  
  8885.     TID tidThread;    /* ThreadID of the thread to be terminated */
  8886.  
  8887.     DosCreateThread(&tidThread, ThreadFunction, 0, 0, 4096);
  8888.     .
  8889.     .
  8890.     .
  8891.     DosKillThread(tidThread);
  8892.  
  8893.  
  8894. Terminating a Thread within the Same Process 
  8895.  
  8896. DosKillThread returns to the requestor without waiting for the target thread to 
  8897. complete its termination processing. 
  8898.  
  8899. It is an invalid operation to use DosKillThread to kill the current thread. 
  8900.  
  8901. Terminating thread 1 will cause the entire process to terminate similar to 
  8902. executing DosExit on thread 1. 
  8903.  
  8904. If the target thread is executing 16-bit code or was created by a 16-bit 
  8905. requester, ERROR_BUSY is returned. 
  8906.  
  8907.  
  8908. ΓòÉΓòÉΓòÉ 11.5. Using Sessions ΓòÉΓòÉΓòÉ
  8909.  
  8910. A session consists of at least one process and a virtual console (either full 
  8911. screen, or Presentation Manager window, and buffers for keyboard and mouse 
  8912. input). An application can manage its own child sessions by using 
  8913. DosStartSession, DosStopSession, DosSelectSession, and DosSetSession. 
  8914.  
  8915.  
  8916. ΓòÉΓòÉΓòÉ 11.5.1. Starting a Session ΓòÉΓòÉΓòÉ
  8917.  
  8918. DosStartSession is used to start new sessions and to specify the name of the 
  8919. application to be started in the new session. 
  8920.  
  8921. There are five types of sessions that you can start: full screen, text window, 
  8922. Presentation Manager (PM), full screen DOS Session, and windowed DOS Session. 
  8923. OS/2 applications running in any of the OS/2 session types-full screen, text 
  8924. window, and PM-can start a session for any other application type, including 
  8925. DOS Sessions. Applications running in DOS Sessions cannot start sessions. 
  8926.  
  8927. DosStartSession can be used to start either a foreground or a background 
  8928. session, but a new session can be started in the foreground only when the 
  8929. session of the caller, or one of the descendant sessions of the caller, is 
  8930. currently executing in the foreground. 
  8931.  
  8932. A session can be started as an unrelated session or as a child session. 
  8933.  
  8934. In the following code fragment, an unrelated, foreground session is created, 
  8935. and the application, SIMON.EXE, is started in the new session: 
  8936.  
  8937.     #define INCL_DOSPROCESS       /* Process and thread values */
  8938.     #define INCL_DOSSESMGR
  8939.     #include <os2.h>
  8940.  
  8941.     #define HF_STDOUT 1      /* Standard output handle */
  8942.  
  8943.     STARTDATA  sd;
  8944.     PID        pidProcess;
  8945.     CHAR       szBuf[CCHMAXPATH];
  8946.     ULONG      ulSessionID, cbWritten;
  8947.     APIRET     rc;
  8948.     CHAR       szPgmName[] = "SIMON.EXE";
  8949.  
  8950.     sd.Length = sizeof(sd);                    /* Length of the structure */
  8951.     sd.Related = SSF_RELATED_INDEPENDENT;      /* Unrelated session       */
  8952.     sd.FgBg = SSF_FGBG_FORE;                   /* In the foreground       */
  8953.     sd.TraceOpt = SSF_TRACEOPT_NONE;           /* No tracing              */
  8954.     sd.PgmTitle = (PSZ) NULL;                  /* Title is PgmName        */
  8955.     sd.PgmName = szPgmName;                    /* Address of szPgmName    */
  8956.     sd.PgmInputs = (PBYTE) NULL;               /* No command line args    */
  8957.     sd.TermQ = (PBYTE) NULL;                   /* No terminal queue       */
  8958.     sd.Environment = (PBYTE) NULL;             /* Inherits environment    */
  8959.     sd.InheritOpt = SSF_INHERTOPT_PARENT;      /* Uses parent environment */
  8960.     sd.SessionType = SSF_TYPE_PM;              /* PM session              */
  8961.     sd.IconFile = (PSZ) NULL;                  /* Uses default icon       */
  8962.     sd.PgmHandle = 0;                          /* Used by Win calls       */
  8963.     sd.PgmControl = SSF_CONTROL_MAXIMIZE;      /* Starts app maximized    */
  8964.     sd.InitXPos = 0;                           /* Lower left corner       */
  8965.     sd.InitYPos = 0;                           /* Lower left corner       */
  8966.     sd.InitXSize = 0;                          /* Ignored for maximized   */
  8967.     sd.InitYSize = 0;                          /* Ignored for maximized   */
  8968.     sd.ObjectBuffer = szBuf;                   /* Fail-name buffer        */
  8969.     sd.ObjectBuffLen = sizeof(szBuf);          /* Buffer length           */
  8970.  
  8971.     rc = DosStartSession(&sd, &ulSessionID, &pidProcess);
  8972.  
  8973.     if (rc) {
  8974.         DosBeep(750,250);
  8975.         DosWrite(HF_STDOUT, "error starting new session\r\n", 28, &cbWritten);
  8976.         DosExit(EXIT_PROCESS, rc);
  8977.     }
  8978.  
  8979.  
  8980. Starting a Foreground Session 
  8981.  
  8982. Before calling DosStartSession, you must create a STARTDATA data structure that 
  8983. defines the session to be started. Different lengths for the data structure are 
  8984. supported to provide compatibility and various levels of application control. 
  8985.  
  8986. DosStartSession uses the STARTDATA structure to specify the details of the new 
  8987. session, such as the name of the application to start in the session, whether 
  8988. the new session should be started in the foreground or background, and whether 
  8989. the new session is unrelated or is a child session of the session calling 
  8990. DosStartSession. 
  8991.  
  8992. When a session is created, the title specified in STARTDATA, (or the 
  8993. application title if no title is specified in STARTDATA) is added to the Window 
  8994. List. 
  8995.  
  8996. The Related field in the STARTDATA structure specifies whether the new session 
  8997. is related to the session calling DosStartSession. 
  8998.  
  8999. If the InheritOpt field in the STARTDATA data structure is set to 1, the new 
  9000. session inherits the environment and open file handles of the calling process. 
  9001. This applies for both unrelated and related sessions. 
  9002.  
  9003.  
  9004. ΓòÉΓòÉΓòÉ 11.5.2. Controlling the Execution of Child Sessions ΓòÉΓòÉΓòÉ
  9005.  
  9006. Once a process has started a child session, it can use DosSelectSession to 
  9007. control the child session. 
  9008.  
  9009. A process calls DosSetSession to set the selectability and bonding of a child 
  9010. session. 
  9011.  
  9012.  
  9013. ΓòÉΓòÉΓòÉ 11.5.2.1. Setting User Selectability of a Child Session ΓòÉΓòÉΓòÉ
  9014.  
  9015. A process calls DosSetSession to set the selectability of a child session. 
  9016. When a child session is selectable, the user can select it from the Window List 
  9017. or by using Alt+Esc. When a child session is nonselectable, the user cannot 
  9018. select the session from the Window List or move to it by using the Alt+Esc 
  9019. keys. 
  9020.  
  9021. In the following code fragment, DosSetSession makes a child session 
  9022. nonselectable: 
  9023.  
  9024.     #define INCL_DOSPROCESS       /* Process and thread values */
  9025.     #define INCL_DOSSESMGR
  9026.     #include <os2.h>
  9027.  
  9028.     ULONG ulSessionID;
  9029.     STATUSDATA stsdata;
  9030.  
  9031.     stsdata.Length = sizeof(stsdata);
  9032.     stsdata.SelectInd = SET_SESSION_NON_SELECTABLE;  /* Non-selectable         */
  9033.     stsdata.BondInd = SET_SESSION_UNCHANGED;         /* Leaves session bonding */
  9034.                                                      /* index unchanged        */
  9035.  
  9036.     DosSetSession(ulSessionID, &stsdata);
  9037.  
  9038.  
  9039. Making a Child Session Nonselectable 
  9040.  
  9041. Once a child session is made nonselectable, the user cannot select the session 
  9042. from the Window List or move to it by using the Alt+Esc keys. However, the 
  9043. parent session can still bring the child session to the foreground by using 
  9044. DosSelectSession. If the session contains a Presentation Manager application or 
  9045. is a windowed session, the user will still be able to select it with a mouse. 
  9046.  
  9047. The parent session can make a nonselectable child session selectable by setting 
  9048. the SelectInd field to SET_SESSION_SELECTABLE in the STATUSDATA structure. 
  9049. DosSetSession can be called only by a parent session and only for a child 
  9050. session. That is, the calling process must be the process that started the 
  9051. child session using DosStartSession. Neither the parent session itself nor any 
  9052. grandchild, nor any other descendant session beyond a child session can be the 
  9053. target of this call. 
  9054.  
  9055. Additionally, DosSetSession cannot be used to change the status of a session 
  9056. that was started as an unrelated session. The Related field in the STARTDATA 
  9057. structure must have been set to 1 when the session was started. 
  9058.  
  9059.  
  9060. ΓòÉΓòÉΓòÉ 11.5.2.2. Binding Child Sessions to Parent Sessions ΓòÉΓòÉΓòÉ
  9061.  
  9062. An application can use DosSetSession to establish a bond between a parent 
  9063. session and one of its child sessions. When the two sessions are bound, the 
  9064. operating system brings the child session to the foreground when the user 
  9065. selects the parent session. 
  9066.  
  9067. In the following code fragment, a parent session is bound to the child session 
  9068. specified by the ulSessionID parameter: 
  9069.  
  9070.     #define INCL_DOSPROCESS       /* Process and thread values */
  9071.     #define INCL_DOSSESMGR
  9072.     #include <os2.h>
  9073.  
  9074.     ULONG ulSessionID;
  9075.     STATUSDATA stsdata;
  9076.  
  9077.     stsdata.Length = sizeof(stsdata);
  9078.     stsdata.SelectInd = SET_SESSION_UNCHANGED;   /* Leaves select setting alone */
  9079.     stsdata.BondInd = SET_SESSION_BOND;          /* Binds parent and child      */
  9080.  
  9081.     DosSetSession(ulSessionID, &stsdata);
  9082.  
  9083.  
  9084. Binding a Child Session to a Parent Session 
  9085.  
  9086. When the application uses DosSetSession to establish a parent-child bond, any 
  9087. bond the parent has with another child session is broken. The application can 
  9088. remove the parent-child bond by calling DosSetSession with the BondInd field 
  9089. (in the STATUSDATA structure) set to SET_SESSION_NO_BOND. 
  9090.  
  9091. A parent session can be executing in either the foreground or the background 
  9092. when it calls DosSetSession. 
  9093.  
  9094.  
  9095. ΓòÉΓòÉΓòÉ 11.5.2.3. Switching a Session to the Foreground ΓòÉΓòÉΓòÉ
  9096.  
  9097. An application can bring a session to the foreground, or select the session, by 
  9098. calling DosSelectSession. 
  9099.  
  9100. DosSelectSession can only be used to select the current session or one of the 
  9101. current session's child sessions. It cannot be used to select a grandchild 
  9102. session, or any other descendant session beyond a child session, or any 
  9103. sessions that were started as unrelated sessions. 
  9104.  
  9105. The session making the call, or one of its child sessions, must be executing in 
  9106. the foreground at the time the function is called. A process can call 
  9107. DosSelectSession with its own session identifier to switch itself to the 
  9108. foreground when one of its descendants is executing in the foreground. 
  9109.  
  9110. The following code fragment uses DosSelectSession to switch the child session 
  9111. specified by the ulSessionID parameter to the foreground for five seconds. The 
  9112. application then switches the parent session back to the foreground: 
  9113.  
  9114.     #define INCL_DOSPROCESS       /* Process and thread values */
  9115.     #include <os2.h>
  9116.  
  9117.     ULONG ulSessionID;
  9118.  
  9119.     DosSelectSession(ulSessionID);   /* Switches child to foreground */
  9120.     DosSleep(5000);                  /* Sleeps for 5 seconds         */
  9121.     DosSelectSession(0);             /* Switches parent back         */
  9122.  
  9123.  
  9124. Switching a Child Session to the Foreground 
  9125.  
  9126.  
  9127. ΓòÉΓòÉΓòÉ 11.5.3. Terminating a Session ΓòÉΓòÉΓòÉ
  9128.  
  9129. DosStopSession can be used by a parent session to stop one or all of its child 
  9130. sessions. If the child session specified in the call to DosStopSession has 
  9131. related sessions, the related sessions are also terminated. The parent session 
  9132. can be running in the foreground or the background when it calls 
  9133. DosStopSession. If the child session is running in the foreground when it is 
  9134. terminated, the parent session becomes the foreground session. 
  9135.  
  9136. DosStopSession can only be called by a parent session for a child session. 
  9137. Neither the parent session itself, nor any grandchild, nor any other descendant 
  9138. session beyond a child session, nor any unrelated session, can be the target of 
  9139. this call. 
  9140.  
  9141. In the following code fragment, the child session specified by the ulSessionID 
  9142. parameter is terminated: 
  9143.  
  9144.     #define INCL_DOSPROCESS       /* Process and thread values */
  9145.     #define INCL_DOSSESMGR
  9146.     #include <os2.h>
  9147.  
  9148.     ULONG ulSessionID;
  9149.  
  9150.     DosStopSession(STOP_SESSION_SPECIFIED, ulSessionID);
  9151.  
  9152.  
  9153. Terminating a Child Session 
  9154.  
  9155. An application can terminate all its child sessions by setting the first 
  9156. parameter to STOP_SESSION_ALL in the call to DosStopSession. If this is 
  9157. specified, the second parameter is ignored. 
  9158.  
  9159. A process running in a child session can ignore the request to terminate. If 
  9160. the process has set up its own exception handler, it might not terminate 
  9161. immediately after the call to DosStopSession. The only way the parent process 
  9162. can be certain that the child session has terminated is to wait for 
  9163. notification through the termination queue specified in the call to 
  9164. DosStartSession that started the session. When the child session terminates, 
  9165. the operating system writes a data element into the termination queue, 
  9166. specifying the child process identifier and the termination status. 
  9167.  
  9168. If the process in the session specified by DosStopSession has not ended, then 
  9169. DosStopSession still returns a normal return code. You can ensure that a 
  9170. process in a session has ended by waiting for notification from the termination 
  9171. queue specified with DosStartSession. 
  9172.  
  9173.  
  9174. ΓòÉΓòÉΓòÉ 11.6. Summary of Functions and Data Structures Used for Multitasking ΓòÉΓòÉΓòÉ
  9175.  
  9176. Following are the OS/2 functions and data structures used for multitasking. 
  9177.  
  9178. Program Execution Control Functions 
  9179.  
  9180. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9181. ΓöéThread Control Functions      Γöé                              Γöé
  9182. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9183. ΓöéDosCreateThread               ΓöéCreates an asynchronous threadΓöé
  9184. Γöé                              Γöéof execution under the currentΓöé
  9185. Γöé                              Γöéprocess.                      Γöé
  9186. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9187. ΓöéDosEnterCritSec               ΓöéDisables thread switching for Γöé
  9188. Γöé                              Γöéthe current process.          Γöé
  9189. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9190. ΓöéDosExit                       ΓöéTerminates thread execution inΓöé
  9191. Γöé                              Γöéthe current process.          Γöé
  9192. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9193. ΓöéDosExitCritSec                ΓöéEnables thread switching for  Γöé
  9194. Γöé                              Γöéthe current process.          Γöé
  9195. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9196. ΓöéDosGetThreadInfo              ΓöéObtains the address of the    Γöé
  9197. Γöé                              ΓöéThread Information Block and  Γöé
  9198. Γöé                              Γöéthe Process Information Block.Γöé
  9199. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9200. ΓöéDosKillThread                 ΓöéTerminates a thread in the    Γöé
  9201. Γöé                              Γöécurrent process.              Γöé
  9202. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9203. ΓöéDosResumeThread               ΓöéRestarts a thread that was    Γöé
  9204. Γöé                              Γöépreviously suspended.         Γöé
  9205. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9206. ΓöéDosSetPriority                ΓöéChanges the priority of a     Γöé
  9207. Γöé                              Γöéchild process or thread in theΓöé
  9208. Γöé                              Γöécurrent process.              Γöé
  9209. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9210. ΓöéDosSuspendThread              ΓöéSuspends execution of another Γöé
  9211. Γöé                              Γöéthread within the current     Γöé
  9212. Γöé                              Γöéprocess.                      Γöé
  9213. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9214. ΓöéDosWaitThread                 ΓöéWaits for another thread in   Γöé
  9215. Γöé                              Γöéthe current process to end.   Γöé
  9216. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9217. ΓöéProcess Control Functions     Γöé                              Γöé
  9218. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9219. ΓöéDosExecPgm                    ΓöéExecutes another program as a Γöé
  9220. Γöé                              Γöéchild process.                Γöé
  9221. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9222. ΓöéDosExitList                   ΓöéDefines a list of routines to Γöé
  9223. Γöé                              Γöébe executed when the current  Γöé
  9224. Γöé                              Γöéprocess ends.                 Γöé
  9225. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9226. ΓöéDosGetThreadInfo              ΓöéObtains the address of the    Γöé
  9227. Γöé                              ΓöéThread Information Block and  Γöé
  9228. Γöé                              Γöéthe Process Information Block.Γöé
  9229. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9230. ΓöéDosKillProcess                ΓöéFlags a process or group of   Γöé
  9231. Γöé                              Γöéprocesses for termination.    Γöé
  9232. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9233. ΓöéDosWaitChild                  ΓöéWaits for a child process to  Γöé
  9234. Γöé                              Γöéend.                          Γöé
  9235. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9236. ΓöéSession Control Functions     Γöé                              Γöé
  9237. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9238. ΓöéDosSelectSession              ΓöéSwitches a child session to   Γöé
  9239. Γöé                              Γöéthe foreground.               Γöé
  9240. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9241. ΓöéDosSetSession                 ΓöéSets the status of a child    Γöé
  9242. Γöé                              Γöésession.                      Γöé
  9243. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9244. ΓöéDosStartSession               ΓöéStarts an unrelated or child  Γöé
  9245. Γöé                              Γöésession.                      Γöé
  9246. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9247. ΓöéDosStopSession                ΓöéTerminates one or all child   Γöé
  9248. Γöé                              Γöésessions.                     Γöé
  9249. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9250.  
  9251. Program Execution Control Data Structures 
  9252.  
  9253. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9254. ΓöéData Structure                ΓöéDescription                   Γöé
  9255. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9256. ΓöéRESULTCODES                   ΓöéDescribes the reason a processΓöé
  9257. Γöé                              Γöéterminated and contains the   Γöé
  9258. Γöé                              Γöévalue returned by the process.Γöé
  9259. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9260. ΓöéPIB                           ΓöéProcess Information Block.    Γöé
  9261. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9262. ΓöéSTATUSDATA                    ΓöéData structure for            Γöé
  9263. Γöé                              ΓöéDosSetSession.                Γöé
  9264. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9265. ΓöéSTARTDATA                     ΓöéData structure for            Γöé
  9266. Γöé                              ΓöéDosStartSession.              Γöé
  9267. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9268. ΓöéTIB                           ΓöéThread Information Block.     Γöé
  9269. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9270.  
  9271.  
  9272. ΓòÉΓòÉΓòÉ 12. National Language Support ΓòÉΓòÉΓòÉ
  9273.  
  9274. Many applications need to be independent of a particular language. Rather than 
  9275. being hard-coded in English, they want to support, for example, an English 
  9276. version of the application, and a French version, and a German version; 
  9277. preferably without having to change the program code for each version. Meeting 
  9278. this requirement is simplified through the use of such resources as string 
  9279. tables, menu templates, dialog templates, accelerator tables, and through the 
  9280. use of code pages. 
  9281.  
  9282. This chapter describes the functions an application uses to be NLS enabled, or 
  9283. language independent. 
  9284.  
  9285. The following topic is related to the information in this chapter: 
  9286.  
  9287. o Message Management. 
  9288.  
  9289.  
  9290. ΓòÉΓòÉΓòÉ 12.1. About National Language Support ΓòÉΓòÉΓòÉ
  9291.  
  9292. The support of national languages by applications requires the following 
  9293. considerations: 
  9294.  
  9295. o Displayed text must be translated into the appropriate language. 
  9296.  
  9297. o Symbols or icons might not convey the same meaning in all countries. 
  9298.   Alternative designs for different countries might be necessary. 
  9299.  
  9300. o Translation changes the length of text strings. 
  9301.  
  9302. o Different languages often have different text characters. 
  9303.  
  9304. The use of national language resource files can help with the first three 
  9305. items, and the ability of the application to receive input and display output 
  9306. in any ASCII code page can help with the last item. 
  9307.  
  9308. The use of ASCII code page 850 avoids many of the problems in this area, since 
  9309. it contains most of the characters required for Latin-1 languages, which 
  9310. include much of Western Europe and North and South America. However, older 
  9311. programs use code page 437 for U.S. English, and code pages 860, 863, and 865 
  9312. for various languages. The code page applies to both input and output data. 
  9313.  
  9314. Note:  Code page 850 was used for translating Presentation Manager text. Use 
  9315.        code page 850 whenever possible for all Presentation Manager 
  9316.        applications that might require translation. 
  9317.  
  9318.  
  9319. ΓòÉΓòÉΓòÉ 12.1.1. National Language Resource Files ΓòÉΓòÉΓòÉ
  9320.  
  9321. When creating an application, define national language dependencies in 
  9322. resources that are held in resource files separate from the program code.  That 
  9323. is: 
  9324.  
  9325. o Keep pure text strings in string tables. 
  9326. o Keep menus in menu templates. 
  9327. o Keep dialog boxes in dialog templates. 
  9328. o Keep accelerators in accelerator tables. 
  9329.  
  9330. The language displayed by the application can then be changed by translating 
  9331. the resources, in most cases without changing the application. 
  9332.  
  9333. However, when translating from one language to another, the length of a text 
  9334. string can change substantially. For example, when translating from English to 
  9335. German, the length of a text string can double in length. 
  9336.  
  9337. The following table furnishes a general idea of the amount of expansion that 
  9338. can be expected during translation. 
  9339.  
  9340. Translation Expansion 
  9341.  
  9342. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9343. ΓöéFor English Phrases           ΓöéTranslation Expansion Factors Γöé
  9344. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9345. ΓöéUp to 10 characters           Γöé101 - 200%                    Γöé
  9346. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9347. Γöé11 - 20 characters            Γöé81 - 100%                     Γöé
  9348. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9349. Γöé21 - 30 characters            Γöé61 - 80%                      Γöé
  9350. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9351. Γöé31 - 50 characters            Γöé41 - 60%                      Γöé
  9352. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9353. Γöé51 - 70 characters            Γöé31 - 40%                      Γöé
  9354. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9355. ΓöéOver 70 characters            Γöé30%                           Γöé
  9356. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9357.  
  9358. When designing your dialog boxes and text string messages, add white space to 
  9359. allow for the expansion that will occur when the text is translated. You might 
  9360. have to adapt the application program to allow for the change in the length of 
  9361. text strings after they are translated. For example, a change in the length of 
  9362. a text string can cause it to become misaligned with other displayed objects. 
  9363.  
  9364. You can also use the Dialog Box Editor to adjust for misalignments, or to 
  9365. change the size of the dialog box. This would enable you to leave your 
  9366. application program unchanged. 
  9367.  
  9368. Text strings explicitly displayed by the application program are more of a 
  9369. problem. You will have to include program code that can handle text strings of 
  9370. varying length and format them at runtime according to their size. 
  9371.  
  9372.  
  9373. ΓòÉΓòÉΓòÉ 12.1.2. Language-Specific Versions of NLS-Enabled Applications ΓòÉΓòÉΓòÉ
  9374.  
  9375. There are two methods of creating a specific national language version of a 
  9376. program designed to handle more than one national language. The choice of the 
  9377. method depends on the amount of available disk space and whether the user wants 
  9378. to change between different languages once the program is installed. The two 
  9379. methods are: 
  9380.  
  9381. o Statically link the resources to the application's .EXE files. The executable 
  9382.   files are then language-specific and cannot be changed to another national 
  9383.   language. The specific .EXE files are then sent to the user. 
  9384.  
  9385. o Place the resources into a language-specific, dynamic link library. Designate 
  9386.   one library file for each national language. Selecting a particular library 
  9387.   file for use with the application gives the desired version of the program. 
  9388.   Using this method, all national languages can be shipped with the product; 
  9389.   selection of the national language occurs during installation (for example, 
  9390.   by naming a specific .DLL file). It is possible to change the national 
  9391.   language setting while the program is operating. 
  9392.  
  9393.  
  9394. ΓòÉΓòÉΓòÉ 12.2. About Code Page Management ΓòÉΓòÉΓòÉ
  9395.  
  9396. A code page is a table that defines how the characters in a language or group 
  9397. of languages are encoded. A specific value is given to each character in the 
  9398. code page. For example, in code page 850 the letter "╨┤" (lowercase) is encoded 
  9399. as hex A4 (decimal 164), and the letter "╨╡" (uppercase) is encoded as hex A5 
  9400. (decimal 165). 
  9401.  
  9402. Code page management enables a user to select a code page for keyboard input, 
  9403. and screen and printer output before starting an application, a system command, 
  9404. or a utility program in the OS/2 multitasking environment. 
  9405.  
  9406. This means that a user in a particular country, such as England (code page 
  9407. 850), Norway (code page 865), or a language region such as Canadian French 
  9408. (code page 863) can use a code page that defines an ASCII-based character set 
  9409. containing characters used by that particular country or language. 
  9410.  
  9411. Installable code page files include keyboard translate tables, display 
  9412. character sets, printer character sets, and country/language information for 
  9413. each code page supported. 
  9414.  
  9415. The code page tables are shown in the Presentation Manager Programming 
  9416. Reference. Check the tables to ensure that the code page you plan to use 
  9417. contains the characters that your application needs. 
  9418.  
  9419. Of particular interest are two code pages: 
  9420.  
  9421. o Code Page 850 
  9422. o Code Page 437 
  9423.  
  9424. Code Page 850 (CP850) 
  9425. Code Page 850 is also called the Latin-1, multilingual code page. This code 
  9426. page supports the alphabetic characters of the Latin-1-based languages. It 
  9427. contains characters required by 13 languages used in approximately 40 
  9428. countries. 
  9429.  
  9430. CP850 also provides the flexibility to develop new applications based on 
  9431. non-Latin-based or special industry-based code pages. 
  9432.  
  9433. Code Page 850 supports countries using the following languages: 
  9434.  
  9435. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9436. ΓöéBelgian French                ΓöéCanadian French               Γöé
  9437. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9438. ΓöéDanish                        ΓöéDutch                         Γöé
  9439. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9440. ΓöéFinnish                       ΓöéFlemish                       Γöé
  9441. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9442. ΓöéFrench                        ΓöéGerman                        Γöé
  9443. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9444. ΓöéItalian                       ΓöéNorwegian                     Γöé
  9445. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9446. ΓöéPortuguese                    ΓöéSpanish                       Γöé
  9447. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9448. ΓöéLAD Spanish                   ΓöéSwedish                       Γöé
  9449. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9450. ΓöéSwiss French                  ΓöéSwiss German                  Γöé
  9451. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9452. ΓöéU.K. English                  ΓöéU.S. English                  Γöé
  9453. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9454.  
  9455.  
  9456. Code Page 437 (CP437) 
  9457. Code Page 437 is the standard personal computer code page. 
  9458.  
  9459. The lower 128 characters are based on the 7-bit ASCII code. The upper 128 
  9460. characters contain characters from several European languages (including part 
  9461. of the Greek alphabet) and various graphic characters. However, some of the 
  9462. accented characters, such as those used in the Nordic countries, are not 
  9463. represented. The missing characters are available in other code pages (code 
  9464. page 850 will usually contain the desired characters). 
  9465.  
  9466. Note:  Some of the 256 symbols that can be displayed are printer control 
  9467.        characters, and are not printed. 
  9468.  
  9469.  
  9470. ΓòÉΓòÉΓòÉ 12.2.1. ASCII and EBCDIC Code Page Support ΓòÉΓòÉΓòÉ
  9471.  
  9472. The two leading character-coding systems are ASCII and EBCDIC. Presentation 
  9473. Manager applications can use an EBCDIC code page instead of an ASCII code page. 
  9474. Code pages based on both systems are supported by the OS/2 operating system. 
  9475. Lists of the code pages supported, and tables showing the contents of the code 
  9476. pages, are in the Presentation Manager Programming Reference. 
  9477.  
  9478. Any code page that either is defined in the CONFIG.SYS file, or is one of the 
  9479. EBCDIC code pages supported, can be selected. 
  9480.  
  9481.  
  9482. ΓòÉΓòÉΓòÉ 12.2.2. Code Page Preparation ΓòÉΓòÉΓòÉ
  9483.  
  9484. During system initialization, the code pages specified in the CODEPAGE 
  9485. statement are prepared to enable run-time code page switching of the display, 
  9486. the keyboard, the printer, and the country information. The display, keyboard, 
  9487. and printer must be defined in a DEVINFO statement in order to be prepared. 
  9488. Country information is prepared for the system country code specified in the 
  9489. COUNTRY statement. 
  9490.  
  9491. If a resource cannot be prepared for the selected code page during system 
  9492. initialization, it is prepared for a default code page. The following are the 
  9493. defaults: 
  9494.  
  9495. o A keyboard layout defaults to the code page of the translate table designated 
  9496.   as the default layout in the KEYBOARD.DCP file. The default layout is based 
  9497.   on the national code page of its associated country. You must explicitly 
  9498.   specify KEYBOARD.DCP in the DEVINFO statement for the keyboard in CONFIG.SYS. 
  9499.  
  9500. o The display defaults to the code page of ROM_0 for the device. 
  9501.  
  9502.   (ROM_0 means a device default code page that is the device native code page 
  9503.   or the lowest addressed ROM code page.) 
  9504.  
  9505. o The printer defaults to the code page of ROM_0 for the device. 
  9506.  
  9507.   (ROM_0 means a device default code page that is the device native code page 
  9508.   or the lowest addressed ROM code page.) 
  9509.  
  9510. o The country information defaults to the code page of the first entry found in 
  9511.   the COUNTRY.SYS file for the country code. Each entry is the same information 
  9512.   for a given country code, but is encoded in a different code page. The first 
  9513.   entry is based on the preferred country code page. 
  9514.  
  9515. If country information cannot be prepared at system initialization because it 
  9516. is not found in the COUNTRY.SYS file, for a code page selected with the 
  9517. CODEPAGE statement, then it is prepared (maintained for run-time code page 
  9518. switching in memory) in the default code page. Similarly, a keyboard layout is 
  9519. prepared in its default code page if it cannot be prepared in the selected code 
  9520. page, because it is not found in the KEYBOARD.DCP file. 
  9521.  
  9522. COUNTRY.SYS contains one default entry per country code, and KEYBOARD.DCP 
  9523. contains one default entry per keyboard layout based on these assignments: 
  9524.  
  9525.  
  9526. ΓòÉΓòÉΓòÉ 12.2.3. Code Page Functions ΓòÉΓòÉΓòÉ
  9527.  
  9528. At the system level, the operating system switches the code pages of supported 
  9529. displays and printers to agree with the code page of the process sending the 
  9530. output. At the application level, OS/2 functions enable a process to control 
  9531. code page assignments. 
  9532.  
  9533.  
  9534. ΓòÉΓòÉΓòÉ 12.3. Using Code Pages ΓòÉΓòÉΓòÉ
  9535.  
  9536. The OS/2 operating system provides applications with several functions to 
  9537. obtain information about and manipulate code pages. These functions enable 
  9538. applications to determine and set the current code page. 
  9539.  
  9540. OS/2 code page management functions enable applications to read keyboard input 
  9541. and write display and printer output for multiple processes using ASCII-based 
  9542. data encoded in different code pages. 
  9543.  
  9544. The system switches to the required code page, for a code-page-supported 
  9545. device, before input or output. 
  9546.  
  9547. Note:  In the example code fragments that follow, error checking was left out 
  9548.        to conserve space. Applications should always check the return code that 
  9549.        the functions return. Control Program functions return an APIRET value. 
  9550.        A return code of 0 indicates success. If a non-zero value is returned, 
  9551.        an error occurred. 
  9552.  
  9553.  
  9554. ΓòÉΓòÉΓòÉ 12.3.1. Querying Code Page Support and the Current Code Page ΓòÉΓòÉΓòÉ
  9555.  
  9556. DosQueryCp is used to determine the code page of the current process and the 
  9557. prepared system code pages. The following code fragment shows how to get the 
  9558. current code page, and then up to three other prepared pages: 
  9559.  
  9560.     #define INCL_DOSNLS   /* National Language Support values */
  9561.     #include <os2.h>
  9562.  
  9563.     ULONG  CpList[8];
  9564.     ULONG  CpSize;
  9565.     APIRET rc;    /* Return code */
  9566.  
  9567.     rc = DosQueryCp(sizeof(CpList),    /* Length of list          */
  9568.                     CpList,            /* List                    */
  9569.                     &CpSize);          /* Length of returned list */
  9570.  
  9571. Obtaining the Current Code Page and Other Prepared Code Pages 
  9572.  
  9573. The required code page is the current code page of the process at the time it 
  9574. opens a device, or a specific code page selected by the process with a 
  9575. set-code-page function. A character set can also be specified for some devices, 
  9576. for example, for some printers. 
  9577.  
  9578. The country functions retrieve country- and language-dependent information in 
  9579. the current code page of the calling process, or in a code page selected by the 
  9580. process. 
  9581.  
  9582.  
  9583. ΓòÉΓòÉΓòÉ 12.3.2. Setting the Code Page for Text Characters ΓòÉΓòÉΓòÉ
  9584.  
  9585. Each process has a code page tag maintained by the operating system. A code 
  9586. page tag is the identifier of the current code page for the process. 
  9587.  
  9588. A child process inherits the code page tag of its parent. The default code page 
  9589. for the first process in a session is the same as the session code page. The 
  9590. default code page for a new session is the primary code page specified in the 
  9591. CODEPAGE configuration statement. 
  9592.  
  9593. To change the code page tag of a process, call DosSetProcessCp. This will not 
  9594. change the process code page tag of its parent or any child process. 
  9595.  
  9596.  
  9597. ΓòÉΓòÉΓòÉ 12.3.3. Obtaining the Case Map String ΓòÉΓòÉΓòÉ
  9598.  
  9599. DosMapCase performs case mapping on a string of binary values that represent 
  9600. ASCII characters. 
  9601.  
  9602. The case map that is used is the one in the country file that corresponds to 
  9603. the system country code or selected country code, and to the process code page 
  9604. or selected code page. The default name of the country file is COUNTRY.SYS. 
  9605.  
  9606.  
  9607. ΓòÉΓòÉΓòÉ 12.3.4. Obtaining the DBCS Environment Vector ΓòÉΓòÉΓòÉ
  9608.  
  9609. DosQueryDBCSEnv obtains a double-byte character set (DBCS) environment vector 
  9610. that resides in the country file. The default name of the country file is 
  9611. COUNTRY.SYS. 
  9612.  
  9613. The vector corresponds to the system country code or selected country code, and 
  9614. to the process code page or selected code page. 
  9615.  
  9616. The following code fragment shows how to use DosQueryDBCSEnv: 
  9617.  
  9618.     #define INCL_DOSNLS   /* National Language Support values */
  9619.     #include <os2.h>
  9620.     #include <stdio.h>
  9621.  
  9622.     ULONG         Length;             /* Length of data area provided         */
  9623.     COUNTRYCODE   Structure;          /* Input data structure                 */
  9624.     UCHAR         MemoryBuffer[12];   /* DBCS environmental vector (returned) */
  9625.     APIRET        rc;                 /* Return code                          */
  9626.  
  9627.     Length = 12;                      /* A length of 12 bytes is sufficient   */
  9628.                                       /* to contain the DBCS data returned    */
  9629.  
  9630.     Structure.country = 0;            /* Use the default system country code  */
  9631.  
  9632.     Structure.codepage = 0;           /* Return DBSC information for the      */
  9633.                                       /* caller's current process code page   */
  9634.  
  9635.     rc = DosQueryDBCSEnv(Length, &Structure, MemoryBuffer);
  9636.  
  9637.     if (rc != 0) {
  9638.         printf("DosQueryDBCSEnv error: return code = %ld", rc);
  9639.         return;
  9640.     }
  9641.  
  9642.  
  9643. Obtaining a DBCS Environmental Vector 
  9644.  
  9645. On successful return, the buffer MemoryBuffer will contain the country 
  9646. dependent information for the DBCS environmental vector. 
  9647.  
  9648. Instead of the single-byte character set (SBCS) representation used for Latin 
  9649. text, some Asian countries use code pages that consist of double-byte character 
  9650. set characters, in which each character is represented by a two-byte code. The 
  9651. DBCS code pages enable single-byte data, double-byte data, or mixed 
  9652. (single-byte and double-byte) data. 
  9653.  
  9654.  
  9655. ΓòÉΓòÉΓòÉ 12.3.5. Obtaining Formatting Information ΓòÉΓòÉΓòÉ
  9656.  
  9657. DosQueryCtryInfo obtains country dependent formatting information that resides 
  9658. in the country file. The default name of the country file is COUNTRY.SYS. 
  9659.  
  9660. The information corresponds to the system country code or selected country 
  9661. code, and to the process code page or selected code page. 
  9662.  
  9663.  
  9664. ΓòÉΓòÉΓòÉ 12.3.6. Obtaining Collating Information for SORT ΓòÉΓòÉΓòÉ
  9665.  
  9666. DosQueryCollate obtains a collating sequence table (for characters 00H through 
  9667. FFH) from the country file. The default name of the country file is 
  9668. COUNTRY.SYS. The SORT utility program uses this table to sort text according to 
  9669. the collating sequence. 
  9670.  
  9671. The collating table returned corresponds to the system country code or selected 
  9672. country code, and to the process code page or selected code page. 
  9673.  
  9674.  
  9675. ΓòÉΓòÉΓòÉ 12.4. National Language Support and Code Page Management Summary ΓòÉΓòÉΓòÉ
  9676.  
  9677. Following are the OS/2 functions used in National Language Support and  Code 
  9678. Page Management. 
  9679.  
  9680. Code Page Management Functions 
  9681.  
  9682. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9683. ΓöéCode Page Functions           Γöé                              Γöé
  9684. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9685. ΓöéDosQueryCp                    ΓöéReturns the current code page Γöé
  9686. Γöé                              Γöéand the prepared system code  Γöé
  9687. Γöé                              Γöépages.                        Γöé
  9688. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9689. ΓöéDosSetProcessCp               ΓöéSets the code page of a       Γöé
  9690. Γöé                              Γöéprocess.                      Γöé
  9691. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9692. ΓöéCountry Dependent Functions   Γöé                              Γöé
  9693. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9694. ΓöéDosMapCase                    ΓöéPerforms case mapping on a    Γöé
  9695. Γöé                              Γöéstring of binary values that  Γöé
  9696. Γöé                              Γöérepresent ASCII characters.   Γöé
  9697. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9698. ΓöéDosQueryCollate               ΓöéObtains a collating sequence  Γöé
  9699. Γöé                              Γöétable (for characters 00H     Γöé
  9700. Γöé                              Γöéthrough FFH) that resides in  Γöé
  9701. Γöé                              Γöéthe country file.             Γöé
  9702. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9703. ΓöéDosQueryCtryInfo              ΓöéObtains country-dependent     Γöé
  9704. Γöé                              Γöéformatting information that   Γöé
  9705. Γöé                              Γöéresides in the country file.  Γöé
  9706. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9707. ΓöéDosQueryDBCSEnv               ΓöéObtains a DBCS environment    Γöé
  9708. Γöé                              Γöévector that resides in the    Γöé
  9709. Γöé                              Γöécountry file.                 Γöé
  9710. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9711. ΓöéDosQueryMessageCP             ΓöéRetrieves a message file list Γöé
  9712. Γöé                              Γöéof code pages and language    Γöé
  9713. Γöé                              Γöéidentifiers.                  Γöé
  9714. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9715.  
  9716. Code Page Management Data Structures 
  9717.  
  9718. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9719. ΓöéData Structure                ΓöéDescription                   Γöé
  9720. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9721. ΓöéCOUNTRYCODE                   ΓöéContains the country and code Γöé
  9722. Γöé                              Γöépage.                         Γöé
  9723. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9724. ΓöéCOUNTRYINFO                   ΓöéContains more detailed,       Γöé
  9725. Γöé                              Γöécomplete, information than    Γöé
  9726. Γöé                              ΓöéCOUNTRYINFO.                  Γöé
  9727. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9728.  
  9729.  
  9730. ΓòÉΓòÉΓòÉ 13. Pipes ΓòÉΓòÉΓòÉ
  9731.  
  9732. Communication between processes is valuable in a multitasking operating system 
  9733. to enable concurrent processes to work together. Pipes are one of three forms 
  9734. of interprocess communication (IPC), the other forms of IPC being semaphores 
  9735. and queues. 
  9736.  
  9737. This chapter describes how to create, manage, and use pipes. Pipes enable two 
  9738. or more processes to communicate as if they were reading from and writing to a 
  9739. file. 
  9740.  
  9741. The following topics are related to the information in this chapter: 
  9742.  
  9743. o Memory (Shared Memory) 
  9744. o Program Execution and Control 
  9745. o Semaphores 
  9746. o Queues. 
  9747.  
  9748.  
  9749. ΓòÉΓòÉΓòÉ 13.1. About Pipes ΓòÉΓòÉΓòÉ
  9750.  
  9751. A pipe is a named or unnamed buffer used to pass data between processes. A 
  9752. process writes to or reads from a pipe as if the pipe were standard input or 
  9753. standard output. A parent process can use pipes to control the input that a 
  9754. child process receives and to receive the output that the child process 
  9755. produces. 
  9756.  
  9757. There are two types of pipes-named and unnamed. 
  9758.  
  9759.  
  9760. ΓòÉΓòÉΓòÉ 13.1.1. Unnamed Pipes ΓòÉΓòÉΓòÉ
  9761.  
  9762. An unnamed pipe is a circular buffer in memory. The buffer has in and out 
  9763. pointers that are maintained by the system. 
  9764.  
  9765. An unnamed pipe can transfer information only between related processes. A 
  9766. child process started by a parent process with DosExecPgm inherits the handles 
  9767. to any unnamed pipes created by its parent. This inheritance enables the parent 
  9768. process and the child process to use the unnamed pipe to communicate with one 
  9769. another. This type of pipe is typically used to redirect the standard input and 
  9770. standard output of a child process. 
  9771.  
  9772. To do this, a process opens a pipe and duplicates the read and write handles of 
  9773. the pipe as the standard input and standard output files for the child process. 
  9774. Once the handles are duplicated, the parent process can use DosExecPgm to start 
  9775. the child process. When the child process reads and writes to its standard 
  9776. input and standard output handles, it is reading and writing to the pipe. The 
  9777. parent process can also communicate with the child process through the pipe. 
  9778.  
  9779. Using an unnamed pipe, a text editor could run another program, such as a 
  9780. compiler or assembler, and display the output of the compiler or assembler 
  9781. within the editor. 
  9782.  
  9783. DosCreatePipe creates an unnamed pipe. This function returns two file handles 
  9784. for the pipe, one for writing to the pipe and another for reading from the 
  9785. pipe. A process can then write to the pipe by using DosWrite and read from the 
  9786. pipe by using DosRead. 
  9787.  
  9788. A pipe exists until both handles are closed. The order in which the handles are 
  9789. closed is sometimes important. For example, DosWrite might wait for data to be 
  9790. read from the pipe before completing its operation. In this case, the read 
  9791. handle is closed before the write handle is closed, writing to the pipe 
  9792. generates an error. 
  9793.  
  9794. No control or permission mechanisms or checks are performed on operations to 
  9795. unnamed pipes. 
  9796.  
  9797.  
  9798. ΓòÉΓòÉΓòÉ 13.1.2. Named Pipes ΓòÉΓòÉΓòÉ
  9799.  
  9800. Named pipes enable related or unrelated processes on either the same computer 
  9801. system or different systems to communicate with each other. Any process that 
  9802. knows the name of a pipe can open and use a named pipe. In addition, named pipe 
  9803. data can be transparently redirected across a network, such as a local area 
  9804. network (LAN). (Unnamed pipes, by contrast, can be used only by related 
  9805. processes that are on the same computer system.) 
  9806.  
  9807. One process (the server process) creates the pipe and connects to one end of 
  9808. it. Other processes that access the named pipe are called client processes; 
  9809. they connect to the other end of the pipe. The server and client processes can 
  9810. then pass data back and forth by reading from and writing to the pipe. The 
  9811. server process controls access to the named pipe. 
  9812.  
  9813. The client process can be either local or remote. A local client process is one 
  9814. that runs on the same computer system as the server process. A remote client 
  9815. process runs on a different system and communicates with the server process 
  9816. across a local area network (LAN). 
  9817.  
  9818. When the server process creates a named pipe with DosCreateNPipe, it must 
  9819. specify the direction that data will flow through the pipe. The process 
  9820. specifies an inbound pipe if it intends to read data from the client process, 
  9821. an outbound pipe if it intends to write data to the client process, or a duplex 
  9822. pipe if it intends to read from and write to the client process. 
  9823.  
  9824. The server process also specifies whether data passes through the pipe as bytes 
  9825. or messages. A message is a block of data, with a system-supplied header, that 
  9826. is read or written as a single unit. The server and client processes define the 
  9827. size and format of a message. 
  9828.  
  9829. The server process also specifies whether child processes will inherit the 
  9830. named pipe and how information will be read from and written to the pipe. If 
  9831. the server specifies wait mode, DosRead will be blocked (it will not return to 
  9832. the process) until data is available in the pipe, and DosWrite will be blocked 
  9833. until there is enough room in the pipe to contain the entire data buffer. If 
  9834. the server specifies no-wait mode, reading from an empty pipe or writing to a 
  9835. full pipe immediately returns an error value. 
  9836.  
  9837. A named pipe consists of two pipe buffers, one for each direction of 
  9838. communication. However, each end of the pipe has only one handle associated 
  9839. with it. The server receives the handle for its end when it creates the pipe 
  9840. with DosCreateNPipe. The client receives the handle for its end when it opens 
  9841. the pipe with DosOpen. 
  9842.  
  9843. The server and the client use their respective handles both to read from the 
  9844. pipe and to write to it. (This is in contrast to unnamed pipes, for which both 
  9845. the server and the client read from one handle and write to another.) In other 
  9846. words, data that is written by the process at one end of the pipe is read by 
  9847. the process at the other end, as shown in the following diagram. 
  9848.  
  9849. A named pipe can have multiple instances, up to the number specified when the 
  9850. pipe is first created. Pipe instances are actually separate pipes-that is, 
  9851. unique sets of pipe buffers with unique handles-that share the same name. The 
  9852. ability to create multiple pipe instances enables the server to communicate 
  9853. with multiple client processes at the same time. 
  9854.  
  9855.  
  9856. ΓòÉΓòÉΓòÉ 13.1.2.1. Server-Client Communications Using Named Pipes ΓòÉΓòÉΓòÉ
  9857.  
  9858. A server process initiates a connection to a client process by using 
  9859. DosConnectNPipe. Once the pipe has been connected by the server process, the 
  9860. client process must open the pipe by using DosOpen to complete the connection. 
  9861. If no client process has opened the pipe when the server process calls 
  9862. DosConnectNPipe, the function either waits until a client opens the pipe or 
  9863. returns ERROR_PIPE_NOT_CONNECTED, depending on whether the server process 
  9864. created the pipe to wait for data. 
  9865.  
  9866. Each client process requires a separate instance of a pipe. For example, if a 
  9867. server process creates a named pipe and specifies that four instances of the 
  9868. pipe can be created, the process can then create three more instances of the 
  9869. named pipe (for a total of four pipes, including the original). Each instance 
  9870. has the same name, but each has a unique pipe handle. The process can then 
  9871. connect each pipe to the server. (Each instance must be connected by an 
  9872. explicit use of DosConnectNPipe.) In this example, the server must use each 
  9873. function four times to create and connect four separate instances of the named 
  9874. pipe. Each pipe is then available to a separate client process. 
  9875.  
  9876. If a client process receives the ERROR_PIPE_BUSY return value from DosOpen, no 
  9877. instances of the given pipe are available. The process can use DosWaitNPipe to 
  9878. wait for an instance to become available. The function waits until an instance 
  9879. is free or until the specified time interval elapses. When an instance becomes 
  9880. free, the process can open the pipe. If several processes are waiting for an 
  9881. instance to become available, the system gives the named pipe to the process 
  9882. that has been waiting the longest. 
  9883.  
  9884. The server process can disconnect a client process from a pipe by using 
  9885. DosDisConnectNPipe. Ideally, the client process closes the pipe by using 
  9886. DosClose before the server process disconnects the pipe. If the client process 
  9887. has not closed the pipe when the server process disconnects it, the server 
  9888. process forces the pipe closed and the client process subsequently receives 
  9889. errors if it attempts to access the pipe. Note that forcing the closure of the 
  9890. pipe might discard data in the pipe before the client process has had an 
  9891. opportunity to read it. 
  9892.  
  9893. A process can read and write bytes to a named pipe by using DosRead and 
  9894. DosWrite. A process can read or write messages by using DosTransactNPipe. 
  9895. Depending on the access mode, DosTransactNPipe writes a message to the pipe, 
  9896. reads a message from the pipe, or both. If a named pipe contains unread data or 
  9897. is not a message pipe, DosTransactNPipe fails. If it is reading from the pipe, 
  9898. DosTransactNPipe does not return until a complete message is read, even if the 
  9899. server process specified no-wait mode when the pipe was created. 
  9900.  
  9901. A process can also read data from a named pipe without removing the data from 
  9902. the pipe by using DosPeekNPipe. This function copies the specified number of 
  9903. bytes from the pipe and returns the number of bytes of data left in the pipe 
  9904. and the number of bytes left in the current message, if any. 
  9905.  
  9906. DosPeekNPipe also returns the state of the pipe. A named pipe can be in one of 
  9907. the following states: 
  9908.  
  9909. Named Pipe States 
  9910.  
  9911. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  9912. ΓöéState          ΓöéDescription                                  Γöé
  9913. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9914. ΓöéConnected      ΓöéThe pipe has been created and connected by   Γöé
  9915. Γöé               Γöéthe server process and has been opened by a  Γöé
  9916. Γöé               Γöéclient process.  Only connected pipes can be Γöé
  9917. Γöé               Γöéwritten to or read from.                     Γöé
  9918. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9919. ΓöéClosing        ΓöéThe pipe has been closed by the client       Γöé
  9920. Γöé               Γöéprocess but has not yet been disconnected by Γöé
  9921. Γöé               Γöéthe server process.                          Γöé
  9922. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9923. ΓöéDisconnected   ΓöéThe pipe has been created by the server      Γöé
  9924. Γöé               Γöéprocess but not connected, or has been       Γöé
  9925. Γöé               Γöéexplicitly disconnected and not yet          Γöé
  9926. Γöé               Γöéreconnected. A disconnected pipe cannot      Γöé
  9927. Γöé               Γöéaccept a DosOpen request.                    Γöé
  9928. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  9929. ΓöéListening      ΓöéThe pipe has been created and connected by   Γöé
  9930. Γöé               Γöéthe server process but has not yet been      Γöé
  9931. Γöé               Γöéopened by a client process. A listening pipe Γöé
  9932. Γöé               Γöéis ready to accept a request to open. If the Γöé
  9933. Γöé               Γöépipe is not in a listening state, DosOpen    Γöé
  9934. Γöé               Γöéreturns ERROR_PIPE_BUSY.                     Γöé
  9935. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  9936. A process can open, read from, write to, and close a named message-format pipe 
  9937. by using DosCallNPipe. This function is equivalent to calling DosOpen, 
  9938. DosTransactNPipe, and DosClose If no instances of the pipe are available, 
  9939. DosCallNPipe waits for an instance or returns without opening the pipe if the 
  9940. specified interval of time elapses. 
  9941.  
  9942. A process can retrieve information about the handle state of a named pipe by 
  9943. using DosQueryNPHState. The handle state is a combination of the instance 
  9944. count, the access mode, and the pipe type (byte or message). DosQueryNPHState 
  9945. also specifies whether the process owning the handle is a server or client and 
  9946. whether the pipe waits if reading and writing cannot proceed. 
  9947.  
  9948. A process can modify the handle state of a named pipe by using DosSetNPHState. 
  9949. For example, the process can change the reading mode for the pipe, enabling a 
  9950. process to read bytes from the pipe instead of messages. 
  9951.  
  9952.  
  9953. ΓòÉΓòÉΓòÉ 13.1.2.2. Steps in Managing Server-Client Transactions ΓòÉΓòÉΓòÉ
  9954.  
  9955. The following sequence summarizes the typical steps in the management of a 
  9956. named pipe: 
  9957.  
  9958.  1. The server process creates the pipe by calling DosCreateNPipe. 
  9959.     DosCreateNPipe returns a handle for the server end of the pipe. (Note that 
  9960.     the server uses the same handle to both read from and write to the pipe.) 
  9961.     The pipe is now in the disconnected state and cannot be opened by a client 
  9962.     process. The server process calls DosConnectNPipe to put the pipe into a 
  9963.     listening state. 
  9964.  
  9965.  2. The pipe can now be opened by a client process. 
  9966.  
  9967.  3. A client process supplies the name of the pipe in a call to DosOpen and 
  9968.     receives a pipe handle in return. (The client uses the same handle to both 
  9969.     read from and write to the pipe.) The pipe is now in the connected state 
  9970.     and can be read from or written to by the client. 
  9971.  
  9972.  4. The server and client processes communicate by calling DosRead and 
  9973.     DosWrite. DosResetBuffer can be used to synchronize read and write dialogs. 
  9974.     A server process that supports a large number of clients for a local named 
  9975.     pipe can use DosSetNPipeSem and DosQueryNPipeSemState to coordinate access 
  9976.     to the pipe. Server and client processes can also use DosTransactNPipe and 
  9977.     DosCallNPipe to facilitate their communication. 
  9978.  
  9979.  5. After completing its transactions, the client process calls DosClose to 
  9980.     close its end of the pipe. The pipe is now in the closing state and cannot 
  9981.     be accessed by another client. 
  9982.  
  9983.  6. The server process calls DosDisConnectNPipe to acknowledge that the client 
  9984.     has closed its end of the pipe.  The pipe is now in the disconnected state 
  9985.     again. 
  9986.  
  9987.  7. To enable another client process to open the pipe, the server must call 
  9988.     DosConnectNPipe again. This puts the pipe back into the listening state. To 
  9989.     end its access to the pipe, the server calls DosClose. When all of the 
  9990.     handles for both ends of the pipe have been closed, the pipe is deallocated 
  9991.     by the system. 
  9992.  
  9993.  
  9994. ΓòÉΓòÉΓòÉ 13.1.2.3. Preparing a Named Pipe for a Client ΓòÉΓòÉΓòÉ
  9995.  
  9996. A server process uses DosConnectNPipe to put a newly created named pipe into 
  9997. the listening state. The pipe must be in the listening state in order for a 
  9998. client process to gain access to the pipe by calling DosOpen. 
  9999.  
  10000. After successfully opening the pipe and finishing its transactions, the client 
  10001. process calls DosClose to end its access to the pipe. The server process must 
  10002. acknowledge the close by calling DosDisConnectNPipe. It can then call 
  10003. DosConnectNPipe again to put the pipe into the listening state for the next 
  10004. client. 
  10005.  
  10006. Together, DosConnectNPipe and DosDisConnectNPipe enable a server to create a 
  10007. named pipe and to reuse it for communication with different clients. Without 
  10008. these functions, the server would have to delete and re-create the pipe for 
  10009. each client. 
  10010.  
  10011. Note:  If multiple instances of a named pipe have been created, then each 
  10012.        instance of the pipe must be put into the listening state before it can 
  10013.        be opened by a client. 
  10014.  
  10015.  
  10016. ΓòÉΓòÉΓòÉ 13.1.2.4. Facilitating Transaction Processing ΓòÉΓòÉΓòÉ
  10017.  
  10018. DosTransactNPipe and DosCallNPipe facilitate the use of named pipes by 
  10019. combining other named pipe functions. Compared to calling the other functions 
  10020. separately, DosTransactNPipe and DosCallNPipe provide significant performance 
  10021. gains for applications that operate in a networked environment.  They can also 
  10022. be used by local processes. However, both of these functions can be used only 
  10023. with duplex message pipes. 
  10024.  
  10025. o DosTransactNPipe performs a transaction (a DosWrite followed by DosRead) on a 
  10026.   duplex message pipe. 
  10027.  
  10028. o DosCallNPipe has the combined effect of DosOpen, DosTransactNPipe, and 
  10029.   DosClose, and is referred to as a procedure call. It provides an efficient 
  10030.   means of implementing local and remote procedure call interfaces between 
  10031.   processes. 
  10032.  
  10033.  
  10034. ΓòÉΓòÉΓòÉ 13.1.2.5. Coordinating Access to a Local Named Pipe with Semaphores ΓòÉΓòÉΓòÉ
  10035.  
  10036. When a process writes to a named pipe, the process at the other end (or handle) 
  10037. of the pipe might require notification that data is available to be read. 
  10038. Similarly, when a process reads from a named pipe, the process at the other end 
  10039. might require notification that write space has become available. As long as 
  10040. the communicating processes are on the same computer system, shared event 
  10041. semaphores and muxwait semaphores can be used to provide this notification. 
  10042. Using shared semaphores for this purpose is more efficient than dedicating a 
  10043. thread to periodically poll each pipe, particularly when a server process is 
  10044. communicating with a large number of client processes. The server or client 
  10045. (whichever is writing to the pipe) can post a semaphore whenever data is 
  10046. available in the pipe. This means that the reading process can use 
  10047. DosWaitEventSem or DosWaitMuxWaitSem to wait for data to arrive, rather than 
  10048. devote a thread to periodically polling the pipe. 
  10049.  
  10050. A process associates a semaphore with a named pipe by using DosSetNPipeSem. 
  10051. First, create an event semaphore with DosCreateEventSem, specifying the initial 
  10052. state of the semaphore as reset. Then call DosSetNPipeSem to attach the event 
  10053. semaphore to a particular named-pipe handle. Up to two event semaphores can be 
  10054. attached to each named pipe, one for the server process and one for the client 
  10055. process. If there is already a semaphore associated with one end of the pipe, 
  10056. that semaphore is replaced. A process can check the state of the semaphores by 
  10057. using DosQueryNPipeSemState. 
  10058.  
  10059. The server or client process must then call DosWaitEventSem. The particular 
  10060. thread that calls this function will block until data is either read from or 
  10061. written to the pipe. At that time, the system posts the event semaphore, 
  10062. enabling the blocked thread to resume its execution. 
  10063.  
  10064. If a process requires notification whenever any one of multiple named pipes has 
  10065. been written to or read from, it can either attach the same event semaphore to 
  10066. multiple pipes, or it can create a muxwait semaphore: 
  10067.  
  10068. o If the same event semaphore is attached to multiple pipes, then the KeyHandle 
  10069.   parameter of DosSetNPipeSem is used to assign a unique value to each pipe. 
  10070.   After the event semaphore has been posted, the process calls 
  10071.   DosQueryNPipeSemState. This function returns information about each of the 
  10072.   named pipes that are attached to the semaphore, including key-handle values. 
  10073.   The calling process can use this information to determine which one of the 
  10074.   named pipes has either data or write space available. 
  10075.  
  10076. o To use a muxwait semaphore, a process first creates an event semaphore for 
  10077.   each of the pipes that it wants to monitor. Each semaphore must then be 
  10078.   attached to a pipe by calling DosSetNPipeSem. Again, a unique key-handle 
  10079.   value must be assigned to each pipe. 
  10080.  
  10081.   Next, the process calls DosCreateMuxWaitSem to create the muxwait semaphore, 
  10082.   specifying DCMW_WAIT_ANY as one of the flAttr flags. The muxwait semaphore 
  10083.   will consist of a linked list of the previously created event semaphores. 
  10084.  
  10085.   The process calls DosWaitMuxWaitSem so that it will be notified the next time 
  10086.   data is read from or written to any of the pipes. However, it must call 
  10087.   DosQueryNPipeSemState to determine which one of the pipes is ready to be read 
  10088.   from or written to. 
  10089.  
  10090.  
  10091. ΓòÉΓòÉΓòÉ 13.2. Using Unnamed Pipes ΓòÉΓòÉΓòÉ
  10092.  
  10093. Unnamed pipes are useful in applications that transfer data between related 
  10094. processes. They are commonly used to control the input and output of child 
  10095. processes by redirecting the standard input and output of the child process to 
  10096. a pipe controlled by the parent process. 
  10097.  
  10098. Note:  In the example code fragments that follow, error checking was left out 
  10099.        to conserve space. Applications should always check the return code that 
  10100.        the functions return. Control Program functions return an APIRET value. 
  10101.        A return code of 0 indicates success. If a non-zero value is returned, 
  10102.        an error occurred. 
  10103.  
  10104.  
  10105. ΓòÉΓòÉΓòÉ 13.2.1. Creating Unnamed Pipes ΓòÉΓòÉΓòÉ
  10106.  
  10107. DosCreatePipe creates an unnamed pipe. Two handles are returned: one for read 
  10108. access to the pipe and one for write access. The pipe size specified is 
  10109. advisory; its actual size is dependent on the amount of available memory. If 
  10110. the size parameter is 0, the pipe is created with the default size, which is 
  10111. 512 bytes. 
  10112.  
  10113. This example creates an unnamed pipe. The current process can use the unnamed 
  10114. pipe for communication between itself and a child process. 
  10115.  
  10116.     #define INCL_DOSQUEUES   /* Queue values */
  10117.     #include <os2.h>
  10118.     #include <stdio.h>
  10119.  
  10120.     HFILE    ReadHandle;    /* Pointer to the read handle      */
  10121.     HFILE    WriteHandle;   /* Pointer to the write handle     */
  10122.     ULONG    PipeSize;      /* Pipe size                       */
  10123.     APIRET   rc;            /* Return code                     */
  10124.  
  10125.     PipeSize = 4096;        /* Ask for 4KB of internal storage */
  10126.                             /* for the pipe                    */
  10127.  
  10128.     rc = DosCreatePipe(&ReadHandle, &WriteHandle, PipeSize);
  10129.  
  10130.     if (rc != 0) {
  10131.         printf("DosCreatePipe error: return code = %ld", rc);
  10132.         return;
  10133.     }
  10134.  
  10135.  
  10136. Creating an Unnamed Pipe 
  10137.  
  10138. On successful return, the ReadHandle variable contains the read handle for the 
  10139. pipe, and the WriteHandle variable contains the write handle for the pipe. 
  10140.  
  10141. After a process creates a pipe, any child process started with DosExecPgm 
  10142. inherits the pipe handles. Using shared memory, the parent process can pass one 
  10143. of the pipe handles to the child process; thus, one process can store data in 
  10144. the pipe and the other can retrieve it. 
  10145.  
  10146.  
  10147. ΓòÉΓòÉΓòÉ 13.2.2. Reading from and Writing to Unnamed Pipes ΓòÉΓòÉΓòÉ
  10148.  
  10149. Applications use the OS/2 file system functions to read from and write to 
  10150. unnamed pipes. The handles returned by DosCreatePipe are used as file handles 
  10151. to DosRead and DosWrite. 
  10152.  
  10153. To write (or add data) to an unnamed pipe, call DosWrite, specifying the write 
  10154. handle of the pipe in DosWrite's file handle parameter. DosWrite requests to a 
  10155. pipe are processed in the order in which they are made. Multiple calls to 
  10156. DosWrite can be made before data is read (or removed) from the pipe. When the 
  10157. pipe becomes full, write requests are blocked until space is freed by read 
  10158. requests. 
  10159.  
  10160. To read from a pipe, call DosRead, specifying the read handle of the pipe in 
  10161. DosRead's file handle parameter. Subsequent calls to DosRead can empty the pipe 
  10162. if no further calls to DosWrite are made in the meantime. 
  10163.  
  10164. If the process reading the pipe ends, the next DosWrite request for that pipe 
  10165. returns ERROR_BROKEN_PIPE. 
  10166.  
  10167. Calling DosClose terminates access to an unnamed pipe. However, the pipe is not 
  10168. deleted from memory until all handles to the pipe have been closed, including 
  10169. any handles that were defined with DosDupHandle. 
  10170.  
  10171.  
  10172. ΓòÉΓòÉΓòÉ 13.2.3. Redirecting Standard I/O for Child Processes ΓòÉΓòÉΓòÉ
  10173.  
  10174. An application can use unnamed pipes to redirect the standard input and the 
  10175. standard output for a child process. 
  10176.  
  10177. A typical use of an unnamed pipe is to read the output of a child process. An 
  10178. application creates a pipe and then duplicates the standard output handle. When 
  10179. the child process is started, its standard output will be written into the 
  10180. pipe, where the application can read and display it. The following code 
  10181. fragment shows how to do this: 
  10182.  
  10183.     #define INCL_DOSQUEUES   /* Queue values */
  10184.     #include <os2.h>
  10185.  
  10186.     #define PIPESIZE 256
  10187.     #define HF_STDOUT 1      /* Standard output handle */
  10188.  
  10189.     HPIPE hpR, hpW;
  10190.     RESULTCODES resc;
  10191.     ULONG cbRead, cbWritten;
  10192.     CHAR achBuf[PIPESIZE], szFailName[CCHMAXPATH];
  10193.  
  10194.     HFILE hfSave = -1,
  10195.           hfNew = HF_STDOUT;
  10196.  
  10197.     DosDupHandle(HF_STDOUT, &hfSave);    /* Saves standard output handle      */
  10198.  
  10199.     DosCreatePipe(&hpR, &hpW, PIPESIZE); /* Creates pipe                      */
  10200.  
  10201.     DosDupHandle(hpW, &hfNew);           /* Duplicates standard output handle */
  10202.  
  10203.     DosExecPgm(szFailName, sizeof(szFailName),   /* Starts child process      */
  10204.                EXEC_ASYNC, (PSZ) NULL, (PSZ) NULL, &resc,
  10205.                "DUMMY.EXE");
  10206.  
  10207.     DosClose(hpW);                       /* Closes write handle to ensure     */
  10208.                                          /* Notification at child termination */
  10209.  
  10210.     DosDupHandle(hfSave, &hfNew);        /* Brings stdout back                */
  10211.  
  10212.     /*
  10213.      * Read from the pipe and write to the screen
  10214.      * as long as there are bytes to read.
  10215.      */
  10216.  
  10217.     do {
  10218.         DosRead(hpR, achBuf, sizeof(achBuf), &cbRead);
  10219.         DosWrite(HF_STDOUT, achBuf, cbRead, &cbWritten);
  10220.     } while(cbRead);
  10221.  
  10222.  
  10223. Redirecting the Standard I/O of a Child Process into an Unnamed Pipe 
  10224.  
  10225. A parent process can also use unnamed pipes to communicate with a child process 
  10226. by redirecting both the standard input and the standard output for the child 
  10227. process. To do this, the parent process: 
  10228.  
  10229.  1. Uses DosDupHandle to redefine the read handle of one pipe as standard input 
  10230.     (0000), and the write handle of the other pipe as standard output (0001). 
  10231.  2. Starts the child process with DosExecPgm. 
  10232.  3. Uses the remaining pipe handles to read and write to the pipes. 
  10233.  
  10234. The parent process controls the meanings for standard I/O for the child 
  10235. process. Thus, when the child process uses standard I/O handles with DosRead 
  10236. and DosWrite, it reads from and writes to the pipes of its parent instead of 
  10237. reading from the keyboard and writing to the display. 
  10238.  
  10239.  
  10240. ΓòÉΓòÉΓòÉ 13.3. Using Named Pipes ΓòÉΓòÉΓòÉ
  10241.  
  10242. Named pipes are useful in applications that transfer data between processes. 
  10243. The processes using named pipes can be related, unrelated, or even on different 
  10244. computers. 
  10245.  
  10246.  
  10247. ΓòÉΓòÉΓòÉ 13.3.1. Creating Named Pipes ΓòÉΓòÉΓòÉ
  10248.  
  10249. The server process creates a named pipe by using DosCreateNPipe. You must 
  10250. specify the name of the pipe, the access modes, the type of pipe (byte or 
  10251. message), and the sizes of the input and output buffers. DosCreateNPipe returns 
  10252. a pipe handle that can be used in subsequent pipe operations. 
  10253.  
  10254. Each named pipe must have a unique name of the following form: 
  10255.  
  10256.     \PIPE\PipeName
  10257. The "\PIPE\" in the name above is required, but need not be uppercase.  It is 
  10258. not the name of a subdirectory. 
  10259.  
  10260. To open a pipe on a remote computer, the client process must specify the name 
  10261. of the server process that opened the pipe as part of the pipe name, as 
  10262. follows: 
  10263.  
  10264.     \\Server\PIPE\PipeName
  10265. "\\Server" in the name above is the name of the remote computer; again, 
  10266. "\PIPE\" is required. 
  10267.  
  10268. The name parameter must conform to the rules for OS/2 file names, but no actual 
  10269. file is created for the pipe. 
  10270.  
  10271. In the following code fragment, DosCreateNPipe creates a pipe named \pipe\pipe1 
  10272. and supplies a unique handle identifying the pipe. OpenMode is set to 
  10273. NP_ACCESS_DUPLEX. This activates full duplex access to the named pipe. There 
  10274. will be no inheritance to child process, and no write-through (write-through 
  10275. only affects remote pipes). PipeMode is set to "NP_WMESG | NP_RMESG | 0x01". 
  10276. This specifies that the pipe should be read as a message stream for both 
  10277. reading and writing and an instance count of 1 (only one instance of the named 
  10278. pipe can be created at a time). The pipe will block on Read/Write if no data is 
  10279. available. 
  10280.  
  10281.     #define INCL_DOSNMPIPES   /* Named-pipe values */
  10282.     #include <os2.h>
  10283.     #include <stdio.h>
  10284.  
  10285.     UCHAR   FileName[40];  /* Pipe name              */
  10286.     HPIPE   PipeHandle;    /* Pipe handle (returned) */
  10287.     ULONG   OpenMode;      /* Open-mode parameters   */
  10288.     ULONG   PipeMode;      /* Pipe-mode parameters   */
  10289.     ULONG   OutBufSize;    /* Size of the out-buffer */
  10290.     ULONG   InBufSize;     /* Size of the in-buffer  */
  10291.     ULONG   TimeOut;       /* Default value for DosWaitNPipe time-out parameter */
  10292.     APIRET  rc;            /* Return code            */
  10293.  
  10294.     strcpy(FileName,"\\PIPE\\PIPE1");
  10295.  
  10296.     OpenMode = NP_ACCESS_DUPLEX;            /* Full duplex, no inheritance,     */
  10297.                                             /* no write-through                 */
  10298.  
  10299.     PipeMode = NP_WMESG | NP_RMESG | 0x01;  /* Block on read and write, message */
  10300.                                             /* stream, instance count of 1      */
  10301.  
  10302.     OutBufSize = 4096;   /* The outgoing buffer must be 4KB in size             */
  10303.  
  10304.     InBufSize = 2048;    /* The incoming buffer must be 2KB in size             */
  10305.  
  10306.     TimeOut = 10000;     /* Time-out is 10 seconds (units are in milliseconds)  */
  10307.  
  10308.     rc = DosCreateNPipe(FileName, &PipeHandle, OpenMode,
  10309.                         PipeMode, OutBufSize, InBufSize,
  10310.                         TimeOut);
  10311.  
  10312.     if (rc != 0) {
  10313.         printf("DosCreateNPipe error: return code = %ld", rc);
  10314.         return;
  10315.     }
  10316.  
  10317.  
  10318. Creating a Named Pipe 
  10319.  
  10320. Once the named pipe is created, the application can call DosConnectNPipe to 
  10321. connect a client process to the pipe. 
  10322.  
  10323. Once a client process connects to the pipe, the process can read from and write 
  10324. to the pipe. The preceding example creates a byte pipe, so the process can use 
  10325. DosRead and DosWrite to read from and write to the pipe. 
  10326.  
  10327. After the client process finishes using the pipe, the server process can 
  10328. disconnect the pipe by using DosDisConnectNPipe. The server process can either 
  10329. connect again or close the named pipe by using DosClose. 
  10330.  
  10331. When a server process creates a named pipe, it defines the pipe to the system 
  10332. by specifying the file write-through mode, the inheritance mode, the access and 
  10333. blocking modes, the pipe type, the read mode, the size of the in and out 
  10334. buffers, and the instance count.  The following list describes these modes, 
  10335. types, and buffers. 
  10336.  
  10337. o The file write-through mode has significance only for communication with 
  10338.   remote client processes. When the file write-through bit is set, data is sent 
  10339.   across the network as soon as it is written; otherwise, the operating system 
  10340.   will in some cases hold data briefly in a local buffer before sending it 
  10341.   across the network. 
  10342.  
  10343. o The inheritance mode specifies whether or not the pipe handle will be 
  10344.   inherited by a child process. 
  10345.  
  10346. o The access mode specifies the direction in which data will flow through the 
  10347.   pipe. The server creates an inbound pipe (a pipe with inbound access mode) if 
  10348.   it intends to read data from the client process, an outbound pipe if it 
  10349.   intends to write data to the client process, or a duplex pipe if it intends 
  10350.   to both read from and write to the client process. 
  10351.  
  10352. o The blocking mode specifies whether or not DosRead and DosWrite will block 
  10353.   when no data is available. 
  10354.  
  10355. o The pipe type is the form in which a stream of data is written to the pipe. 
  10356.   If the pipe is a byte pipe, the server and client processes write data as an 
  10357.   undifferentiated stream of bytes. If the pipe is a message pipe, the 
  10358.   processes write data as a stream of messages;  messages are blocks of data, 
  10359.   each with a system-supplied header, that are written as single units. The 
  10360.   server and client processes define the size and format of a message. 
  10361.  
  10362. o The read mode is the form in which data is read from the pipe. The data in a 
  10363.   pipe that was created as a byte pipe can only be read as bytes; therefore, a 
  10364.   byte pipe will always be in byte-read mode. The data in a message pipe, 
  10365.   however, can be read either as messages or as bytes.  (If it is to be read as 
  10366.   bytes, DosRead skips over the message headers). Therefore, message pipes can 
  10367.   be in either message-read mode or byte-read mode. 
  10368.  
  10369.   Note:  The terms "byte pipe" and "message pipe" always refer to the pipe 
  10370.          type-the form in which data is written to the pipe. When the read mode 
  10371.          of a pipe is being referred to, it is always explicitly identified as 
  10372.          either message-read mode or byte-read mode. 
  10373.  
  10374. o The in and out buffers can be up to 64KB in size. If the pipe will be read in 
  10375.   message-read mode, and if the message size is known, the server can control 
  10376.   how many messages the buffer will hold at one time by specifying the 
  10377.   appropriate buffer size. 
  10378.  
  10379. o The instance count is the maximum number of instances of the named pipe that 
  10380.   can be created. A pipe instance is actually a separate pipe-that is, a unique 
  10381.   set of pipe buffers with unique handles. However, the term "pipe instance" is 
  10382.   used to distinguish pipes that share the same name from pipes with different 
  10383.   names. Because a client process uses only the name of the pipe when opening 
  10384.   it, the existence of multiple pipe instances is transparent to a client 
  10385.   process. 
  10386.  
  10387. Creating Multiple Instances of a Named Pipe 
  10388. Although each named pipe must have a unique name, a server process can create 
  10389. multiple instances of a pipe, all of which have the same name. A pipe instance 
  10390. is actually a separate pipe-that is, a unique set of pipe buffers with unique 
  10391. handles. 
  10392.  
  10393. The ability to create multiple pipe instances enables the server to communicate 
  10394. with multiple client processes at the same time. Because a client process uses 
  10395. only the name of the pipe when opening it, the existence of multiple pipe 
  10396. instances is transparent to a client process. 
  10397.  
  10398. The ICount parameter of DosCreateNPipe specifies the maximum number of named 
  10399. pipe instances that can be created. (An unlimited number can also be 
  10400. specified.) This parameter is specified only when the first instance of a named 
  10401. pipe is created; any subsequent attempt to redefine the instance count will be 
  10402. ignored. 
  10403.  
  10404. If the instance count is greater than 1, the server process can create 
  10405. additional pipe instances by specifying the same pipe name in subsequent calls 
  10406. to DosCreateNPipe. Generally, the attributes of the subsequent pipe instances 
  10407. are defined to be the same as those of the original pipe instance, because a 
  10408. client process that requests the pipe has no way of controlling which pipe 
  10409. instance will be assigned to it. 
  10410.  
  10411. After an additional pipe instance has been created, it is used in the same 
  10412. manner as the original pipe instance.  That is, the same sequence of named pipe 
  10413. functions is used in the control or management of all named pipe instances. 
  10414. (See Steps in Managing Server-Client Transactions for more information.) 
  10415.  
  10416. Note:  If all of the instances of a named pipe are in use when a client calls 
  10417.        DosOpen, ERROR_PIPE_BUSY is returned. However, the client can wait for 
  10418.        an instance of that pipe to become available by calling DosWaitNPipe. 
  10419.  
  10420. Multiple instances of a named pipe can be created by different processes. That 
  10421. is, multiple server processes can create and use instances of the same named 
  10422. pipe to communicate with their clients. 
  10423.  
  10424.  
  10425. ΓòÉΓòÉΓòÉ 13.3.2. Opening Named Pipes ΓòÉΓòÉΓòÉ
  10426.  
  10427. A client process can open the client end of a named pipe by using DosOpen. 
  10428. DosOpen opens the client end of a pipe by name and returns a handle. The 
  10429. application must use the appropriate pipe name and access modes to open the 
  10430. pipe for reading, writing, or both. (To open a pipe on a remote computer, the 
  10431. client process must also specify the name of the computer system as part of the 
  10432. pipe name, as follows: 
  10433.  
  10434.     \\ComputerName\PIPE\PipeName.)
  10435.  
  10436. If a pipe name includes a remote LAN server name, DosOpen attempts to open the 
  10437. pipe on a remote computer. The server process can then read input from the 
  10438. client process through the pipe. 
  10439.  
  10440. The following code fragment opens a remote pipe, reads from the standard input 
  10441. (usually the keyboard), and sends the information to the server process through 
  10442. the pipe: 
  10443.  
  10444.     #define INCL_DOSQUEUES   /* Queue values          */
  10445.     #include <os2.h>
  10446.  
  10447.     #define PIPESIZE 256
  10448.     #define SERVER_PIPE_NAME "\\\\myserver\\pipe\\mypipe"
  10449.     #define HF_STDIN 0       /* Standard input handle */
  10450.  
  10451.     HPIPE   hp;
  10452.     BYTE    abBuf[PIPESIZE];
  10453.     ULONG   ulAction, cbRead, cbWritten;
  10454.     APIRET  rc;
  10455.  
  10456.     rc = DosOpen(SERVER_PIPE_NAME, &hp, &ulAction, 0,
  10457.                  FILE_NORMAL, FILE_OPEN,
  10458.                  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
  10459.                  (PEAOP) NULL);
  10460.  
  10461.     if (rc)
  10462.         DosExit(EXIT_PROCESS, 0);                    /* Open pipe failed      */
  10463.  
  10464.     do {                                             /* Open pipe succeeded   */
  10465.         DosRead(HF_STDIN, abBuf, sizeof(abBuf), &cbRead);
  10466.         DosWrite(hp, abBuf, cbRead, &cbWritten);     /* Writes to the pipe    */
  10467.     } while (cbRead > 2);                            /* Stop on a blank line  */
  10468.  
  10469.     DosClose(hp);
  10470.  
  10471.  
  10472. Opening and Writing to a Remote Pipe 
  10473.  
  10474. The client process checks the return value from DosOpen to verify that the pipe 
  10475. was actually opened. If the server process has not yet created the pipe, 
  10476. DosOpen returns an error. When the client process finishes using the pipe, it 
  10477. closes the pipe by using DosClose. 
  10478.  
  10479. When a named pipe is opened, its initial state is set by the system to block 
  10480. read and write operations (blocking mode), and to read data as a byte stream 
  10481. (byte-read mode). However, the client can change these modes by calling 
  10482. DosSetNPHState. A call to DosOpen fails if all instances of the named pipe are 
  10483. already open. 
  10484.  
  10485. The open also fails if the pipe has been closed by a client, but the server has 
  10486. not called DosDisConnectNPipe (to acknowledge the client's close), followed by 
  10487. DosConnectNPipe (to prepare the pipe for the next client). In both of these 
  10488. situations, ERROR_PIPE_BUSY is returned. 
  10489.  
  10490. If all instances of a named pipe are busy, a client process can call 
  10491. DosWaitNPipe to wait for an instance to become available before it calls 
  10492. DosOpen again. 
  10493.  
  10494. After a pipe instance has been opened by a client, that same instance cannot be 
  10495. opened by another client at the same time.  However, the opening process can 
  10496. duplicate the handle as many times as desired by calling DosDupHandle. This 
  10497. enables child processes to share access to a pipe instance with a parent 
  10498. process. 
  10499.  
  10500. The access-mode and sharing-mode fields that are specified for DosOpen must be 
  10501. the same as those that were specified by the server when it created the pipe 
  10502. with DosCreateNPipe. 
  10503.  
  10504.  
  10505. ΓòÉΓòÉΓòÉ 13.3.3. Reading from Named Pipes ΓòÉΓòÉΓòÉ
  10506.  
  10507. Both the server and the client processes read data from a pipe by calling 
  10508. DosRead. The server reads from the handle that was returned when it created the 
  10509. pipe with DosCreateNPipe, and the client reads from the handle that was 
  10510. returned to it by DosOpen. 
  10511.  
  10512. When a pipe is created, the PipeMode parameter is used to specify both the pipe 
  10513. type and the read mode for the server end of the pipe: 
  10514.  
  10515. o A byte pipe can be read-only in byte-read mode. (DosCreateNPipe and 
  10516.   DosSetNPHState return ERROR_INVALID_PARAMETER if message-read mode is 
  10517.   specified for a byte pipe.) In byte-read mode, all currently available data 
  10518.   is returned, up to the buffer size specified by DosRead. 
  10519.  
  10520. o A message pipe can be read in either byte-read mode or message-read mode, as 
  10521.   follows: 
  10522.  
  10523.    - When a message pipe is read in byte-read mode, the message headers are 
  10524.      skipped, and the pipe is read as if it were a byte pipe. 
  10525.  
  10526.    - When a message pipe is read in message-read mode, each message is read 
  10527.      either in its entirety, or not at all, depending on the size of the 
  10528.      message and the buffer length: 
  10529.  
  10530.       o If the buffer length that was specified for DosRead is larger than the 
  10531.         next available message, then only that message is read, and the 
  10532.         Bytes-Read parameter indicates the size of the message. 
  10533.  
  10534.       o If the buffer length for DosRead is smaller than the next available 
  10535.         message, DosRead returns the number of bytes requested and 
  10536.         ERROR_MORE_DATA. Subsequent calls to DosRead are blocked until the rest 
  10537.         of the message can be transferred. (DosPeekNPipe can be used to find 
  10538.         out how many bytes are left in the message.) 
  10539.  
  10540. The PipeMode parameter of DosCreateNPipe also specifies the blocking mode for 
  10541. the server end of the pipe: 
  10542.  
  10543. o If nonblocking mode was specified, DosRead returns immediately with 0 in the 
  10544.   Bytes-Read parameter if no data is available. 
  10545.  
  10546. o If blocking mode was specified, DosRead blocks until data is available; the 
  10547.   only time it will return with 0 in the Bytes-Read parameter is if it reaches 
  10548.   end-of-file. 
  10549.  
  10550. DosRead works the same for both ends of the pipe. However, the read mode and 
  10551. blocking mode are not necessarily the same for the client end of the pipe as 
  10552. they are for the server end, because DosOpen always opens the CLIENT end in 
  10553. byte-read mode and blocking mode. 
  10554.  
  10555. The read mode and blocking mode for either end of the pipe can be changed by 
  10556. calling DosSetNPHState. The pipe type, however, is always the same for both the 
  10557. server and client ends of the pipe, and it cannot be changed. 
  10558.  
  10559.  
  10560. ΓòÉΓòÉΓòÉ 13.3.4. Writing to Named Pipes ΓòÉΓòÉΓòÉ
  10561.  
  10562. Both the server and the client processes write to a pipe by calling DosWrite. 
  10563. The server writes to the handle that was returned to it by DosCreateNPipe, and 
  10564. the client writes to the handle that was returned to it by DosOpen. 
  10565.  
  10566. Either bytes or messages can be written, depending on whether the pipe was 
  10567. created as a byte pipe or as a message pipe. 
  10568.  
  10569. When a process writes to a message pipe, the buffer-length parameter for 
  10570. DosWrite holds the size of the message that the process is writing. Because 
  10571. DosWrite automatically encodes message lengths in the pipe, applications do not 
  10572. have to encode this information in the data buffers. 
  10573.  
  10574. The action taken by DosWrite depends on the blocking mode of the pipe, which is 
  10575. not necessarily the same for the server and client ends of the pipe. For the 
  10576. server process, the blocking mode of the pipe is specified when the pipe is 
  10577. created. For a client process, the blocking mode is automatically set to 
  10578. blocking when the pipe is opened. The blocking mode can also be reset by 
  10579. calling DosSetNPHState. 
  10580.  
  10581. If the end of the message pipe that is being written to is in blocking mode, 
  10582. DosWrite does not return until all of the requested bytes have been written. 
  10583. (It might have to wait for the first part of the message to be read before it 
  10584. can write the rest of the message.) 
  10585.  
  10586. If the message pipe is in nonblocking mode, DosWrite takes the following 
  10587. action: 
  10588.  
  10589. o If the message is larger than the pipe buffer, DosWrite blocks until the 
  10590.   entire message has been written. (Again, it might have to wait for the first 
  10591.   part of the message to be read before it can write the rest of the message.) 
  10592.  
  10593. o If the message is smaller than the pipe buffer, but there is currently not 
  10594.   enough room in the buffer, DosWrite returns with a value of 0 in the 
  10595.   Bytes-Written parameter. 
  10596.  
  10597. If a byte pipe is in nonblocking mode, and if there is more data to be written 
  10598. than will fit in the pipe buffer, then DosWrite writes as many bytes as will 
  10599. fit in the buffer and returns the number of bytes that were actually written. 
  10600.  
  10601. If a process tries to write to a pipe whose other end is closed, 
  10602. ERROR_BROKEN_PIPE is returned. 
  10603.  
  10604.  
  10605. ΓòÉΓòÉΓòÉ 13.3.5. Synchronizing Named Pipe Dialogs ΓòÉΓòÉΓòÉ
  10606.  
  10607. Communicating processes can synchronize their named pipe dialogs by calling 
  10608. DosResetBuffer after each call to DosWrite. 
  10609.  
  10610. When used with external files, DosResetBuffer flushes the buffer cache of the 
  10611. requesting process to disk. When used with named pipes, this function blocks 
  10612. the calling process at one end of the pipe until the data the calling process 
  10613. has written to the pipe has been successfully read at the other end of the 
  10614. pipe. 
  10615.  
  10616.  
  10617. ΓòÉΓòÉΓòÉ 13.3.6. Determining Pipe Status ΓòÉΓòÉΓòÉ
  10618.  
  10619. DosQueryNPHState and DosQueryNPipeInfo can be used to obtain information about 
  10620. named pipes. 
  10621.  
  10622. DosQueryNPHState 
  10623. A client process can read data from the pipe, write data to the pipe, or both, 
  10624. depending on the access mode specified when the pipe was created. To check the 
  10625. current access mode, the client process can call DosQueryNPHState. 
  10626.  
  10627. The following code fragment shows how to use DosQueryNPHState to obtain 
  10628. information about a named pipe: 
  10629.  
  10630.     #define INCL_DOSNMPIPES   /* Named-pipe values */
  10631.     #include <os2.h>
  10632.     #include <stdio.h>
  10633.  
  10634.     HPIPE    Handle;            /* Pipe handle       */
  10635.     ULONG    PipeHandleState;   /* Pipe-handle state */
  10636.     APIRET   rc;                /* Return code       */
  10637.  
  10638.     rc = DosQueryNPHState(Handle, &PipeHandleState);
  10639.  
  10640.     if (rc != 0) {
  10641.         printf("DosQueryNPHState error: return code = %ld", rc);
  10642.         return;
  10643.     }
  10644.  
  10645.  
  10646. Getting Information about a Named Pipe 
  10647.  
  10648. On successful return, PipeHandleState will contain information that describes 
  10649. the nature of the named pipe. 
  10650.  
  10651. DosQueryNPHState returns the following information about the pipe handle and 
  10652. the attributes of the pipe: 
  10653.  
  10654. o The end of the pipe that the handle is for (server or client end) 
  10655.  
  10656. o The pipe type (byte pipe or message pipe) 
  10657.  
  10658. o The instance count 
  10659.  
  10660. o The blocking mode (blocking or nonblocking) 
  10661.  
  10662. o The read mode (byte-read mode or message-read mode). 
  10663.  
  10664. The values for pipe type and instance count cannot be changed, so they are 
  10665. always the same as those that were specified when the pipe was created with 
  10666. DosCreateNPipe. The information returned for blocking mode and read mode, 
  10667. however, can come from different sources: 
  10668.  
  10669. o If the handle is for the server end of the pipe, then the blocking mode and 
  10670.   the read mode were set with DosCreateNPipe, but could have been reset with 
  10671.   DosSetNPHState. 
  10672.  
  10673. o If the handle is for the client end of the pipe, then the blocking mode and 
  10674.   the read mode were set to "blocking" and "byte-read" by the system when the 
  10675.   client called DosOpen. However, again, they could have been reset with 
  10676.   DosSetNPHState. 
  10677.  
  10678. The pipe attributes are described in more detail in Creating Named Pipes. 
  10679.  
  10680. An application can use DosSetNPHState to change the wait mode and the read 
  10681. mode. The pipe cannot be changed to no-wait mode when another thread is blocked 
  10682. on a read or write operation to the same end of the pipe. 
  10683.  
  10684. DosQueryNPipeInfo 
  10685. More detailed information about a named pipe can be obtained by using 
  10686. DosQueryNPipeInfo. This function returns information in a PIPEINFO data 
  10687. structure that includes the name of the pipe, the current and maximum instance 
  10688. counts (the current number of pipes and the maximum number of times the pipe 
  10689. can be created), the size of the input and output buffers for the pipe, and the 
  10690. pipe identifier of the client process. 
  10691.  
  10692. The following code fragment shows how to use DosQueryNPipeInfo: 
  10693.  
  10694.     #define INCL_DOSNMPIPES   /* Named-pipe values */
  10695.     #include <os2.h>
  10696.     #include <stdio.h>
  10697.  
  10698.     HPIPE    Handle;          /* Pipe handle                     */
  10699.     ULONG    InfoLevel;       /* Pipe data required              */
  10700.     PIPEINFO InfoBuf;         /* Pipe information data structure */
  10701.     ULONG    InfoBufSize;     /* Pipe data-buffer size           */
  10702.     APIRET   rc;              /* Return code                     */
  10703.  
  10704.     InfoLevel = 1;                    /* Ask for standard level of pipe info */
  10705.  
  10706.     InfoBufSize = sizeof(PIPEINFO);   /* Length of pipe info data structure  */
  10707.  
  10708.     rc = DosQueryNPipeInfo(Handle, InfoLevel, &InfoBuf, InfoBufSize);
  10709.  
  10710.     if (rc != 0) {
  10711.         printf("DosQueryNPipeInfo error: return code = %ld", rc);
  10712.         return;
  10713.     }
  10714.  
  10715.  
  10716. Using DosQueryNPipeInfo to Get Information about a Pipe 
  10717.  
  10718. On successful return, the pipe information data structure contains a set of 
  10719. information describing the nature and the current state of the named pipe. 
  10720.  
  10721. DosQueryNPipeInfo returns level 1 or level 2 file information for the pipe. 
  10722. Level 1 information includes the following: 
  10723.  
  10724. o The actual sizes of the in-buffer and out-buffer 
  10725. o The maximum number of pipe instances permitted 
  10726. o The current number of pipe instances 
  10727. o The length of the pipe name 
  10728. o The ASCIIZ name of the pipe, including \\ComputerName if the pipe is in a 
  10729.   remote computer system. 
  10730.  
  10731.   Level 2 information consists of a unique 2-byte identifier for each of the 
  10732.   pipe's client processes. 
  10733.  
  10734.  
  10735. ΓòÉΓòÉΓòÉ 13.3.7. Examining the Contents of Named Pipes ΓòÉΓòÉΓòÉ
  10736.  
  10737. DosPeekNPipe examines the current contents of a named pipe. It is similar to 
  10738. DosRead, except that DosPeekNPipe does not remove data from the pipe. In 
  10739. addition, DosPeekNPipe never blocks, even if the pipe is in blocking mode; if 
  10740. the pipe cannot be accessed immediately, ERROR_PIPE_BUSY is returned. 
  10741.  
  10742. Because DosPeekNPipe does not block, it returns only what is currently in the 
  10743. pipe. Thus, if a message pipe is being examined, only a portion of a message 
  10744. might be returned, even though the specified buffer length could accommodate 
  10745. the entire message. 
  10746.  
  10747. DosPeekNPipe also returns the state of the pipe. A named pipe can be in any of 
  10748. the following states: Connected, Disconnected, Listening, Closing. 
  10749.  
  10750. The following code fragment shows how to use DosPeekNPipe: 
  10751.  
  10752.     #define INCL_DOSNMPIPES   /* Named-pipe values */
  10753.     #include <os2.h>
  10754.     #include <stdio.h>
  10755.  
  10756.     HPIPE              Handle;      /* Pipe handle                */
  10757.     UCHAR              Buffer[200]; /* Address of user buffer     */
  10758.     ULONG              BufferLen;   /* Buffer length              */
  10759.     ULONG              BytesRead;   /* Bytes read (returned)      */
  10760.     struct _AVAILDATA  BytesAvail;  /* Bytes available (returned) */
  10761.     ULONG              PipeState;   /* Pipe state (returned)      */
  10762.     APIRET             rc;          /* Return code                */
  10763.  
  10764.     BufferLen = 200;  /* Length of the read buffer */
  10765.  
  10766.     rc = DosPeekNPipe(Handle, Buffer, BufferLen,
  10767.                       &BytesRead, &BytesAvail, &PipeState);
  10768.  
  10769.     if (rc != 0) {
  10770.         printf("DosPeekNPipe error: return code = %ld", rc);
  10771.         return;
  10772.     }
  10773.  
  10774.  
  10775. Using DosPeekNPipe to Peek into a Named Pipe 
  10776.  
  10777. On successful return, the input buffer Buffer will contain up to the first 200 
  10778. bytes from the named pipe, BytesRead will contain the number of bytes read into 
  10779. Buffer, BytesAvail will contain the total number of bytes that were available 
  10780. in the pipe, and PipeState will contain a value indicating the state of the 
  10781. named pipe 
  10782.  
  10783.  
  10784. ΓòÉΓòÉΓòÉ 13.3.8. Closing Named Pipes ΓòÉΓòÉΓòÉ
  10785.  
  10786. DosClose closes the specified pipe handle. When all of the handles that access 
  10787. one end of a pipe have been closed, the pipe is referred to as a broken pipe. 
  10788.  
  10789. If the client end of the pipe closes, no other process can reopen the pipe 
  10790. until the server calls DosDisConnectNPipe (to acknowledge the client's close) 
  10791. followed by DosConnectNPipe (to prepare the pipe for a new client). Until it 
  10792. calls DosDisConnectNPipe, the server will receive ERROR_EOF if it tries to read 
  10793. from the pipe, and ERROR_BROKEN_PIPE if it tries to write to it. Clients that 
  10794. attempt to open the pipe receive ERROR_PIPE_BUSY. 
  10795.  
  10796. If the server end closes when the client end is already closed, the pipe is 
  10797. deallocated immediately; otherwise, the pipe is not deallocated until the last 
  10798. client handle is closed. 
  10799.  
  10800. The following code fragment shows how to close a named pipe.  Assume that a 
  10801. previous call to DosOpen provided the named pipe handle that is contained in 
  10802. Handle. 
  10803.  
  10804.     #define INCL_DOSNMPIPES   /* Named-pipe values */
  10805.     #include <os2.h>
  10806.     #include <stdio.h>
  10807.  
  10808.     HPIPE   Handle;      /* Pipe handle */
  10809.     APIRET  rc;          /* Return code */
  10810.  
  10811.     rc = DosDisConnectNPipe(Handle);
  10812.  
  10813.     if (rc != 0) {
  10814.         printf("DosDisConnectNPipe error: return code = %ld", rc);
  10815.         return;
  10816.     }
  10817.  
  10818.  
  10819. Closing a Named Pipe 
  10820.  
  10821.  
  10822. ΓòÉΓòÉΓòÉ 13.4. Summary of Functions and Data Structures Used with Pipes ΓòÉΓòÉΓòÉ
  10823.  
  10824. Following are the OS/2 functions and data structures used with pipes. 
  10825.  
  10826. Pipe Functions 
  10827.  
  10828. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  10829. ΓöéNamed-Pipe Functions          Γöé                              Γöé
  10830. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10831. ΓöéDosCallNPipe                  ΓöéCombines the functionality of Γöé
  10832. Γöé                              ΓöéDosTransactNPipe and DosClose Γöé
  10833. Γöé                              Γöéfor a duplex pipe.  This      Γöé
  10834. Γöé                              Γöéaction is called a procedure  Γöé
  10835. Γöé                              Γöécall.                         Γöé
  10836. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10837. ΓöéDosConnectNPipe               ΓöéPrepares a named pipe for a   Γöé
  10838. Γöé                              Γöéclient process by placing the Γöé
  10839. Γöé                              Γöépipe into the listening state.Γöé
  10840. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10841. ΓöéDosCreateNPipe                ΓöéCreates a named pipe.         Γöé
  10842. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10843. ΓöéDosDisConnectNPipe            ΓöéAcknowledges that a client    Γöé
  10844. Γöé                              Γöéprocess has closed a named    Γöé
  10845. Γöé                              Γöépipe.                         Γöé
  10846. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10847. ΓöéDosPeekNPipe                  ΓöéExamines the data in a named  Γöé
  10848. Γöé                              Γöépipe without removing the     Γöé
  10849. Γöé                              Γöédata. Also returns informationΓöé
  10850. Γöé                              Γöéabout the state of the pipe.  Γöé
  10851. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10852. ΓöéDosQueryNPHState              ΓöéReturns information about a   Γöé
  10853. Γöé                              Γöénamed pipe handle.            Γöé
  10854. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10855. ΓöéDosQueryNPipeInfo             ΓöéReturns information about a   Γöé
  10856. Γöé                              Γöénamed pipe.                   Γöé
  10857. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10858. ΓöéDosQueryNPipeSemState         ΓöéReturns information about     Γöé
  10859. Γöé                              Γöélocal named pipes that are    Γöé
  10860. Γöé                              Γöéattached to a shared event or Γöé
  10861. Γöé                              Γöémuxwait semaphore.            Γöé
  10862. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10863. ΓöéDosSetNPHState                ΓöéResets the blocking mode and  Γöé
  10864. Γöé                              Γöéthe read mode of a named pipe.Γöé
  10865. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10866. ΓöéDosSetNPipeSem                ΓöéAttaches a shared event       Γöé
  10867. Γöé                              Γöésemaphore to a local named    Γöé
  10868. Γöé                              Γöépipe.                         Γöé
  10869. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10870. ΓöéDosTransactNPipe              ΓöéWrites to a duplex message    Γöé
  10871. Γöé                              Γöépipe, then reads from it.     Γöé
  10872. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10873. ΓöéDosWaitNPipe                  ΓöéWaits for an instance of a    Γöé
  10874. Γöé                              Γöénamed pipe to become          Γöé
  10875. Γöé                              Γöéavailable.                    Γöé
  10876. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10877. ΓöéUnnamed-Pipe Functions        Γöé                              Γöé
  10878. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10879. ΓöéDosClose                      ΓöéCloses a file or pipe.        Γöé
  10880. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10881. ΓöéDosCreatePipe                 ΓöéCreates an unnamed (anonymous)Γöé
  10882. Γöé                              Γöépipe.                         Γöé
  10883. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10884. ΓöéDosDupHandle                  ΓöéReturns a new file handle for Γöé
  10885. Γöé                              Γöéan open file or pipe.         Γöé
  10886. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10887. ΓöéDosOpen                       ΓöéOpens a file or pipe for      Γöé
  10888. Γöé                              Γöéreading or writing.           Γöé
  10889. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10890. ΓöéDosRead                       ΓöéReads from a file or pipe.    Γöé
  10891. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10892. ΓöéDosWrite                      ΓöéWrites to a file or pipe.     Γöé
  10893. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  10894.  
  10895. Pipe Data Structures 
  10896.  
  10897. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  10898. ΓöéData Structure                ΓöéDescription                   Γöé
  10899. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10900. ΓöéAVAILDATA                     ΓöéUsed to return a count of the Γöé
  10901. Γöé                              Γöéavailable items in a named    Γöé
  10902. Γöé                              Γöépipe.                         Γöé
  10903. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10904. ΓöéPIPEINFO                      ΓöéUsed to return level 1        Γöé
  10905. Γöé                              Γöéinformation about a named     Γöé
  10906. Γöé                              Γöépipe.                         Γöé
  10907. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10908. ΓöéPIPESEMSTATE                  ΓöéUsed to return information    Γöé
  10909. Γöé                              Γöéabout local named pipes       Γöé
  10910. Γöé                              Γöéattached to a semaphore.      Γöé
  10911. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  10912.  
  10913.  
  10914. ΓòÉΓòÉΓòÉ 14. Device I/O ΓòÉΓòÉΓòÉ
  10915.  
  10916. Devices used with computers include the keyboard, video display, mouse, floppy 
  10917. and fixed disk drives, and external systems, such as modems and printers. This 
  10918. chapter describes the OS/2 functions used to access and control such devices. 
  10919.  
  10920. The following topics are related to the information in this chapter: 
  10921.  
  10922. o File Systems 
  10923. o File Names 
  10924. o File Management 
  10925. o Semaphores. 
  10926.  
  10927.  
  10928. ΓòÉΓòÉΓòÉ 14.1. About Device I/O ΓòÉΓòÉΓòÉ
  10929.  
  10930. The OS/2 operating system uses devices to communicate with the real world. A 
  10931. device is a piece of hardware used for input and output. The keyboard and 
  10932. screen are devices, as are serial and parallel ports. The computer's speaker, 
  10933. which can be made to beep using DosBeep, is a device. 
  10934.  
  10935.  
  10936. ΓòÉΓòÉΓòÉ 14.1.1. Accessing Devices ΓòÉΓòÉΓòÉ
  10937.  
  10938. OS/2 applications usually communicate with devices through the operating 
  10939. system. Some devices, like the screen, have their own set of supporting 
  10940. functions. Most other devices can be accessed by using the standard OS/2 file 
  10941. system functions- DosOpen, DosRead, DosWrite, and DosClose. Using the file 
  10942. system functions, an application can open and access the device just as it 
  10943. would a disk file. Using the file system also enables applications to redirect 
  10944. the device's I/O stream. 
  10945.  
  10946. Sometimes however, these higher-level approaches do not suffice. For these 
  10947. situations, the operating system provides several functions that interface with 
  10948. devices at a lower level. DosDevConfig is used to retrieve information about 
  10949. the devices available. DosPhysicalDisk can be used to retrieve information 
  10950. about a partitionable hard disk. DosDevIOCtl is used to send device-specific 
  10951. commands directly to a particular device driver. 
  10952.  
  10953.  
  10954. ΓòÉΓòÉΓòÉ 14.1.2. Device Names ΓòÉΓòÉΓòÉ
  10955.  
  10956. To open a device using DosOpen, the application must supply the reserved name 
  10957. for that device. For example, to open the console (both keyboard and screen), 
  10958. you must specify the name CON. 
  10959.  
  10960. The following table shows some of the common reserved device names: 
  10961.  
  10962. Common Device Names 
  10963.  
  10964. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  10965. ΓöéDevice NameΓöéDescription                                       Γöé
  10966. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10967. ΓöéCON        ΓöéThe system console. This device consists of both  Γöé
  10968. Γöé           Γöéthe keyboard and the screen. You can open CON for Γöé
  10969. Γöé           Γöéreading (from the keyboard), writing (to the      Γöé
  10970. Γöé           Γöéscreen), or both.                                 Γöé
  10971. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10972. ΓöéCOM1       ΓöéSerial port 1. You can open this device for       Γöé
  10973. Γöé           Γöéreading, writing, or both. Other serial ports willΓöé
  10974. Γöé           Γöéhave names in ascending sequence-COM2, COM3, and  Γöé
  10975. Γöé           Γöéso on.                                            Γöé
  10976. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10977. ΓöéPRN        ΓöéThe default printer port. This device corresponds Γöé
  10978. Γöé           Γöéto one of the system's parallel ports, usually    Γöé
  10979. Γöé           ΓöéLPT1. You can open it for writing but not for     Γöé
  10980. Γöé           Γöéreading.                                          Γöé
  10981. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10982. ΓöéLPT1       ΓöéParallel port 1. You can open this device for     Γöé
  10983. Γöé           Γöéwriting but not for reading. Other parallel ports Γöé
  10984. Γöé           Γöéwill have names in ascending sequence-LPT2, LPT3, Γöé
  10985. Γöé           Γöéand so on.                                        Γöé
  10986. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10987. ΓöéNUL        ΓöéThe null device. This device provides a method of Γöé
  10988. Γöé           Γöédiscarding output. If you open this device for    Γöé
  10989. Γöé           Γöéwriting, any data written to the file is          Γöé
  10990. Γöé           Γöédiscarded. If you open the device for reading, anyΓöé
  10991. Γöé           Γöéattempt to read from the file returns an          Γöé
  10992. Γöé           Γöéend-of-file mark.                                 Γöé
  10993. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  10994. ΓöéSCREEN$    ΓöéThe screen. This device can be written to but not Γöé
  10995. Γöé           Γöéread from. Writing to the screen is similar to    Γöé
  10996. Γöé           Γöéwriting to the system console. Bytes are displayedΓöé
  10997. Γöé           Γöéas characters (unless the ANSI screen driver is   Γöé
  10998. Γöé           Γöéloaded and the character represents an ANSI escapeΓöé
  10999. Γöé           Γöésequence).                                        Γöé
  11000. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11001. ΓöéKBD$       ΓöéThe keyboard. This device can be read from but notΓöé
  11002. Γöé           Γöéwritten to. Reading from the keyboard is similar  Γöé
  11003. Γöé           Γöéto reading from the system console.               Γöé
  11004. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  11005.  
  11006. After an application uses a device, it should close it by using DosClose. 
  11007.  
  11008.  
  11009. ΓòÉΓòÉΓòÉ 14.1.3. Device Drivers ΓòÉΓòÉΓòÉ
  11010.  
  11011. The operating system communicates with devices through special programs called 
  11012. device drivers. A device driver acts as an interface between the operating 
  11013. system, together with its applications, and a physical device such as the 
  11014. keyboard, mouse, or printer. The device driver sends data to and receives data 
  11015. from a device, resolving device-independent requests from applications with the 
  11016. device-specific attributes of the device. 
  11017.  
  11018. The primary method of communication between the operating system and a device 
  11019. driver is request packets. The operating system receives I/O requests from 
  11020. applications and sends data in the form of request packets to the device 
  11021. driver. The device driver communicates with the device either directly or 
  11022. through the BIOS and ABIOS interfaces. (Applications can communicate with 
  11023. device drivers also, by using DosDevIOCtl. See IOCtl Interface) 
  11024.  
  11025. Devices work differently depending on the device driver installed. For example, 
  11026. if an application writes to the system console, each byte is interpreted as a 
  11027. character and is displayed on the screen. If, however, the ANSI display driver 
  11028. is loaded, some byte sequences direct the system to carry out certain actions 
  11029. on the screen, such as moving the cursor or clearing the screen. These byte 
  11030. sequences are called ANSI escape sequences. 
  11031.  
  11032. Some devices are available to applications only if the appropriate device 
  11033. driver is installed. For example, an application cannot open a serial port 
  11034. unless a communications device driver, such as COM.SYS, has been loaded by 
  11035. using a DEVICE= command in CONFIG.SYS. 
  11036.  
  11037.  
  11038. ΓòÉΓòÉΓòÉ 14.1.4. IOCtl Interface ΓòÉΓòÉΓòÉ
  11039.  
  11040. Many devices have more than one operating mode. For example, a serial port 
  11041. typically can operate at a variety of bit rates (sometimes called baud rates). 
  11042. Because the modes are unique to each device, the operating system does not 
  11043. include specific functions to set or retrieve these modes. Instead the 
  11044. operating system provides an I/O Control (IOCtl) interface to enable 
  11045. applications to control devices by communicating directly with the device 
  11046. driver. 
  11047.  
  11048. The IOCtl interface is a method that an application or subsystem can use to 
  11049. send device-specific control commands to a device driver. The IOCtl interface 
  11050. function for OS/2 applications is DosDevIOCtl. 
  11051.  
  11052. DosDevIOCtl provides a generic, expandable IOCtl facility. Applications send 
  11053. commands and data to the device driver with DosDevIOCtl. The OS/2 kernel 
  11054. reformats the generic IOCtl packets into request packets then calls the device 
  11055. driver. The device driver then carries out the specified action. IOCtl commands 
  11056. can be sent to both block and character device drivers. 
  11057.  
  11058. Before using DosDevIOCtl, the application or subsystem must first obtain the 
  11059. device handle by calling DosOpen for the device name. The opened device handle 
  11060. is used to specify the device the command is to go to. 
  11061.  
  11062. Refer to the Control Program Programming Reference for details of DosDevIOCtl. 
  11063.  
  11064.  
  11065. ΓòÉΓòÉΓòÉ 14.1.5. IOCtl Commands ΓòÉΓòÉΓòÉ
  11066.  
  11067. DosDevIOCtl has many subfunctions. These are called generic IOCtl commands and 
  11068. typically are used to retrieve data from a device driver that is not available 
  11069. through standard OS/2 functions. For example, an application can use these 
  11070. functions to set the bit rate of a serial port or read input directly from a 
  11071. sector on a disk. 
  11072.  
  11073.  
  11074. ΓòÉΓòÉΓòÉ 14.1.5.1. Category and Function Codes ΓòÉΓòÉΓòÉ
  11075.  
  11076. Each IOCtl function has a category and a function code. The category defines 
  11077. the type of device to be accessed. The operating system has several predefined 
  11078. categories. In general, all codes in the range 0x0000 through 0x007F are 
  11079. reserved for predefined categories. A device driver can use additional 
  11080. categories, but they must be explicitly defined by the device and be in the 
  11081. range 0x0080 through 0x00FF. 
  11082.  
  11083. In each category, a function code defines the action to carry out, such as 
  11084. reading from or writing to the device and retrieving or setting the device 
  11085. modes. The number and meaning of each function code depend on the device driver 
  11086. and the specified category. 
  11087.  
  11088. There is a listing of the IOCtl control functions, by category and function, 
  11089. with parameter and data packet structures, in the Generic IOCtl Commands 
  11090. chapter in the Physical Device Driver Reference. 
  11091.  
  11092.  
  11093. ΓòÉΓòÉΓòÉ 14.1.5.2. Parameter and Data Packets ΓòÉΓòÉΓòÉ
  11094.  
  11095. DosDevIOCtl uses a parameter packet and a data packet to pass information to 
  11096. and from the device driver. The packets can vary in format and length, 
  11097. depending on the IOCtl function. Simple functions might use only a single 
  11098. variable, while more complex functions might require a more complex data 
  11099. structure for the parameter packet, the data packet, or both. 
  11100.  
  11101. There is a listing of the IOCtl control functions, by category and function, 
  11102. with parameter and data packet structures, in the Generic IOCtl Commands 
  11103. chapter in the Physical Device Driver Reference. 
  11104.  
  11105.  
  11106. ΓòÉΓòÉΓòÉ 14.2. Using the File System to Access Devices ΓòÉΓòÉΓòÉ
  11107.  
  11108. An application can use the OS/2 file system functions-DosOpen, DosRead, 
  11109. DosWrite, and DosClose-with the standard (predefined) devices. The application 
  11110. simply specifies the name of the device in the call to DosOpen, then uses the 
  11111. returned handle to read from and write to the device. When the application has 
  11112. finished using the device, the application should close the device handle by 
  11113. using DosClose. 
  11114.  
  11115. The following code fragment shows how an application can open the COM1 device 
  11116. (serial port 1) and write the contents of a disk file to the communications 
  11117. port: 
  11118.  
  11119.     #define INCL_DOSFILEMGR    /* File System values */
  11120.     #define INCL_DOSDEVIOCTL   /* DosDevIOCtl values */
  11121.     #include <os2.h>
  11122.  
  11123.     BYTE abBuf[512];
  11124.     HFILE hfCom, hfFile;
  11125.     ULONG ulAction, cbRead, cbWritten;
  11126.  
  11127.     DosOpen("COM1", &hfCom, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  11128.             OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL);
  11129.  
  11130.     DosOpen("testfile", &hfFile, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  11131.             OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE, (PEAOP2) NULL);
  11132.  
  11133.     do {
  11134.         DosRead(hfFile, abBuf, sizeof(abBuf), &cbRead);
  11135.         DosWrite(hfCom, abBuf, cbRead, &cbWritten);
  11136.     } while(cbRead);
  11137.  
  11138.     DosClose(hfCom);
  11139.  
  11140.     DosClose(hfFile);
  11141.  
  11142.  
  11143. Writing the Contents of a Disk File to the COM1 Serial Port 
  11144.  
  11145. Note:  In this example code fragment and the ones that follow, error checking 
  11146.        was left out to conserve space. Applications should always check the 
  11147.        return code that the functions return. Control Program functions return 
  11148.        an APIRET value. A return code of 0 indicates success. If a non-zero 
  11149.        value is returned, an error occurred. 
  11150.  
  11151.  
  11152. ΓòÉΓòÉΓòÉ 14.3. Using IOCtl Functions to Access Devices ΓòÉΓòÉΓòÉ
  11153.  
  11154. Many OS/2 functions communicate with devices. Usually, this communication is 
  11155. transparent to the application (the application has no knowledge of how the 
  11156. communication actually occurs). At times, however, an application requires more 
  11157. direct access to a device. To accommodate this need, the operating system 
  11158. furnishes DosDevIOCtl. Applications can use DosDevIOCtl to send commands and 
  11159. data to a device driver; the device driver interprets these commands and sends 
  11160. the appropriate instructions to the physical device. 
  11161.  
  11162. As an example, some devices have several operating modes. A communications port 
  11163. can operate at one of a number of bit rates and have several data-word formats. 
  11164. The actual commands to set these parameters might vary, depending on the 
  11165. communications hardware. 
  11166.  
  11167. Named constants have been defined for the categories, functions, and commands 
  11168. that are passed to a device driver, to make it easier for application 
  11169. programmers to use DosDevIOCtl. These named constants are defined in the file 
  11170. BSEDEV.H. This file must be included in your application when you use the 
  11171. constants. This file also contains data structure definitions for the parameter 
  11172. and data packets commonly used with DosDevIOCtl. The following examples use the 
  11173. communications port to demonstrate how DosDevIOCtl works. 
  11174.  
  11175.  
  11176. ΓòÉΓòÉΓòÉ 14.3.1. Setting Communications-Port Parameters ΓòÉΓòÉΓòÉ
  11177.  
  11178. You can use DosDevIOCtl to control the data parameters (bit rate, stop bits, 
  11179. parity, and data bits) of a communications port and to get the status of the 
  11180. COM port. The IOCTL_ASYNC category is used for communications-port control. The 
  11181. ASYNC_SETBAUDRATE function sets the COM port transmission rate. The 
  11182. ASYNC_GETCOMMSTATUS returns the COM port status-byte. 
  11183.  
  11184.  
  11185. ΓòÉΓòÉΓòÉ 14.3.1.1. Setting the Data Rate ΓòÉΓòÉΓòÉ
  11186.  
  11187. The ASYNC_SETBAUDRATE function sets the bit rate of a communications port. 
  11188.  
  11189. The following code fragment sets the bit rate of COM1 to 9600 bits per second: 
  11190.  
  11191.     #define INCL_DOSFILEMGR    /* File System values */
  11192.     #define INCL_DOSDEVIOCTL   /* DosDevIOCtl values */
  11193.     #include <os2.h>
  11194.  
  11195.     HFILE   hf;                /* File handle for the device           */
  11196.     USHORT  usBPS = 9600;      /* Bit rate to set the COM port to      */
  11197.     ULONG   ulParmLen = 2;     /* Maximum size of the parameter packet */
  11198.     ULONG   ulAction;          /* Action taken by DosOpen              */
  11199.     APIRET  rc;                /* Return code                          */
  11200.  
  11201.     rc = DosOpen("COM1", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  11202.                  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL);
  11203.  
  11204.     rc = DosDevIOCtl(hf,                 /* Device handle                  */
  11205.                      IOCTL_ASYNC,        /* Serial-device control          */
  11206.                      ASYNC_SETBAUDRATE,  /* Sets bit rate                  */
  11207.                      (PULONG) &usBPS,    /* Points at bit rate             */
  11208.                      sizeof(usBPS),      /* Maximum size of parameter list */
  11209.                      &ulParmLen,         /* Size of parameter packet       */
  11210.                      NULL,               /* No data packet                 */
  11211.                      0,                  /* Maximum size of data packet    */
  11212.                      NULL);              /* Size of data packet            */
  11213.     .
  11214.     .   /* Use the COM port here. */
  11215.     .
  11216.  
  11217.     rc = DosClose(hf);
  11218.  
  11219.  
  11220. Setting COM1 to 9600 Bits Per Second 
  11221.  
  11222.  
  11223. ΓòÉΓòÉΓòÉ 14.3.1.2. Getting the COM Port Transmission Status ΓòÉΓòÉΓòÉ
  11224.  
  11225. The ASYNC_GETCOMMSTATUS function get the transmission status of the specified 
  11226. COM port. This function has no parameter packet. 
  11227.  
  11228. The following code fragment uses the ASYNC_GETCOMMSTATUS function to get the 
  11229. transmission status of COM1: 
  11230.  
  11231.     #define INCL_DOSFILEMGR    /* File System values */
  11232.     #define INCL_DOSDEVIOCTL   /* DosDevIOCtl values */
  11233.     #include <os2.h>
  11234.  
  11235.     HFILE   hf;           /* File handle for the device         */
  11236.     UCHAR   ucStatus;     /* The COM port status byte           */
  11237.     ULONG   ulStatusLen;  /* Length of status (the data packet) */
  11238.     ULONG   ulAction;     /* Action taken by DosOpen            */
  11239.     APIRET  rc;           /* Return code                        */
  11240.  
  11241.     rc = DosOpen("COM1", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN,
  11242.                  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL);
  11243.  
  11244.     rc = DosDevIOCtl(hf,                   /* Device handle                    */
  11245.                      IOCTL_ASYNC,          /* Serial-device control            */
  11246.                      ASYNC_GETCOMMSTATUS,  /* Get the COM status byte          */
  11247.                      NULL,                 /* No parameter packet              */
  11248.                      0,                    /* Maximum size of parameter packet */
  11249.                      NULL,                 /* Length of parameter packet       */
  11250.                      (PULONG) &ucStatus,   /* Data packet                      */
  11251.                      sizeof(ucStatus),     /* Maximum size of data packet      */
  11252.                      &ulStatusLen);        /* Length of data packet            */
  11253.     .
  11254.     .   /* Use the COM port here. */
  11255.     .
  11256.  
  11257.     rc = DosClose(hf);
  11258.  
  11259.  
  11260. Getting the Transmission Status of COM1 
  11261.  
  11262.  
  11263. ΓòÉΓòÉΓòÉ 14.4. Summary of Functions and Data Structures Used for Device I/O ΓòÉΓòÉΓòÉ
  11264.  
  11265. Following are the OS/2 functions and data structures used for device I/O. 
  11266.  
  11267. Device I/O Functions 
  11268.  
  11269. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  11270. ΓöéDosBeep                       ΓöéGenerates sound from the      Γöé
  11271. Γöé                              Γöéspeaker                       Γöé
  11272. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11273. ΓöéDosDevConfig                  ΓöéReturns information about an  Γöé
  11274. Γöé                              Γöéattached device, such as a    Γöé
  11275. Γöé                              Γöéprinter or a floppy disk      Γöé
  11276. Γöé                              Γöédrive.                        Γöé
  11277. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11278. ΓöéDosDevIOCtl                   ΓöéPerforms control functions on Γöé
  11279. Γöé                              Γöéa device that is specified by Γöé
  11280. Γöé                              Γöéan opened device handle       Γöé
  11281. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11282. ΓöéDosPhysicalDisk               ΓöéObtains information about     Γöé
  11283. Γöé                              Γöépartitionable disks           Γöé
  11284. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11285. ΓöéFile System Functions Used to Γöé                              Γöé
  11286. ΓöéPerform I/O to Devices        Γöé                              Γöé
  11287. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11288. ΓöéDosClose                      ΓöéCloses a file or device.      Γöé
  11289. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11290. ΓöéDosOpen                       ΓöéOpens a file or device for    Γöé
  11291. Γöé                              ΓöéI/O.                          Γöé
  11292. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11293. ΓöéDosRead                       ΓöéReads from a file or device.  Γöé
  11294. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11295. ΓöéDosWrite                      ΓöéWrites to a file or device.   Γöé
  11296. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  11297.  
  11298. Device I/O Data Structures 
  11299.  
  11300. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  11301. ΓöéData Structure                ΓöéDescription                   Γöé
  11302. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11303. ΓöéLINECONTROL                   ΓöéUsed to set the line          Γöé
  11304. Γöé                              Γöécharacteristics of a COM port Γöé
  11305. Γöé                              Γöéthrough the IOCtl interface.  Γöé
  11306. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11307. ΓöéBIOSPARAMETERBLOCK            ΓöéUsed to return information    Γöé
  11308. Γöé                              Γöéabout a logical disk through  Γöé
  11309. Γöé                              Γöéthe IOCtl interface.          Γöé
  11310. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11311. ΓöéTRACKLAYOUT                   ΓöéUsed for reading and writing  Γöé
  11312. Γöé                              Γöédisk sectors through the IOCtlΓöé
  11313. Γöé                              Γöéinterface.                    Γöé
  11314. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  11315.  
  11316.  
  11317. ΓòÉΓòÉΓòÉ 15. Queues ΓòÉΓòÉΓòÉ
  11318.  
  11319. Communication between processes is valuable in a multitasking operating system 
  11320. to enable concurrent processes to work together. Queues are one of three forms 
  11321. of interprocess communication (IPC), the other forms of IPC being semaphores 
  11322. and pipes. 
  11323.  
  11324. This chapter describes how to create and use queues. Queues enable one or more 
  11325. processes to transfer data to a specific target process. 
  11326.  
  11327. Note:  The queues used for interprocess communication should not to be confused 
  11328.        with the message queues used for communication between Presentation 
  11329.        Manager (PM) and PM applications, nor with the printer queues used by 
  11330.        the print spooler in managing print jobs. 
  11331.  
  11332. The following topics are related to the information in this chapter: 
  11333.  
  11334. o Memory (Shared Memory) 
  11335. o Program Execution and Control 
  11336. o Semaphores 
  11337. o Pipes. 
  11338.  
  11339.  
  11340. ΓòÉΓòÉΓòÉ 15.1. About Queues ΓòÉΓòÉΓòÉ
  11341.  
  11342. A queue is a named, ordered list of elements that is used to pass information 
  11343. between threads of the same (related) process or between different (unrelated) 
  11344. processes. 
  11345.  
  11346. Processes pass information to a queue in the form of elements. An element is a 
  11347. 32-bit unit of information. Queue elements can be values, flags, pointers to 
  11348. shared memory regions, anything that can fit into 32 bits. The format of a 
  11349. queue element depends entirely on the process that creates the queue (the queue 
  11350. owner). Only the queue owner can read elements from the queue; other processes 
  11351. can only write to the queue. Reading an element automatically removes it from 
  11352. the queue. 
  11353.  
  11354. The process that creates the queue is known as the server process of the queue. 
  11355. The other processes that access the queue are known as client processes. 
  11356.  
  11357. The owner of the queue (the server process) can choose the order in which to 
  11358. read incoming information and can examine queue elements without removing them 
  11359. from the queue. Queue elements can be added and accessed in First-In-First-Out 
  11360. (FIFO), Last-In-First-Out (LIFO), or priority-based order. 
  11361.  
  11362. Any process that has the name of a queue can open the queue and write to it. 
  11363. The processes writing elements to the queue must use the format determined by 
  11364. the queue owner. 
  11365.  
  11366. Queues are very efficient. They pass only 32-bit sized elements, rather than 
  11367. large data structures. However, queues can be used only for one-way 
  11368. communication, because a client process can write to a queue but cannot read 
  11369. from one. 
  11370.  
  11371. Typically, processes use queues to transfer information about the contents of a 
  11372. shared memory. The elements in the queue could contain the address and length 
  11373. of data areas in shared memory objects. The sending process allocates a shared 
  11374. memory object and gives access to the shared memory to the queue owner. The 
  11375. sending process can free the shared memory after writing the elements to the 
  11376. queue because the shared memory will not be deallocated until the queue owner 
  11377. frees it. 
  11378.  
  11379. Any thread in the process that owns the queue can examine queue elements 
  11380. without removing them. This is called peeking at the queue. 
  11381.  
  11382. The operating system supplies the process identifier of the process that writes 
  11383. an element to the queue, so that a process reading from or peeking at the queue 
  11384. can determine the origin of the element. The process identifier is returned as 
  11385. part of a REQUESTDATA data structure. Threads can use the ulData field of the 
  11386. REQUESTDATA data structure to pass additional information about the queue 
  11387. element. 
  11388.  
  11389. If the queue is empty when a process attempts to read from it, the process can 
  11390. either wait for an element to become available or continue executing without 
  11391. reading from the queue. Semaphores can be used to indicate when an element is 
  11392. in the queue. 
  11393.  
  11394.  
  11395. ΓòÉΓòÉΓòÉ 15.1.1. Queues and Semaphores ΓòÉΓòÉΓòÉ
  11396.  
  11397. If a process manages only one queue, it typically waits for an element to 
  11398. become available. However, if a process manages several queues, waiting for one 
  11399. queue means that other queues cannot be read. To avoid wasting time while 
  11400. waiting, a process can supply an event semaphore when it calls DosReadQueue or 
  11401. DosPeekQueue. The process can then continue to execute without actually reading 
  11402. an element from the queue, because DosWriteQueue will post the semaphore only 
  11403. when an element is ready. The semaphore remains posted until someone resets it; 
  11404. usually  the queue owner process resets the semaphore after it reads all the 
  11405. available information from the queue. 
  11406.  
  11407. If a process uses a unique semaphore for each queue, it can use 
  11408. DosWaitMuxWaitSem to wait for the first queue to receive an element. 
  11409.  
  11410. Only one semaphore is permitted per queue. 
  11411.  
  11412.  
  11413. ΓòÉΓòÉΓòÉ 15.1.2. Queue Servers and Clients ΓòÉΓòÉΓòÉ
  11414.  
  11415. The server process and its threads have certain queue-managing privileges. Only 
  11416. the server process and its threads can: 
  11417.  
  11418. o Examine queue elements without removing them (DosPeekQueue) 
  11419. o Remove elements from the queue (DosReadQueue) 
  11420. o Purge all the elements in a queue (DosPurgeQueue) 
  11421. o Write to the queue without opening it first (DosWriteQueue) 
  11422. o Delete the queue (DosCloseQueue). 
  11423. Both server and client processes can query the number of elements in the queue 
  11424. using DosQueryQueue. 
  11425.  
  11426. Client processes can query the queue (DosQueryQueue) and add elements to it 
  11427. (DosWriteQueue), but they must first gain access to the queue by calling 
  11428. DosOpenQueue. When a client process is finished with a queue, it ends its 
  11429. access to the queue by calling DosCloseQueue. (Note that, unlike the server 
  11430. process and its threads, a client process cannot use DosCloseQueue to delete a 
  11431. queue.) 
  11432.  
  11433. When a queue is opened by a client process, an access count is set to 1. Each 
  11434. client process has its own access count. The access count is incremented 
  11435. whenever a thread in a process opens the queue and decremented whenever a 
  11436. thread in the process closes the queue. Access to the queue by the client 
  11437. process ends when the access count for the process reaches 0. When the server 
  11438. process closes the queue, the queue is terminated and removed from the system. 
  11439.  
  11440.  
  11441. ΓòÉΓòÉΓòÉ 15.1.3. Queue Element Order ΓòÉΓòÉΓòÉ
  11442.  
  11443. DosReadQueue reads either a specified element or the first element in the 
  11444. queue. The first element in the queue depends on the queue type, which is 
  11445. specified when the queue is created. A queue can have FIFO, LIFO, or priority 
  11446. ordering. 
  11447.  
  11448. Priority values range from 0 (lowest priority) through 15 (highest priority). 
  11449. The writing process assigns a priority to a queue element when the element is 
  11450. written to the queue. DosReadQueue reads elements from the queue in descending 
  11451. order of priority, regardless of the order in which DosWriteQueue placed the 
  11452. elements in the queue. Elements with equal priority are read in FIFO order. 
  11453.  
  11454.  
  11455. ΓòÉΓòÉΓòÉ 15.1.4. Obtaining Information about Queues and Queue Elements ΓòÉΓòÉΓòÉ
  11456.  
  11457. Any thread in the process that owns the queue can use DosPeekQueue to examine 
  11458. the elements in the queue to determine which one to actually read. Each call to 
  11459. DosPeekQueue returns the identifier of the next element in the queue, so the 
  11460. function can be called repeatedly to move through the queue. The identifier of 
  11461. the desired element can then be supplied to DosReadQueue. 
  11462.  
  11463. Any process that has opened a queue can use DosQueryQueue to determine the 
  11464. number of elements in the queue. This function also returns an error value if 
  11465. the queue owner has closed the queue. 
  11466.  
  11467.  
  11468. ΓòÉΓòÉΓòÉ 15.2. Using Queues ΓòÉΓòÉΓòÉ
  11469.  
  11470. Queues are useful for a process to manage input from other processes. The 
  11471. examples in the following sections show how to create and use queues. 
  11472.  
  11473. Note:  In the example code fragments that follow, error checking was left out 
  11474.        to conserve space. Applications should always check the return code that 
  11475.        the functions return. Control Program functions return an APIRET value. 
  11476.        A return code of 0 indicates success. If a non-zero value is returned, 
  11477.        an error occurred. 
  11478.  
  11479.  
  11480. ΓòÉΓòÉΓòÉ 15.2.1. Creating a Queue ΓòÉΓòÉΓòÉ
  11481.  
  11482. A thread creates a queue by using DosCreateQueue and specifying a queue name 
  11483. and the queue type as arguments. The queue name must be unique and have the 
  11484. following form: 
  11485.  
  11486.     \QUEUES\QueName
  11487. The "\QUEUES\" is required, though it need not be uppercase.  It is not a 
  11488. subdirectory. 
  11489.  
  11490. The QueName parameter must conform to the rules for OS/2 file names, although 
  11491. no actual file is created for the queue. 
  11492.  
  11493. The process that creates the queue is known as the server process of the queue. 
  11494. The other processes that access the queue are known as client processes. 
  11495.  
  11496. The following code fragment creates a FIFO queue named \queues\sample.que: 
  11497.  
  11498.     #define INCL_DOSQUEUES   /* Queue values */
  11499.     #include <os2.h>
  11500.  
  11501.     HQUEUE hq;
  11502.  
  11503.     DosCreateQueue(&hq, QUE_FIFO | QUE_CONVERT_ADDRESS,
  11504.                    "\\queues\\sample.que");
  11505.  
  11506.  
  11507. Creating a Named FIFO Queue 
  11508.  
  11509. When the server process creates the queue, it determines whether the ordering 
  11510. of queue elements is based on arrival (FIFO or LIFO) or priority. If the 
  11511. ordering is based on priority, then priority values must be assigned whenever 
  11512. data is added to the queue. 
  11513.  
  11514. The server must also specify whether the operating system is to convert 16-bit 
  11515. addresses of elements placed in the queue by 16-bit processes to 32-bit 
  11516. addresses. 
  11517.  
  11518. After a process has created a queue, any thread in that process can access the 
  11519. queue with equal authority. 
  11520.  
  11521.  
  11522. ΓòÉΓòÉΓòÉ 15.2.2. Allocating Memory for Queue Data ΓòÉΓòÉΓòÉ
  11523.  
  11524. When queues are used only to pass the addresses to data rather than the data 
  11525. itself, processes must allocate shared memory objects for storing queue data. 
  11526. The two most common methods of storing queue data are: 
  11527.  
  11528. o Using a named shared memory object - for related processes 
  11529. o Using unnamed shared memory objects - for unrelated processes. 
  11530.  
  11531.  
  11532. ΓòÉΓòÉΓòÉ 15.2.2.1. Named Shared Memory Objects ΓòÉΓòÉΓòÉ
  11533.  
  11534. Related processes generally use a single named shared memory object for storing 
  11535. queue data.  The server process allocates the memory object by calling 
  11536. DosAllocSharedMem. Care must be taken to ensure that the memory object is large 
  11537. enough to meet application requirements. 
  11538.  
  11539. The name of the shared memory object is established by agreement among the 
  11540. server and the client processes. For simplicity, the name can be the same as 
  11541. the queue name, except that the prefix \SHAREMEM\ must be used instead of 
  11542. \QUEUES\. 
  11543.  
  11544. A client process accesses the named shared memory object by calling 
  11545. DosGetNamedSharedMem. It must then call DosOpenQueue to gain access to the 
  11546. queue of the server. 
  11547.  
  11548. Before the server process ends, it releases the memory object by calling 
  11549. DosFreeMem. 
  11550.  
  11551.  
  11552. ΓòÉΓòÉΓòÉ 15.2.2.2. Unnamed Shared Memory Objects ΓòÉΓòÉΓòÉ
  11553.  
  11554. Unrelated processes generally use unnamed shared memory objects for storing 
  11555. queue data. This makes it possible for a client process to store data in a 
  11556. shared memory object without knowing its name. To use unnamed shared memory 
  11557. objects for storing queue data, the server process must take the following 
  11558. steps whenever it is called by a client: 
  11559.  
  11560.  1. Save the process identification (PID) of the client process. 
  11561.  2. Allocate an unnamed shared memory object for the data of the client process 
  11562.     by calling DosAllocSharedMem. 
  11563.  3. Give the client process the capability of accessing the memory object by 
  11564.     calling DosGiveSharedMem with the client's PID. 
  11565. The client process must then call DosOpenQueue to gain access to the server's 
  11566. queue. 
  11567.  
  11568. After each client completes its queue requests or ends, the server calls 
  11569. DosFreeMem to release the client's memory object. 
  11570.  
  11571.  
  11572. ΓòÉΓòÉΓòÉ 15.2.3. Opening a Queue ΓòÉΓòÉΓòÉ
  11573.  
  11574. Once the queue is created, the server process of the queue and the threads of 
  11575. the server process have immediate access to the queue and can proceed to access 
  11576. the queue. A client process must request access to a queue by calling 
  11577. DosOpenQueue. Once the queue is open, the client process can add an element to 
  11578. the queue with DosWriteQueue, and it can query the number of elements in the 
  11579. queue with DosQueryQueue. 
  11580.  
  11581. DosOpenQueue retrieves the queue handle and the process identifier of the queue 
  11582. owner. The function also increments the queue's access count. 
  11583.  
  11584. The following code fragment shows how another process would open the queue 
  11585. created with DosCreateQueue. 
  11586.  
  11587.     #define INCL_DOSQUEUES
  11588.     #include<os2.h>
  11589.  
  11590.     #define HF_STDOUT 1    /* Standard output handle */
  11591.  
  11592.     HQUEUE  hq;
  11593.     PID     pidOwner;
  11594.     ULONG   cbWritten;
  11595.     APIRET  rc;
  11596.  
  11597.     rc = DosOpenQueue(&pidOwner, &hq, "\\queues\\sample.que");
  11598.  
  11599.     if (rc) {
  11600.         DosWrite(HF_STDOUT, "\r\n Queue open failed. \r\n", 24, &cbWritten);
  11601.         DosExit(EXIT_PROCESS, 1);
  11602.     }
  11603.     else {
  11604.         DosWrite(HF_STDOUT, "\r\n Queue opened. \r\n", 19, &cbWritten);
  11605.     }
  11606.  
  11607.  
  11608. Opening a Queue 
  11609.  
  11610. When it is finished with the queue, a thread in the client process ends its 
  11611. access by calling DosCloseQueue. DosCloseQueue decrements the access count for 
  11612. the process each time it is called. When the access count reaches 0, the 
  11613. connection between the client process and the queue is terminated. 
  11614.  
  11615. After a process has opened a queue, any thread in that process can access the 
  11616. queue with equal authority. 
  11617.  
  11618. Note:  If a queue was created by a call to the 16-bit DosCreateQueue, then it 
  11619.        is not accessible to 32-bit DosOpenQueue requests, and 
  11620.        ERROR_QUE_PROC_NO_ACCESS will be returned. 
  11621.  
  11622.  
  11623. ΓòÉΓòÉΓòÉ 15.2.4. Writing to a Queue ΓòÉΓòÉΓòÉ
  11624.  
  11625. The server process and any of its threads can add an element to a queue simply 
  11626. by calling DosWriteQueue. A client process, however, must first request access 
  11627. to the queue by calling DosOpenQueue. 
  11628.  
  11629. Processes that communicate by passing the addresses of shared memory objects 
  11630. through the queue must have a shared memory object that they each have access 
  11631. to. Once a process opens the queue, it can allocate shared memory by using 
  11632. DosAllocMem with the OBJ_GIVEABLE attribute and then give the shared memory to 
  11633. the queue owner with DosGiveSharedMem. 
  11634.  
  11635. A process that has opened a queue can write to the queue by using 
  11636. DosWriteQueue. The writing process must create elements in a form that the 
  11637. queue owner can read. 
  11638.  
  11639. The following code fragment adds an element to a queue. Assume that the caller 
  11640. has placed the handle of the queue into QueueHandle already. Assume also that 
  11641. DataBuffer has been set to point to a data element in shared memory, and that 
  11642. DataLength has been set to contain the length of the data element in shared 
  11643. memory. 
  11644.  
  11645.     #define INCL_DOSQUEUES   /* Queue values */
  11646.     #include <os2.h>
  11647.     #include <stdio.h>
  11648.  
  11649.     HQUEUE   QueueHandle;   /* Queue handle                         */
  11650.     ULONG    Request;       /* Request-identification data          */
  11651.     ULONG    DataLength;    /* Length of element being added        */
  11652.     PVOID    DataBuffer;    /* Element being added                  */
  11653.     ULONG    ElemPriority;  /* Priority of element being added      */
  11654.     APIRET   rc;            /* Return code                          */
  11655.  
  11656.     Request = 0;            /* Assume that no special data is being */
  11657.                             /* sent along with this write request   */
  11658.  
  11659.     ElemPriority = 0;       /* For priority-based queues: add the   */
  11660.                             /* new queue element at the logical end */
  11661.                             /* of the queue                         */
  11662.  
  11663.     rc = DosWriteQueue(QueueHandle, Request, DataLength,
  11664.                        DataBuffer, ElemPriority);
  11665.  
  11666.     if (rc != 0) {
  11667.         printf("DosWriteQueue error: return code = %ld", rc);
  11668.         return;
  11669.     }
  11670.  
  11671.  
  11672. Adding an Element to a Queue 
  11673.  
  11674. Once the process has written to the queue, it frees the shared memory. However, 
  11675. the memory will not be freed until the queue owner also frees it. 
  11676.  
  11677. If the queue was created as a priority-based queue (as specified in the 
  11678. QueueFlags parameter of DosCreateQueue), then the priority of the element that 
  11679. is being added must be specified. 
  11680.  
  11681. If the server process has ended, or if it has closed the queue before 
  11682. DosWriteQueue is called, then ERROR_QUE_INVALID_HANDLE is returned. 
  11683.  
  11684.  
  11685. ΓòÉΓòÉΓòÉ 15.2.5. Reading from a Queue ΓòÉΓòÉΓòÉ
  11686.  
  11687. The queue owner (server process) and its threads can read an element from the 
  11688. queue by using DosReadQueue. The owner can read the first element in the queue 
  11689. by specifying 0 as the element number. Alternatively, the owner can read a 
  11690. particular element in the queue by specifying an element code returned from 
  11691. DosPeekQueue. This function is not available to client processes. 
  11692.  
  11693. DosReadQueue can either remove queue elements in the order that was specified 
  11694. when the queue was created (FIFO, LIFO, or priority), or it can use an element 
  11695. identifier from DosPeekQueue as input to remove a previously examined element. 
  11696.  
  11697. The following code fragment reads an element from the queue. Assume that the 
  11698. caller has placed the handle of the queue into QueueHandle already and that the 
  11699. identifier of the process that owns the queue has been placed into OwningPID 
  11700. already. 
  11701.  
  11702.     #define INCL_DOSQUEUES   /* Queue values */
  11703.     #include <os2.h>
  11704.     #include <stdio.h>
  11705.  
  11706.     HQUEUE        QueueHandle;   /* Queue handle                 */
  11707.     REQUESTDATA   Request;       /* Request-identification data  */
  11708.     ULONG         DataLength;    /* Length of element received   */
  11709.     PULONG        DataAddress;   /* Address of element received  */
  11710.     ULONG         ElementCode;   /* Request a particular element */
  11711.     BOOL32        NoWait;        /* No wait if queue is empty    */
  11712.     BYTE          ElemPriority;  /* Priority of element received */
  11713.     HEV           SemHandle;     /* Semaphore handle             */
  11714.     PID           OwningPID;     /* PID of queue owner           */
  11715.     APIRET        rc;            /* Return code                  */
  11716.  
  11717.     Request.pid = OwningPID;     /* Set request data block to indicate  */
  11718.                                  /* queue owner                         */
  11719.  
  11720.     ElementCode = 0;             /* Indicate that the read should start */
  11721.                                  /* at the front of the queue           */
  11722.  
  11723.     NoWait = 0;                  /* Indicate that the read should wait  */
  11724.                                  /* if the queue is currently empty     */
  11725.  
  11726.     SemHandle = 0;               /* Unused since this is a call that    */
  11727.                                  /* waits synchronously                 */
  11728.  
  11729.     rc = DosReadQueue(QueueHandle, &Request, &DataLength,
  11730.                       (PVOID *) &DataAddress, ElementCode, NoWait,
  11731.                       &ElemPriority, SemHandle);
  11732.  
  11733.     if (rc != 0) {
  11734.         printf("DosReadQueue error: return code = %ld", rc);
  11735.         return;
  11736.     }
  11737.  
  11738.  
  11739. Reading an Element from a Queue 
  11740.  
  11741. On successful return, DataLength contains the size of the element on the queue 
  11742. that is pointed to by the pointer within DataAddress, ElemPriority has been 
  11743. updated to contain the priority of the queue element pointed to by DataAddress, 
  11744. and Request.ulData contains any special data that the DosWriteQueue caller 
  11745. placed into the queue. 
  11746.  
  11747. If the queue is empty and NoWait is set to DCWW_WAIT (0), the calling thread 
  11748. waits until an element is placed in the queue. If the queue is empty and NoWait 
  11749. is set to DCWW_NOWAIT (1), DosReadQueue returns immediately with 
  11750. ERROR_QUE_EMPTY. 
  11751.  
  11752. If NoWait is set to DCWW_NOWAIT, an event semaphore must be provided so that 
  11753. the calling thread can determine when an element has been placed in the queue. 
  11754. The semaphore is created by calling DosCreateEventSem, and its handle is 
  11755. supplied as a DosReadQueue parameter. The first time an event semaphore handle 
  11756. is supplied in a DosReadQueue or DosPeekQueue request for which DCWW_NOWAIT has 
  11757. been specified for a particular queue, the handle is saved by the system. The 
  11758. same handle must be supplied in all subsequent DosReadQueue and DosPeekQueue 
  11759. requests that are called for that queue; if a different handle is supplied, 
  11760. ERROR_INVALID_PARAMETER is returned. 
  11761.  
  11762. When a client process adds an element to the queue, the system automatically 
  11763. opens the semaphore (if necessary) and posts it. The server can either call 
  11764. DosQueryEventSem periodically to determine whether the semaphore has been 
  11765. posted, or it can call DosWaitEventSem. DosWaitEventSem causes the calling 
  11766. thread to block until the semaphore is posted. 
  11767.  
  11768. After the event semaphore has been posted, the calling thread must call 
  11769. DosReadQueue again to remove the newly added queue element. 
  11770.  
  11771. If QUE_CONVERT_ADDRESS is specified in the call to DosCreateQueue, the 
  11772. operating system will automatically convert 16-bit addresses to 32-bit 
  11773. addresses. 
  11774.  
  11775.  
  11776. ΓòÉΓòÉΓòÉ 15.2.6. Peeking at a Queue ΓòÉΓòÉΓòÉ
  11777.  
  11778. The server process and its threads can examine a queue element by calling 
  11779. DosPeekQueue. This function is not available to client processes. 
  11780.  
  11781. Unlike DosReadQueue, DosPeekQueue does not remove the element from the queue. 
  11782.  
  11783. DosPeekQueue can either examine elements in the order that was specified when 
  11784. the queue was created (FIFO, LIFO, or priority), or it can examine the next 
  11785. element in the queue after a previous DosPeekQueue request has been called. By 
  11786. making multiple DosPeekQueue requests, the server process can search through a 
  11787. queue, examining each element in turn. When it locates the element it is 
  11788. searching for, the server process can remove the element from the queue by 
  11789. calling DosReadQueue. 
  11790.  
  11791. If several threads are using the same queue, the process writing to the queue 
  11792. can use the ulData field of the REQUESTDATA data structure to indicate that an 
  11793. element is directed to a particular thread. The thread can peek at the queue 
  11794. whenever data is available and read any elements containing the appropriate 
  11795. value in the ulData field. 
  11796.  
  11797. The following code fragment shows how a thread can use DosPeekQueue to examine 
  11798. the elements in a queue. Assume that a previous call to DosOpenQueue provided 
  11799. the queue handle that is contained in QueueHandle. Assume that the identifier 
  11800. of the process that owns the queue has been placed into OwningPID already. 
  11801.  
  11802.     #define INCL_DOSQUEUES       /* Queue values */
  11803.     #include <os2.h>
  11804.     #include <stdio.h>
  11805.  
  11806.     HQUEUE        QueueHandle;   /* Queue handle                  */
  11807.     REQUESTDATA   Request;       /* Request-identification data   */
  11808.     ULONG         DataLength;    /* Length of examined element    */
  11809.     PVOID         DataAddress;   /* Address of examined element   */
  11810.     ULONG         ElementCode;   /* Indicator of examined element */
  11811.     BOOL32        NoWait;        /* No wait if queue is empty     */
  11812.     BYTE          ElemPriority;  /* Priority of examined element  */
  11813.     HEV           SemHandle;     /* Semaphore handle              */
  11814.     PID           OwningPID;     /* PID of queue owner            */
  11815.     APIRET        rc;            /* Return code                   */
  11816.  
  11817.     Request.pid = OwningPID;     /* Set request data block to indicate   */
  11818.                                  /* queue owner                          */
  11819.  
  11820.     ElementCode = 0;             /* Indicate that the peek should start  */
  11821.                                  /* at the front of the queue            */
  11822.  
  11823.     NoWait = DCWW_WAIT           /* Indicate that the peek call should   */
  11824.                                  /* wait if the queue is currently empty */
  11825.  
  11826.     SemHandle = 0;               /* Unused since this is a call that     */
  11827.                                  /* synchronously waits                  */
  11828.  
  11829.     rc = DosPeekQueue(QueueHandle, &Request, &DataLength,
  11830.                       &DataAddress, &ElementCode, NoWait,
  11831.                       &ElemPriority, SemHandle);
  11832.  
  11833.     if (rc != 0) {
  11834.         printf("DosPeekQueue error: return code = %ld", rc);
  11835.         return;
  11836.     }
  11837.  
  11838.  
  11839. Peeking at the Elements of a Queue 
  11840.  
  11841. On successful return, DataLength contains the size of the element on the queue 
  11842. that is pointed to by the pointer within DataAddress, ElementCode has been 
  11843. updated to indicate the next queue element, ElemPriority has been updated to 
  11844. contain the priority of the queue element pointed to by DataAddress, and 
  11845. Request.ulData contains any special data that the DosWriteQueue caller placed 
  11846. into the queue. 
  11847.  
  11848. If the queue is empty and NoWait is set to DCWW_WAIT (0), the calling thread 
  11849. waits until an element is placed in the queue. If the queue is empty and NoWait 
  11850. is set to DCWW_NOWAIT (1), DosPeekQueue returns immediately with 
  11851. ERROR_QUE_EMPTY. 
  11852.  
  11853. If NoWait is set to DCWW_NOWAIT, an event semaphore must be provided so that 
  11854. the calling thread can determine when an element has been placed in the queue. 
  11855. The semaphore is created by calling DosCreateEventSem, and its handle is 
  11856. supplied as a DosPeekQueue parameter. The first time an event semaphore handle 
  11857. is supplied in a DosPeekQueue or DosReadQueue request for which DCWW_NOWAIT has 
  11858. been specified for a particular queue, the handle is saved by the system. The 
  11859. same handle must be supplied in all subsequent DosPeekQueue and DosReadQueue 
  11860. requests that are called for that queue; if a different handle is supplied, 
  11861. ERROR_INVALID_PARAMETER is returned. 
  11862.  
  11863. When a client process adds an element to the queue, the system automatically 
  11864. opens the semaphore (if necessary) and posts it. The server can either call 
  11865. DosQueryEventSem periodically to determine whether the semaphore has been 
  11866. posted, or it can call DosWaitEventSem. DosWaitEventSem causes the calling 
  11867. thread to block until the semaphore is posted. 
  11868.  
  11869. After the event semaphore has been posted, the calling thread must call 
  11870. DosPeekQueue again to examine the newly added queue element. 
  11871.  
  11872. If QUE_CONVERT_ADDRESS is specified in the call to DosCreateQueue, the 
  11873. operating system will automatically convert 16-bit addresses to 32-bit 
  11874. addresses. 
  11875.  
  11876.  
  11877. ΓòÉΓòÉΓòÉ 15.2.7. Purging a Queue ΓòÉΓòÉΓòÉ
  11878.  
  11879. The server process or any of its threads can empty a queue of all its elements 
  11880. by calling DosPurgeQueue. This function is not available to client processes. 
  11881.  
  11882. Warning: This is an unconditional purge of all elements in the queue. 
  11883.  
  11884. The following code fragment shows how the owner of a queue can empty the queue 
  11885. of all data elements. Assume that the owner of the queue has saved the queue's 
  11886. handle (obtained in a previous call to DosCreateQueue) in QueueHandle. 
  11887.  
  11888.     #define INCL_DOSQUEUES    /* Queue values */
  11889.     #include <os2.h>
  11890.     #include <stdio.h>
  11891.  
  11892.     HQUEUE   QueueHandle;     /* Queue handle */
  11893.     APIRET   rc;              /* Return code  */
  11894.  
  11895.     rc = DosPurgeQueue(QueueHandle);
  11896.  
  11897.     if (rc != 0) {
  11898.         printf("DosPurgeQueue error: return code = %ld", rc);
  11899.         return;
  11900.     }
  11901.  
  11902.  
  11903. Purging a Queue 
  11904.  
  11905.  
  11906. ΓòÉΓòÉΓòÉ 15.2.8. Closing a Queue ΓòÉΓòÉΓòÉ
  11907.  
  11908. DosCloseQueue can be used both to end access to a queue and to delete a queue. 
  11909. The action taken as a result of a DosCloseQueue request depends on: 
  11910.  
  11911. o Whether the requesting process is the server process or a client process 
  11912. o The value of the access count, which is maintained for each client process by 
  11913.   the operating system. The access count for a client process is incremented 
  11914.   whenever DosOpenQueue is called, and decremented whenever DosCloseQueue is 
  11915.   called. 
  11916.  
  11917. If the requesting process is a client, and the access count equals 0, 
  11918. DosCloseQueue ends the client's access to the queue, but the queue itself is 
  11919. not affected. If the access count does not equal 0, the count is decremented, 
  11920. but the process retains access to the queue. 
  11921.  
  11922. If the requesting process is the server, DosCloseQueue purges any outstanding 
  11923. elements from the queue and deletes the queue regardless of the access count; 
  11924. client processes that still have the queue open receive 
  11925. ERROR_QUE_INVALID_HANDLE on their next request. 
  11926.  
  11927.  
  11928. ΓòÉΓòÉΓòÉ 15.3. Summary of Functions and the Data Structures Used with Queues ΓòÉΓòÉΓòÉ
  11929.  
  11930. Following are the OS/2 functions and the data structures used with queues. 
  11931.  
  11932. Queue Functions 
  11933.  
  11934. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  11935. ΓöéFunction                      ΓöéDescription                   Γöé
  11936. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11937. ΓöéDosCloseQueue                 ΓöéCloses a queue.               Γöé
  11938. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11939. ΓöéDosCreateQueue                ΓöéCreates a queue.              Γöé
  11940. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11941. ΓöéDosOpenQueue                  ΓöéOpens a queue for use.        Γöé
  11942. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11943. ΓöéDosPeekQueue                  ΓöéExamines a queue element      Γöé
  11944. Γöé                              Γöéwithout removing it from the  Γöé
  11945. Γöé                              Γöéqueue. Also returns           Γöé
  11946. Γöé                              Γöéinformation about the element Γöé
  11947. Γöé                              Γöéit peeked at.                 Γöé
  11948. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11949. ΓöéDosPurgeQueue                 ΓöéEmpties a queue of all its    Γöé
  11950. Γöé                              Γöéelements.                     Γöé
  11951. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11952. ΓöéDosQueryQueue                 ΓöéReturns the number of elementsΓöé
  11953. Γöé                              Γöéin a queue.                   Γöé
  11954. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11955. ΓöéDosReadQueue                  ΓöéReads (and removes) an elementΓöé
  11956. Γöé                              Γöéfrom a queue. Also returns    Γöé
  11957. Γöé                              Γöéinformation about the element Γöé
  11958. Γöé                              Γöéit read.                      Γöé
  11959. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11960. ΓöéDosWriteQueue                 ΓöéWrites an element to a queue. Γöé
  11961. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  11962.  
  11963. Queue Data Structures 
  11964.  
  11965. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  11966. ΓöéData Structure                ΓöéDescription                   Γöé
  11967. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  11968. ΓöéREQUESTDATA                   ΓöéUsed to return information    Γöé
  11969. Γöé                              Γöéabout a queue element, and    Γöé
  11970. Γöé                              Γöéabout the process that added  Γöé
  11971. Γöé                              Γöéthe element to the queue, whenΓöé
  11972. Γöé                              Γöéthe element is read or peeked Γöé
  11973. Γöé                              Γöéat.                           Γöé
  11974. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  11975.  
  11976.  
  11977. ΓòÉΓòÉΓòÉ 16. Semaphores ΓòÉΓòÉΓòÉ
  11978.  
  11979. Communication between processes is valuable in a multitasking operating system 
  11980. to enable concurrent processes to work together. Semaphores are one of three 
  11981. forms of interprocess communication (IPC), the other forms of IPC being pipes 
  11982. and queues. 
  11983.  
  11984. This chapter describes how to create and use semaphores. Semaphores enable an 
  11985. application to signal the completion of tasks and control access to resources 
  11986. that are shared between more than one thread or process. 
  11987.  
  11988. The following topics are related to the information in this chapter: 
  11989.  
  11990. o Memory (Shared Memory) 
  11991. o Program Execution and Control 
  11992. o Pipes 
  11993. o Queues. 
  11994.  
  11995.  
  11996. ΓòÉΓòÉΓòÉ 16.1. About Semaphores ΓòÉΓòÉΓòÉ
  11997.  
  11998. Semaphores signal the beginning or ending of an operation and provide mutually 
  11999. exclusive ownership of resources. Typically, semaphores are used to prevent 
  12000. more than one process or thread within a process from accessing a resource, 
  12001. such as shared memory, at the same time. 
  12002.  
  12003. Semaphores are defined by the operating system and reside in an internal memory 
  12004. buffer. They are divided into three types, according to the functionality they 
  12005. provide: 
  12006.  
  12007. o Event semaphores enable a thread to notify waiting threads that an event has 
  12008.   occurred. The waiting threads then resume execution, performing operations 
  12009.   that are dependent on the completion of the signaled event. 
  12010.  
  12011. o Mutual exclusion (mutex) semaphores enable threads to serialize their access 
  12012.   to shared resources. That is, ownership of a mutex semaphore is used by 
  12013.   cooperating threads as a prerequisite for performing operations on a 
  12014.   resource. (Threads cooperate by using the mutex semaphore functions to ensure 
  12015.   that access to the resource is mutually exclusive.) 
  12016.  
  12017. o Multiple Wait (muxwait) semaphores enable threads to wait either for multiple 
  12018.   events to occur, or for multiple resources to become available. 
  12019.   Alternatively, a flag can be set so that a thread waits for any one of 
  12020.   multiple events to occur, or for any one of multiple resources to become 
  12021.   available. 
  12022.  
  12023.  
  12024. ΓòÉΓòÉΓòÉ 16.1.1. Event Semaphores ΓòÉΓòÉΓòÉ
  12025.  
  12026. An event semaphore provides a signaling mechanism among threads or processes, 
  12027. ensuring that events occur in the desired sequence. Event semaphores are used 
  12028. by one thread to signal other threads that an event has occurred. An 
  12029. application can use this type of semaphore to block a thread or process until 
  12030. the event has occurred. 
  12031.  
  12032. An event semaphore has two states, reset and posted. When an event semaphore is 
  12033. in the reset state, the operating system blocks any thread or process that is 
  12034. waiting on the semaphore. When an event semaphore is in the posted state, all 
  12035. threads or processes waiting on the semaphore resume execution. 
  12036.  
  12037. For example, assume thread 1 is allocating a shared memory object and threads 2 
  12038. and 3 must wait for the memory to be allocated before they attempt to examine 
  12039. its contents. Before thread 1 allocates the memory, it creates an event 
  12040. semaphore, specifying the initial state of the semaphore as reset. (If the 
  12041. event semaphore has already been created, thread 1 simply resets the 
  12042. semaphore.) Threads 2 and 3 use DosWaitEventSem to wait for the semaphore to 
  12043. signal that the event, in this case the allocation and preparation of the 
  12044. shared memory object, has been completed. Because the semaphore was reset by 
  12045. thread 1, threads 2 and 3 are blocked when they call DosWaitEventSem. After 
  12046. thread 1 has finished allocating and placing data in the shared memory object, 
  12047. it signals the completion of its task by posting the event semaphore. The 
  12048. posting of the event semaphore unblocks threads 2 and 3, enabling them to 
  12049. resume execution. They can then proceed to examine the contents of the 
  12050. allocated memory. 
  12051.  
  12052. In the example above, one thread controls the resetting and posting of the 
  12053. event semaphore, while other threads merely wait on the semaphore. Another 
  12054. approach could be for an application or thread to reset an event semaphore, 
  12055. then block itself on that semaphore. At a later time, another application or 
  12056. thread would post the event semaphore, unblocking the first thread. 
  12057.  
  12058.  
  12059. ΓòÉΓòÉΓòÉ 16.1.2. Mutual Exclusion (Mutex) Semaphores ΓòÉΓòÉΓòÉ
  12060.  
  12061. A mutual exclusion (mutex) semaphore protects resources (such as files, data in 
  12062. memory, and peripheral devices) from simultaneous access by several processes. 
  12063. Mutex semaphores enable threads to serialize their access to resources. It does 
  12064. so by preventing the processes from concurrently executing the sections of code 
  12065. through which access is made. These sections of code are called critical 
  12066. sections. For example, a mutex semaphore could be used to prevent two or more 
  12067. threads from simultaneously writing to the same file on a disk. 
  12068.  
  12069. Before a thread can execute a mutex-protected critical section, it must request 
  12070. and receive ownership of the mutex semaphore. Only the thread that has gained 
  12071. ownership of the mutex semaphore is permitted to perform operations on the 
  12072. protected resource. Only one thread at a time can own the mutex semaphore, and 
  12073. the owner thread retains ownership  until it finishes executing its critical 
  12074. section. When finished, the owner thread releases the mutex semaphore, enabling 
  12075. another thread to become the owner. 
  12076.  
  12077. When a thread requests ownership of a mutex semaphore that is already owned, 
  12078. the operating system blocks the thread. When more than one thread requests 
  12079. ownership of the same semaphore, the operating system queues the requests and 
  12080. grants subsequent ownership based on the thread's priority and the order in 
  12081. which the requests were received. 
  12082.  
  12083. If more than one thread is blocked on a DosRequestMutexSem request, then 
  12084. ownership is given to the thread that has the highest priority level. If more 
  12085. than one of the waiting threads have the same priority level, then FIFO 
  12086. ordering is used to determine which thread is unblocked and given ownership of 
  12087. the semaphore. 
  12088.  
  12089. For example, both thread 1 and thread 2 must write information to the same disk 
  12090. file. Thread 1 claims ownership of an agreed-upon mutex semaphore and starts 
  12091. writing its information to the file. If thread 2 also requests ownership of the 
  12092. semaphore, it will be blocked. When thread 1 has finished writing to the file, 
  12093. it releases the semaphore. The operating system then unblocks thread 2 and 
  12094. designates it as the new owner of the semaphore so that it can write to the 
  12095. file. 
  12096.  
  12097. During process termination, after delivery of process-termination exceptions 
  12098. and unwind exceptions, if any threads in the process aside from Thread 1 (the 
  12099. main thread) own a mutex semaphore, ownership of the semaphore (and therefore, 
  12100. the shared resource) passes to Thread 1. This gives Thread 1 a last chance to 
  12101. clean up the semaphore and the shared resource before the process ends. If 
  12102. Thread 1 ends without releasing the semaphore, all threads that are currently 
  12103. waiting on ownership of the semaphore will be unblocked with the SEM_OWNER_DIED 
  12104. return code. Any thread that attempts to open it or request ownership of the 
  12105. semaphore will receive a SEM_OWNER_DIED return code. 
  12106.  
  12107. The recommended way to clean up semaphores, and other resources, is for each 
  12108. thread, especially Thread 1, to have an exception handler to handle clean up 
  12109. during process termination (the XCPT_PROCESS_TERMINATE or 
  12110. XCPT_ASYNC_PROCESS_TERMINATE exceptions). When it is not possible to register 
  12111. an exception handler for a thread, (a DLL, for example, must de-register its 
  12112. exception handlers when it returns control to the thread that called it), you 
  12113. should add a clean up routine to the exit list of the process. 
  12114.  
  12115.  
  12116. ΓòÉΓòÉΓòÉ 16.1.3. Multiple Wait (Muxwait) Semaphores ΓòÉΓòÉΓòÉ
  12117.  
  12118. A multiple wait (muxwait) semaphore enables a thread to wait on several event 
  12119. or mutex semaphores simultaneously. A muxwait semaphore is a compound semaphore 
  12120. that consists of a list of up to 64 event semaphores or mutex semaphores (the 
  12121. two types cannot be mixed). 
  12122.  
  12123. A flag is set when the muxwait semaphore is created to enable threads to use 
  12124. the semaphore in either of two ways: 
  12125.  
  12126. o Threads can wait for all of the mutex semaphores to be released, or for all 
  12127.   of the event semaphores to be posted. 
  12128.  
  12129. o Threads can wait for any one of the mutex semaphores in the list to be 
  12130.   released, or for any one of the event semaphores in the list to be posted. 
  12131.  
  12132. Depending on the value of the flag, a muxwait semaphore is said to have cleared 
  12133. when either any or all of the semaphores in the muxwait list have been posted 
  12134. or released. 
  12135.  
  12136. For example, suppose a thread requires access to several regions of shared 
  12137. memory at the same time. The operating system blocks the thread until the 
  12138. thread acquires ownership of all the mutex semaphores protecting the shared 
  12139. regions. The thread can then access all the memory regions. Meanwhile, the 
  12140. operating system prevents access by other threads. 
  12141.  
  12142.  
  12143. ΓòÉΓòÉΓòÉ 16.1.4. Named and Anonymous Semaphores ΓòÉΓòÉΓòÉ
  12144.  
  12145. A semaphore can be either named or anonymous. A named semaphore is always 
  12146. shared; that is, it is always available to any process that knows the name. An 
  12147. anonymous semaphore can be either private to a process or shared among 
  12148. processes, depending on whether the application includes the DC_SEM_SHARED flag 
  12149. in the function that creates the semaphore. A semaphore intended for use solely 
  12150. among threads of the same process can be anonymous and private. 
  12151.  
  12152. The operating system creates a named semaphore when an application specifies a 
  12153. name in the function that creates the semaphore. The name must have the 
  12154. following form: 
  12155.  
  12156.     \SEM32\SemName
  12157.  
  12158. The "\SEM32\" is required, though it need not be uppercase. The semaphore name 
  12159. must conform to the rules for OS/2 file names, although no actual file is 
  12160. created for the semaphore. If the application does not specify a name in the 
  12161. function that creates the semaphore, the operating system creates an anonymous 
  12162. semaphore. 
  12163.  
  12164. The OS/2 operating system permits a system-wide maximum of 65536 (64K) shared 
  12165. semaphores. In addition, each process can use up to 65536 (64K) private 
  12166. semaphores. 
  12167.  
  12168. A shared muxwait semaphore must contain either all shared event semaphores or 
  12169. all shared mutex semaphores. However, a private muxwait semaphore can contain a 
  12170. combination of shared and private event or mutex semaphores. The operating 
  12171. system generates a unique handle when it creates a semaphore. Processes must 
  12172. obtain this handle before they can access the semaphore. A semaphore's handle 
  12173. is always available to the process that created the semaphore. A process can 
  12174. obtain the handle of a named semaphore created in another process by using the 
  12175. appropriate semaphore-opening function. A process that requires access to an 
  12176. anonymous shared semaphore that was created in another process must obtain the 
  12177. handle of the semaphore through some other form of interprocess communication, 
  12178. such as a pipe or a queue. 
  12179.  
  12180.  
  12181. ΓòÉΓòÉΓòÉ 16.1.5. Semaphore Management ΓòÉΓòÉΓòÉ
  12182.  
  12183. After one process creates a semaphore, threads in other processes must open the 
  12184. semaphore before they can access it. (Creating a semaphore automatically opens 
  12185. it for the creating process.) The open operation ensures that the process is a 
  12186. valid user of the semaphore. The operating system keeps track of the number of 
  12187. open operations that each process performs on a semaphore. A process can have 
  12188. up to 65535 (64K - 1) open operations performed on a semaphore at any one time. 
  12189.  
  12190. If a process finishes using a semaphore and will not use it again, the process 
  12191. should close the semaphore so that the operating system can free the memory the 
  12192. semaphore is using. The operating system returns the ERROR_SEM_BUSY error value 
  12193. if a thread tries to close a semaphore that has another thread in the same 
  12194. process still waiting for it. 
  12195.  
  12196. If a process terminates with open semaphores, the operating system 
  12197. automatically closes the semaphores for that process. 
  12198.  
  12199. Semaphores reside in a memory buffer rather than a disk file. Therefore, when 
  12200. the last process that has a semaphore open exits or closes that semaphore, the 
  12201. operating system frees the associated handle or name. 
  12202.  
  12203. When an application calls a function that causes a thread to wait on a 
  12204. semaphore, the application can specify the amount of time for the thread to 
  12205. wait. When the interval elapses without the semaphore being posted or released, 
  12206. the function returns the ERROR_TIMEOUT error value and the thread continues 
  12207. running. The application can provide a specific time-out value in milliseconds, 
  12208. or it can specify either the SEM_INDEFINITE_WAIT or the SEM_IMMEDIATE_RETURN 
  12209. flag. If a thread is interrupted while it is waiting on a semaphore, the 
  12210. ERROR_INTERRUPT error value is returned to the caller. 
  12211.  
  12212.  
  12213. ΓòÉΓòÉΓòÉ 16.2. Using Event Semaphores ΓòÉΓòÉΓòÉ
  12214.  
  12215. An application can use an event semaphore to trigger execution of other 
  12216. processes. This is useful if, for example, one process provides data to many 
  12217. other processes. Using an event semaphore frees the other process from the 
  12218. trouble of polling to determine when new data is available. 
  12219.  
  12220. Note:  In the example code fragments that follow, error checking was left out 
  12221.        to conserve space. Applications should always check the return code that 
  12222.        the functions return. Control Program functions return an APIRET value. 
  12223.        A return code of 0 indicates success. If a non-zero value is returned, 
  12224.        an error occurred. 
  12225.  
  12226.  
  12227. ΓòÉΓòÉΓòÉ 16.2.1. Creating an Event Semaphore ΓòÉΓòÉΓòÉ
  12228.  
  12229. Processes create an event semaphore by using DosCreateEventSem. The process 
  12230. that controls the event or resource is usually the one that creates the 
  12231. semaphore, but it does not have to be. 
  12232.  
  12233. Threads in the process that creates the semaphore do not have to open the 
  12234. semaphore before using it. DosCreateEventSem obtains access to the semaphore 
  12235. for the calling process and its threads. Threads in other processes must call 
  12236. DosOpenEventSem to open the semaphore before they can use it. 
  12237.  
  12238. Event semaphores can be defined as either private or shared: 
  12239.  
  12240. o Private semaphores are always unnamed and are therefore always identified by 
  12241.   their handles. They can be used only by threads within a single process. 
  12242.  
  12243. o Shared semaphores can be either named or unnamed. If named, they can be 
  12244.   opened using either the name or the handle. The handle returned by 
  12245.   DosOpenEventSem is then used to identify the semaphore for all other 
  12246.   functions. Semaphore names must include the prefix \SEM32\ and must conform 
  12247.   to file system naming conventions. Shared semaphores can be used by threads 
  12248.   in multiple processes. 
  12249.  
  12250. In the following code fragment, the controlling process creates a named event 
  12251. semaphore and posts the semaphore after writing data to a shared file: 
  12252.  
  12253.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12254.     #include <os2.h>
  12255.  
  12256.     HEV hevWriteEvent;
  12257.  
  12258.     DosCreateEventSem("\\sem32\\wrtevent",          /* Named-shared semaphore */
  12259.                        &hevWriteEvent, 0, FALSE);   /* Initially reset        */
  12260.         .
  12261.         .
  12262.         /* Write data to shared file. */
  12263.         .
  12264.         .
  12265.     DosPostEventSem(hevWriteEvent);                 /* Posts the event        */
  12266.         .
  12267.         .    /* Continue execution. */
  12268.         .
  12269.  
  12270. Creating and Posting a Named Event Semaphore 
  12271.  
  12272. There is a system-wide limit of 65536 (64K) shared semaphores (including mutex, 
  12273. event, and muxwait semaphores); in addition, each process can have up to 65536 
  12274. (64K) private semaphores. 
  12275.  
  12276. When an event semaphore is created, a flag is used to specify the initial state 
  12277. of the event semaphore, either reset or posted. If the initial state is reset, 
  12278. a thread that calls DosWaitEventSem will be blocked until a process that has 
  12279. access to the semaphore uses DosPostEventSem to post the event semaphore. If 
  12280. the initial state is posted, then a thread that calls DosWaitEventSem will 
  12281. return immediately to continue its execution. If the thread calling 
  12282. DosWaitEventSem is not in the process that created the semaphore, the thread 
  12283. must open the semaphore with DosOpenEventSem before calling DosWaitEventSem. 
  12284.  
  12285. The operating system maintains a usage count for each semaphore. 
  12286. DosCreateEventSem initializes the usage count to 1. Thereafter, each call to 
  12287. DosOpenEventSem increments the count, and each call to DosCloseEventSem 
  12288. decrements it. 
  12289.  
  12290.  
  12291. ΓòÉΓòÉΓòÉ 16.2.2. Opening an Event Semaphore ΓòÉΓòÉΓòÉ
  12292.  
  12293. When a process creates an event semaphore, all of the threads that belong to 
  12294. the process have immediate access to the semaphore. 
  12295.  
  12296. Threads in other processes must open the semaphore by calling DosOpenEventSem 
  12297. before they can use the semaphore in any other event semaphore function. 
  12298.  
  12299. The following code fragment shows how processes can open an event semaphore 
  12300. that was created in a different process and then wait for the event to be 
  12301. posted: 
  12302.  
  12303.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12304.     #include <os2.h>
  12305.  
  12306.     HEV hevEventHandle = 0;                 /* Must be 0 because we are opening */
  12307.                                             /* the semaphore by name            */
  12308.  
  12309.     DosOpenEventSem("\\sem32\\wrtevent", &hevEventHandle);
  12310.  
  12311.     DosWaitEventSem(hevEventHandle,
  12312.                     SEM_INDEFINITE_WAIT);   /* Waits until event is posted      */
  12313.         .
  12314.         .    /* Read from file when event is posted. */
  12315.         .
  12316.  
  12317. Opening an Event Semaphore and Waiting for It to be Posted 
  12318.  
  12319. Applications can open an event semaphore by name or by handle. If the name is 
  12320. used to open the semaphore, as in the code fragment above, the handle parameter 
  12321. must be 0. If the handle is used to open the semaphore, the name parameter must 
  12322. be NULL. 
  12323.  
  12324. Access to semaphores is on a per-process basis. Therefore, a semaphore that has 
  12325. been opened by one thread in a process is open to all other threads in that 
  12326. process as well. 
  12327.  
  12328. DosOpenEventSem merely provides access to an event semaphore. In order to wait 
  12329. for an event semaphore to be posted, a thread must call DosWaitEventSem. In 
  12330. order to post or reset an open event semaphore, a thread uses DosPostEventSem 
  12331. or DosResetEventSem respectively. 
  12332.  
  12333. When a process no longer requires access to an event semaphore, it closes the 
  12334. semaphore by calling DosCloseEventSem. If a process ends without closing an 
  12335. open semaphore, the semaphore is closed by the operating system. 
  12336.  
  12337. Each call to DosOpenEventSem increments the usage count of the semaphore. This 
  12338. count is initialized to 1 when the semaphore is created and is decremented by 
  12339. each call to DosCloseEventSem. When the usage count reaches 0, the semaphore is 
  12340. deleted by the operating system. 
  12341.  
  12342. Calls to DosOpenEventSem and DosCloseEventSem can be nested, but the usage 
  12343. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  12344. number, ERROR_TOO_MANY_OPENS is returned. 
  12345.  
  12346.  
  12347. ΓòÉΓòÉΓòÉ 16.2.3. Closing an Event Semaphore ΓòÉΓòÉΓòÉ
  12348.  
  12349. When a process no longer requires access to an event semaphore, it closes the 
  12350. semaphore by calling DosCloseEventSem. 
  12351.  
  12352. The following code fragment closes an event semaphore. Assume that the handle 
  12353. of the semaphore has been placed into HEV already. 
  12354.  
  12355.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12356.     #include <os2.h>
  12357.     #include <stdio.h>
  12358.  
  12359.     HEV     hev;     /* Event semaphore handle */
  12360.     APIRET  rc;      /* Return code            */
  12361.  
  12362.     rc = DosCloseEventSem(hev);
  12363.  
  12364.     if (rc != 0) {
  12365.         printf("DosCloseEventSem error: return code = %ld", rc);
  12366.         return;
  12367.     }
  12368.  
  12369.  
  12370. Closing an Event Semaphore 
  12371.  
  12372. Calls to DosOpenEventSem and DosCloseEventSem can be nested, but the usage 
  12373. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  12374. number, ERROR_TOO_MANY_OPENS is returned. 
  12375.  
  12376. If a process ends without closing an open semaphore, the semaphore is closed by 
  12377. the operating system. 
  12378.  
  12379. Each call to DosCloseEventSem decrements the usage count of the semaphore. This 
  12380. count is initialized to 1 when the semaphore is created and is incremented by 
  12381. each call to DosOpenEventSem. When the usage count reaches 0, the semaphore is 
  12382. deleted from the operating system. The call to DosCloseEventSem that decrements 
  12383. the usage count to 0 and causes the semaphore to be deleted is referred to as 
  12384. the final close. If a thread attempts to perform the final close for a 
  12385. semaphore while another thread in the same process is still waiting for it, 
  12386. ERROR_SEM_BUSY is returned. 
  12387.  
  12388.  
  12389. ΓòÉΓòÉΓòÉ 16.2.4. Resetting an Event Semaphore ΓòÉΓòÉΓòÉ
  12390.  
  12391. DosResetEventSem resets an event semaphore if it is not already reset, and 
  12392. returns the number of times the semaphore was posted since it was last reset. 
  12393. All threads that subsequently call DosWaitEventSem for this semaphore will be 
  12394. blocked. 
  12395.  
  12396. Any thread belonging to the process that created the event semaphore can change 
  12397. the state of the semaphore to reset by calling DosResetEventSem. Threads in 
  12398. other processes can also call DosResetEventSem, but they must first gain access 
  12399. to the semaphore by calling DosOpenEventSem. 
  12400.  
  12401. When an event semaphore is in the reset state, any thread that calls 
  12402. DosWaitEventSem to wait for the semaphore will be blocked. When the event 
  12403. semaphore is posted, all of the threads that are waiting for the semaphore are 
  12404. released to continue execution. 
  12405.  
  12406. The following code fragment resets an event semaphore. Assume that the handle 
  12407. of the semaphore has been placed into HEV already. 
  12408.  
  12409.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12410.     #include <os2.h>
  12411.     #include <stdio.h>
  12412.  
  12413.     HEV     hev;        /* Event semaphore handle                        */
  12414.     ULONG   ulPostCt;   /* Post count for the event semaphore (returned) */
  12415.     APIRET  rc;         /* Return code                                   */
  12416.  
  12417.     rc = DosResetEventSem(hev, &ulPostCt);
  12418.  
  12419.     if (rc != 0) {
  12420.         printf("DosResetEventSem error: return code = %ld", rc);
  12421.         return;
  12422.     }
  12423.  
  12424.  
  12425. Resetting an Event Semaphore 
  12426.  
  12427. DosResetEventSem returns the post count of the event semaphore and resets the 
  12428. post count to 0. The post count is the number of times the semaphore has been 
  12429. posted (using DosPostEventSem) since the last time the semaphore was in the 
  12430. reset state. (An event semaphore can be reset when it is created, as well as by 
  12431. calling DosResetEventSem.) The post count can also be obtained by calling 
  12432. DosQueryEventSem. 
  12433.  
  12434. If the event semaphore is already reset when DosResetEventSem is called, 
  12435. ERROR_ALREADY_RESET is returned, along with a post count of 0. The semaphore is 
  12436. not reset a second time. 
  12437.  
  12438.  
  12439. ΓòÉΓòÉΓòÉ 16.2.5. Posting an Event Semaphore ΓòÉΓòÉΓòÉ
  12440.  
  12441. DosPostEventSem posts the semaphore, if it is not already posted, and 
  12442. increments the post count. All threads that have called DosWaitEventSem for 
  12443. this semaphore are unblocked and resume execution. Threads that call 
  12444. DosWaitEventSem after the event semaphore has been posted and before the next 
  12445. time it is reset, will return immediately from a call to DosWaitEventSem and 
  12446. continue execution. If the semaphore is subsequently reset, threads that call 
  12447. DosWaitEventSem will again be blocked. 
  12448.  
  12449. Any thread in the process that created an event semaphore can post the 
  12450. semaphore by calling DosPostEventSem. Threads in other processes can also call 
  12451. DosPostEventSem, but they must first gain access to the semaphore by calling 
  12452. DosOpenEventSem. 
  12453.  
  12454. The following code fragment posts a system event semaphore. Assume that the 
  12455. handle of the semaphore has been placed into HEV already. 
  12456.  
  12457.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12458.     #include <os2.h>
  12459.     #include <stdio.h>
  12460.  
  12461.     HEV     hev;     /* Event semaphore handle */
  12462.     APIRET  rc;      /* Return code            */
  12463.  
  12464.     rc = DosPostEventSem(hev);
  12465.  
  12466.     if (rc != 0) {
  12467.         printf("DosPostEventSem error: return code = %ld", rc);
  12468.         return;
  12469.     }
  12470.  
  12471.  
  12472. Posting an Event Semaphore 
  12473.  
  12474. The operating system maintains a post count for each event semaphore. The post 
  12475. count is the number of times the semaphore has been posted (with 
  12476. DosPostEventSem) since the last time the semaphore was in the reset state. 
  12477.  
  12478. If the event semaphore is reset when DosPostEventSem is called, the semaphore 
  12479. is posted and the post count is set to 1. If the event semaphore is already 
  12480. posted when DosPostEventSem is called, the post count is incremented, and 
  12481. ERROR_ALREADY_POSTED is returned to the calling thread. 
  12482.  
  12483. The post count is returned as output by DosResetEventSem; it can also be 
  12484. obtained by calling DosQueryEventSem. 
  12485.  
  12486. The maximum number of times an event semaphore can be posted is 65535. The 
  12487. value of the post count cannot exceed 65535. If an attempt is made to exceed 
  12488. this number, DosPostEventSem returns ERROR_TOO_MANY_POSTS. 
  12489.  
  12490.  
  12491. ΓòÉΓòÉΓòÉ 16.2.6. Waiting for an Event Semaphore ΓòÉΓòÉΓòÉ
  12492.  
  12493. Any thread in the process that created an event semaphore can wait for the 
  12494. semaphore to be posted by calling DosWaitEventSem. Threads in other processes 
  12495. can also call DosWaitEventSem, but they must first gain access to the semaphore 
  12496. by calling DosOpenEventSem. 
  12497.  
  12498. If the semaphore is already posted when DosWaitEventSem is called, the function 
  12499. returns immediately, and the thread continues to run. Otherwise, the thread is 
  12500. blocked until the semaphore is posted. 
  12501.  
  12502. The following code fragment causes the calling thread to wait until the 
  12503. specified event semaphore is posted. Assume that the handle of the semaphore 
  12504. has been placed into HEV already. ulTimeout is the number of milliseconds that 
  12505. the calling thread will wait for the event semaphore to be posted. If the 
  12506. specified event semaphore is not posted during this time interval, the request 
  12507. times out. 
  12508.  
  12509.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12510.     #include <os2.h>
  12511.     #include <stdio.h>
  12512.  
  12513.     HEV     hev;        /* Event semaphore handle         */
  12514.     ULONG   ulTimeout;  /* Number of milliseconds to wait */
  12515.     APIRET  rc;         /* Return code                    */
  12516.  
  12517.     ulTimeout = 60000;  /* Wait for a maximum of 1 minute */
  12518.  
  12519.     rc = DosWaitEventSem(hev, ulTimeout);
  12520.  
  12521.     if (rc == ERROR_TIMEOUT) {
  12522.         printf("DosWaitEventSem call timed out");
  12523.         return;
  12524.     }
  12525.  
  12526.     if (rc == ERROR_INTERRUPT) {
  12527.         printf("DosWaitEventSem call was interrupted");
  12528.         return;
  12529.     }
  12530.  
  12531.     if (rc != 0) {
  12532.         printf("DosWaitEventSem error: return code = %ld", rc);
  12533.         return;
  12534.     }
  12535.  
  12536.  
  12537. Waiting for an Event Semaphore 
  12538.  
  12539. If the time limit specified in ulTimeout is reached before the semaphore is 
  12540. posted, ERROR_TIMEOUT is returned. If the waiting period is interrupted for 
  12541. some reason before the semaphore is posted, ERROR_INTERRUPT is returned. If 
  12542. SEM_IMMEDIATE_RETURN is specified for the time limit, DosWaitEventSem returns 
  12543. to the calling thread immediately. If SEM_INDEFINITE_WAIT is specified for the 
  12544. time limit, the thread waits indefinitely. 
  12545.  
  12546. Unlike multiple event semaphores in a muxwait list, which are level-triggered, 
  12547. single event semaphores are edge-triggered. This means that if an event 
  12548. semaphore is posted and then reset before a waiting thread gets a chance to 
  12549. run, the semaphore is considered to be posted for the rest of that thread's 
  12550. waiting period; the thread does not have to wait for the semaphore to be posted 
  12551. again. 
  12552.  
  12553.  
  12554. ΓòÉΓòÉΓòÉ 16.2.7. Querying an Event Semaphore ΓòÉΓòÉΓòÉ
  12555.  
  12556. DosQueryEventSem returns the current post count of a semaphore. The post count 
  12557. is the number of times that the semaphore has been posted (with 
  12558. DosPostEventSem) since the last time the semaphore was reset. A count of 0 
  12559. indicates that the semaphore is in the reset state; therefore, the operating 
  12560. system will block any threads that call DosWaitEventSem to wait on the 
  12561. semaphore. 
  12562.  
  12563. Any thread in the process that created an event semaphore can obtain the post 
  12564. count for the semaphore by calling DosQueryEventSem. Threads in other processes 
  12565. can also call DosQueryEventSem, but they must first gain access to the 
  12566. semaphore by calling DosOpenEventSem. 
  12567.  
  12568. The following code fragment retrieves the post count for an event semaphore. 
  12569. Assume that the handle of the semaphore has been placed into HEV already. 
  12570.  
  12571.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12572.     #include <os2.h>
  12573.     #include <stdio.h>
  12574.  
  12575.     HEV     hev;       /* Event semaphore handle                          */
  12576.     ULONG   ulPostCt;  /* Current post count for the semaphore (returned) */
  12577.     APIRET  rc;        /* Return code                                     */
  12578.  
  12579.     rc = DosQueryEventSem(hev, &ulPostCt);
  12580.  
  12581.     if (rc != 0) {
  12582.         printf("DosQueryEventSem error: return code = %ld", rc);
  12583.         return;
  12584.     }
  12585.  
  12586.  
  12587. Querying an Event Semaphore 
  12588.  
  12589. If the specified event semaphore does not exist, ERROR_INVALID_HANDLE is 
  12590. returned. 
  12591.  
  12592.  
  12593. ΓòÉΓòÉΓòÉ 16.3. Using Mutex Semaphores ΓòÉΓòÉΓòÉ
  12594.  
  12595. An application can use a mutual exclusion (mutex) semaphore to protect a shared 
  12596. resource from simultaneous access by multiple threads or processes. For 
  12597. example, if several processes must write to the same disk file, the mutex 
  12598. semaphore ensures that only one process at a time writes to the file. 
  12599.  
  12600.  
  12601. ΓòÉΓòÉΓòÉ 16.3.1. Creating a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12602.  
  12603. Mutex semaphores are created by calling DosCreateMutexSem. This function also 
  12604. opens the semaphore for the calling process and its threads. 
  12605.  
  12606. When a mutex semaphore is created, a flag is set to specify the initial state 
  12607. of the semaphore, owned or unowned. If the semaphore is owned by a thread, 
  12608. other threads requesting the semaphore are blocked. If the semaphore is 
  12609. unowned-not owned by any thread- then any thread requesting ownership will be 
  12610. granted ownership immediately. 
  12611.  
  12612. If the calling thread sets the initial state to owned, it owns the semaphore as 
  12613. soon as the operating system creates the semaphore and can proceed to access 
  12614. the resource that the semaphore was created to protect. 
  12615.  
  12616. If the semaphore is unowned, any thread in the creating process can 
  12617. subsequently request ownership of the semaphore by calling DosRequestMutexSem. 
  12618. Threads in other processes can gain ownership of the semaphore, but they must 
  12619. call DosOpenMutexSem to acquire access to the semaphore before they can call 
  12620. DosRequestMutexSem. 
  12621.  
  12622. Mutex semaphores can be defined as either private or shared. 
  12623.  
  12624. o Private semaphores are always unnamed and are therefore identified by their 
  12625.   handles. They can be used only by threads within a single process. 
  12626.  
  12627. o Shared semaphores can be either named or unnamed. If named, they can be 
  12628.   opened using either the name or the handle. The handle returned by 
  12629.   DosOpenMutexSem is then used to identify the semaphore for all other 
  12630.   functions. Semaphore names must include the prefix \SEM32\ and must conform 
  12631.   to file system naming conventions. Shared semaphores can be used by threads 
  12632.   in multiple processes. 
  12633.  
  12634. The following code fragment creates a mutex semaphore: 
  12635.  
  12636.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12637.     #include <os2.h>
  12638.  
  12639.     HMTX hmtxProtFile;
  12640.  
  12641.     DosCreateMutexSem("\\sem32\\ProtFile",          /* Named-shared semaphore */
  12642.                       &hmtxProtFile, 0, FALSE);     /* Initially unowned      */
  12643.         .
  12644.         .    /* Get data to write to shared file. */
  12645.         .
  12646.  
  12647.  
  12648. Creating a Mutex Semaphore 
  12649.  
  12650. There is a system-wide limit of 65536 shared semaphores (including mutex, 
  12651. event, and muxwait semaphores); in addition, each process can have up to 65536 
  12652. private semaphores. 
  12653.  
  12654. The operating system maintains a usage count for each semaphore. 
  12655. DosCreateMutexSem initializes the usage count to 1. Thereafter, each call to 
  12656. DosOpenMutexSem increments the count, and each call to DosCloseMutexSem 
  12657. decrements it. 
  12658.  
  12659.  
  12660. ΓòÉΓòÉΓòÉ 16.3.2. Opening a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12661.  
  12662. All of the threads belonging to the process that creates a mutex semaphore have 
  12663. immediate access to the semaphore. Threads in other processes must request 
  12664. access to the semaphore by calling DosOpenMutexSem before they can use the 
  12665. semaphore in other mutex semaphore functions. 
  12666.  
  12667. Access to system resources is granted on a per-process basis. Therefore, a 
  12668. semaphore that has been opened by one thread in a process is open to all other 
  12669. threads in that process as well. 
  12670.  
  12671. DosOpenMutexSem merely provides access to a mutex semaphore. To request 
  12672. ownership of a mutex semaphore, a thread must call DosRequestMutexSem. 
  12673.  
  12674. When a process no longer requires access to a mutex semaphore, it should close 
  12675. the semaphore by calling DosCloseMutexSem. However, if a process ends without 
  12676. closing an open semaphore, the semaphore is closed by the operating system. 
  12677.  
  12678. Each call to DosOpenMutexSem. increments the usage count of the semaphore. This 
  12679. count is initialized to 1 when the semaphore is created and is decremented by 
  12680. each call to DosCloseMutexSem. When the usage count reaches 0, the semaphore is 
  12681. deleted by the system. 
  12682.  
  12683. Calls to DosOpenMutexSem and DosCloseMutexSem. can be nested, but the usage 
  12684. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  12685. number, ERROR_TOO_MANY_OPENS is returned. 
  12686.  
  12687. If a process ends without releasing a mutex semaphore that it owns, any other 
  12688. thread that subsequently tries to open the semaphore will receive 
  12689. ERROR_SEM_OWNER_DIED. This return code indicates that the owning process ended 
  12690. abnormally, leaving the protected resource in an indeterminate state. However, 
  12691. the semaphore is still opened for the calling thread, enabling the thread to 
  12692. call DosQueryMutexSem to find out which process ended without releasing the 
  12693. semaphore. The thread can then take appropriate action concerning the semaphore 
  12694. and the protected resource. 
  12695.  
  12696.  
  12697. ΓòÉΓòÉΓòÉ 16.3.3. Requesting a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12698.  
  12699. In order to access a shared resource, a process must own the mutex semaphore 
  12700. that is protecting the shared resource. Ownership is obtained by first opening 
  12701. the mutex semaphore with DosOpenMutexSem, then using DosRequestMutexSem to 
  12702. request ownership of the semaphore. If another process already owns the 
  12703. semaphore, the requesting process is blocked. If the semaphore is not owned, 
  12704. the operating system grants ownership to the requesting process and the process 
  12705. can access the shared resource. When the process is finished using the shared 
  12706. resource, it uses DosReleaseMutexSem to relinquish its ownership of the 
  12707. semaphore, thereby enabling another process to gain ownership. 
  12708.  
  12709. A process can gain ownership of a mutex semaphore in three ways: 
  12710.  
  12711.  1. The thread that creates a mutex semaphore can designate itself as the owner 
  12712.     by setting a flag when it calls DosCreateMutexSem. 
  12713.  
  12714.  2. Any thread in the process that created the semaphore can request ownership 
  12715.     by calling DosRequestMutexSem. 
  12716.  
  12717.  3. A thread in another process must request access to the semaphore with 
  12718.     DosOpenMutexSem before it can call DosRequestMutexSem. 
  12719.  
  12720. Note that ownership of a mutex semaphore is given only to the requesting 
  12721. thread; it is not shared by other threads in the same process. 
  12722.  
  12723. If a mutex semaphore is unowned, DosRequestMutexSem sets it as owned and 
  12724. returns immediately to the caller. If the semaphore is already owned, the 
  12725. calling thread is blocked until either the owning thread calls 
  12726. DosReleaseMutexSem to release the semaphore, or a specified time limit is 
  12727. reached. 
  12728.  
  12729. The following code fragment shows how a process opens a mutex semaphore, 
  12730. requests it, and, after writing to the shared file, releases and closes the 
  12731. semaphore: 
  12732.  
  12733.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12734.     #include <os2.h>
  12735.  
  12736.     HMTX hmtxProtFile;
  12737.  
  12738.     DosOpenMutexSem("\\sem32\\ProtFile",
  12739.                     &hmtxProtFile);           /* Opens for this process    */
  12740.  
  12741.     DosRequestMutexSem(hmtxProtFile, 5000);   /* Returns in 5 seconds if   */
  12742.         .                                     /* Ownership not obtained    */
  12743.         .    /* Write data to shared file. */
  12744.         .
  12745.     DosReleaseMutexSem(hmtxProtFile);         /* Releases ownership        */
  12746.         .
  12747.         .    /* Continue execution. */
  12748.         .
  12749.     DosCloseMutexSem(hmtxProtFile);           /* Finished with shared file */
  12750.  
  12751.  
  12752. Opening, Requesting, Releasing, and Closing a Mutex Semaphore 
  12753.  
  12754. If more than one thread is blocked on a DosRequestMutexSem request, the thread 
  12755. with the highest priority level is the first to be unblocked and given 
  12756. ownership of the semaphore. If more than 1 of the waiting threads have the same 
  12757. priority level, then FIFO ordering is used to determine which thread is 
  12758. unblocked and given ownership. 
  12759.  
  12760. The time-out parameter (5000 milliseconds in the example above) places a limit 
  12761. on the amount of time a thread blocks on a DosRequestMutexSem request. If the 
  12762. time limit is reached before the thread gains ownership of the semaphore, 
  12763. ERROR_TIMEOUT is returned. If SEM_IMMEDIATE_RETURN is specified for the time 
  12764. limit, DosRequestMutexSem returns without blocking the thread. The thread can 
  12765. then perform other operations and call DosRequestMutexSem again later if it 
  12766. still requires access to the protected resource. If SEM_INDEFINITE_WAIT is 
  12767. specified for the time limit, the thread waits indefinitely. If the thread is 
  12768. unblocked by an external event while it is waiting for the mutex semaphore (as 
  12769. when a No Wait I/O request has just been completed), ERROR_INTERRUPT is 
  12770. returned to the caller. 
  12771.  
  12772. In addition to the usage count that the operating system maintains for all 
  12773. semaphores, the operating system maintains a request count for each mutex 
  12774. semaphore. Each call to DosRequestMutexSem increments the count, and each call 
  12775. to DosReleaseMutexSem decrements it. 
  12776.  
  12777. Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but the 
  12778. request count for a semaphore cannot exceed 65535. If an attempt is made to 
  12779. exceed this number, ERROR_TOO_MANY_SEM_REQUESTS is returned. When calls to 
  12780. DosRequestMutexSem and DosReleaseMutexSem are nested, a call to 
  12781. DosReleaseMutexSem merely decrements the request count for the semaphore; the 
  12782. semaphore is not actually released to another thread until its request count is 
  12783. 0. If a process ends while it owns a mutex semaphore, all of the currently 
  12784. blocked DosRequestMutexSem requests, as well as any future requests for the 
  12785. semaphore, return ERROR_SEM_OWNER_DIED. This return code indicates that the 
  12786. owning process ended abnormally, leaving the protected resource in an 
  12787. indeterminate state. An application that receives this error should close the 
  12788. mutex semaphore (so that it can be deleted from the operating system), because 
  12789. it is no longer valid. Appropriate action should also be taken concerning the 
  12790. protected resource. 
  12791.  
  12792.  
  12793. ΓòÉΓòÉΓòÉ 16.3.4. Releasing a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12794.  
  12795. A thread can release ownership of a mutex semaphore by calling 
  12796. DosReleaseMutexSem. Each call to DosReleaseMutexSem decrements the request 
  12797. count that is maintained for the semaphore by the operating system. Each call 
  12798. to DosRequestMutexSem increments the count. 
  12799.  
  12800. The following code fragment relinquishes ownership of a mutex semaphore. Assume 
  12801. that the handle of the semaphore has been placed into hmtx already. 
  12802.  
  12803.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12804.     #include <os2.h>
  12805.     #include <stdio.h>
  12806.  
  12807.     HMTX    hmtx;    /* Mutex semaphore handle */
  12808.     APIRET  rc;      /* Return code            */
  12809.  
  12810.     rc = DosReleaseMutexSem(hmtx);
  12811.  
  12812.     if (rc != 0) {
  12813.         printf("DosReleaseMutexSem error: return code = %ld", rc);
  12814.         return;
  12815.     }
  12816.  
  12817.  
  12818. Releasing a Mutex Semaphore 
  12819.  
  12820. Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but the 
  12821. request count cannot exceed 65535. If an attempt is made to exceed this number, 
  12822. ERROR_TOO_MANY_SEM_REQUESTS is returned. When calls to DosRequestMutexSem and 
  12823. DosReleaseMutexSem are nested, a call to DosReleaseMutexSem merely decrements 
  12824. the request count for the semaphore; the semaphore is not actually released to 
  12825. another thread until its request count is 0. 
  12826.  
  12827.  
  12828. ΓòÉΓòÉΓòÉ 16.3.5. Closing a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12829.  
  12830. When a process no longer requires access to a mutex semaphore, it can close the 
  12831. semaphore by calling DosCloseMutexSem. However, if a process ends without 
  12832. closing an open semaphore, the semaphore is closed by the operating system. 
  12833.  
  12834. The following code fragment closes a mutex semaphore. Assume that the handle of 
  12835. the semaphore has been placed into hmtx already. 
  12836.  
  12837.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12838.     #include <os2.h>
  12839.     #include <stdio.h>
  12840.  
  12841.     HMTX    hmtx;    /* Mutex semaphore handle */
  12842.     APIRET  rc;      /* Return code            */
  12843.  
  12844.     rc = DosCloseMutexSem(hmtx);
  12845.  
  12846.     if (rc != 0) {
  12847.         printf("DosCloseMutexSem error: return code = %ld", rc);
  12848.         return;
  12849.     }
  12850.  
  12851.  
  12852. Closing a Mutex Semaphore 
  12853.  
  12854. Each call to DosCloseMutexSem decrements the usage count of the semaphore. This 
  12855. count is initialized to 1 when the semaphore is created and is incremented by 
  12856. each call to DosOpenMutexSem. When the usage count reaches 0, the semaphore is 
  12857. deleted by the operating system. 
  12858.  
  12859. The call to DosCloseMutexSem that decrements the usage count to 0 and causes 
  12860. the semaphore to be deleted is referred to as the final close. The final close 
  12861. will not succeed if either of the following conditions exists: 
  12862.  
  12863. o The semaphore is owned by another thread in the same process. 
  12864.  
  12865. o Another thread in the same process is still blocked on a DosRequestMutexSem 
  12866.   request for the semaphore. 
  12867.  
  12868. For both conditions, ERROR_SEM_BUSY is returned. 
  12869.  
  12870. ERROR_SEM_BUSY is also returned if a thread tries to close a mutex semaphore 
  12871. that it still owns. The thread must first relinquish ownership of the semaphore 
  12872. by calling DosReleaseMutexSem. 
  12873.  
  12874. Calls to DosOpenMutexSem and DosCloseMutexSem can be nested, but the usage 
  12875. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  12876. number, ERROR_TOO_MANY_OPENS is returned. 
  12877.  
  12878.  
  12879. ΓòÉΓòÉΓòÉ 16.3.6. Querying a Mutex Semaphore ΓòÉΓòÉΓòÉ
  12880.  
  12881. An application can use DosQueryMutexSem to determine the current owner of a 
  12882. mutex semaphore and to obtain a count of the number of requests on it. If the 
  12883. mutex semaphore is not owned, the request count is 0. 
  12884.  
  12885. Any thread in the process that created a mutex semaphore can obtain information 
  12886. about the semaphore by calling DosQueryMutexSem. Threads in other processes can 
  12887. also call DosQueryMutexSem, but they must first gain access to the semaphore by 
  12888. calling DosOpenMutexSem. 
  12889.  
  12890. If the mutex semaphore exists and is owned, DosQueryMutexSem returns the 
  12891. process and thread identifications of the owner, as well as the request count 
  12892. for the semaphore. The request count is the number of DosRequestMutexSem calls 
  12893. minus the number of DosReleaseMutexSem calls that have been made for the 
  12894. semaphore by the owning thread. 
  12895.  
  12896. If DosQueryMutexSem returns a request count of 0, the mutex semaphore is 
  12897. unowned. 
  12898.  
  12899. If the owning process ended without calling DosCloseMutexSem, then 
  12900. ERROR_SEM_OWNER_DIED is returned, and the output parameters contain information 
  12901. about the ended owning process. 
  12902.  
  12903.  
  12904. ΓòÉΓòÉΓòÉ 16.4. Using Muxwait Semaphores ΓòÉΓòÉΓòÉ
  12905.  
  12906. A process that requires exclusive use of several shared resources at once can 
  12907. use a multiple wait (muxwait) semaphore to obtain ownership of all the mutex 
  12908. semaphores protecting the shared resources. A process can also use a muxwait 
  12909. semaphore to wait on a group of event semaphores so that the process continues 
  12910. running whenever events of interest occur. 
  12911.  
  12912. A muxwait semaphore can refer to up to 64 event or mutex semaphores. An 
  12913. application cannot refer to event and mutex semaphores in a single muxwait 
  12914. semaphore, or include a muxwait semaphore in another muxwait semaphore. 
  12915.  
  12916.  
  12917. ΓòÉΓòÉΓòÉ 16.4.1. Creating a Muxwait Semaphore ΓòÉΓòÉΓòÉ
  12918.  
  12919. DosCreateMuxWaitSem is used to create muxwait semaphores. This function also 
  12920. opens (obtains access to) the semaphore for the calling process and its 
  12921. threads. Threads in other processes must call DosOpenMuxWaitSem to open the 
  12922. semaphore before they can use it in any other muxwait semaphore function. 
  12923.  
  12924. All the semaphores in the muxwait list must be created and opened before the 
  12925. muxwait list can be created. 
  12926.  
  12927. The following code fragment creates five event semaphores and a corresponding 
  12928. array of semaphore records. The array is used to specify the semaphores 
  12929. included in the muxwait semaphore in the subsequent call to 
  12930. DosCreateMuxWaitSem. 
  12931.  
  12932.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  12933.     #include <os2.h>
  12934.  
  12935.     ULONG ulLoop, ulSem;
  12936.     HMUX hmuxHandAny;
  12937.     SEMRECORD apsr[5];
  12938.  
  12939.     /* Create event semaphores and fill semaphore-record array. */
  12940.  
  12941.     for (ulLoop = 0; ulLoop < 5; ulLoop++) {   /* Create 5 private events       */
  12942.         DosCreateEventSem((PSZ) NULL,
  12943.                           (PHEV) &apsr[ulLoop].hsemCur,
  12944.                           0,
  12945.                           FALSE);
  12946.         apsr[ulLoop].ulUser = ulLoop;          /* User-assigned data            */
  12947.     }
  12948.         .
  12949.         .
  12950.         .
  12951.  
  12952.     DosCreateMuxWaitSem((PSZ) NULL,
  12953.                         &hmuxHandAny,          /* Creates the muxwait semaphore */
  12954.                         sizeof(apsr),
  12955.                         apsr,                  /* Specifies semrecord array     */
  12956.                         DCMW_WAIT_ANY);
  12957.  
  12958.     DosWaitMuxWaitSem(hmuxHandAny,             /* Waits until one is posted     */
  12959.                       SEM_INDEFINITE_WAIT, &ulSem);
  12960.         .
  12961.         . /* Execution will continue when any event is posted. */
  12962.         .
  12963.  
  12964.  
  12965. Creating and Waiting for a Muxwait Semaphore 
  12966.  
  12967. Muxwait semaphores can be defined as either private or shared: 
  12968.  
  12969. o Private semaphores are always unnamed and are therefore always identified by 
  12970.   their handles. They can be used only by threads within a single process. 
  12971.  
  12972. o Shared semaphores can be either named or unnamed. If named, they can be 
  12973.   opened using either the name or the handle. The handle returned by 
  12974.   DosOpenMuxWaitSem is then used to identify the semaphore for all other 
  12975.   functions. Semaphore names must include the prefix \SEM32\ and must conform 
  12976.   to file system naming conventions. Shared semaphores can be used by threads 
  12977.   in multiple processes. 
  12978.  
  12979. There is a system-wide limit of 65536 (64K) shared semaphores (including mutex, 
  12980. event, and muxwait semaphores); in addition, each process can have up to 65536 
  12981. (64K) private semaphores. 
  12982.  
  12983. The following conditions apply to the kinds of semaphores that can be included 
  12984. in a muxwait-semaphore list: 
  12985.  
  12986. o The list must contain either mutex semaphores or event semaphores. It cannot 
  12987.   contain both at the same time and it cannot contain other muxwait semaphores. 
  12988.  
  12989. o If the muxwait semaphore is shared, then all the semaphores in the list must 
  12990.   also be shared. 
  12991.  
  12992. o If the muxwait semaphore is private, then the semaphores in its list can be 
  12993.   either private or shared. 
  12994.  
  12995. If any of these conditions is violated, ERROR_WRONG_TYPE is returned. 
  12996.  
  12997. The muxwait list can contain a maximum of 64 event semaphores or mutex 
  12998. semaphores. If an attempt is made to exceed this maximum, 
  12999. ERROR_TOO_MANY_SEMAPHORES is returned. 
  13000.  
  13001. If the owners of any of the mutex semaphores in the muxwait semaphore list have 
  13002. ended without releasing them, ERROR_SEM_OWNER_DIED is returned. The thread 
  13003. should call DosQueryMutexSem for each mutex semaphore in the muxwait-semaphore 
  13004. list so that it can determine which semaphores are in the Owner Died state. 
  13005.  
  13006. Each mutex semaphore that returns ERROR_SEM_OWNER_DIED from the query should be 
  13007. closed by calling DosCloseMutexSem. Also, because semaphore handles can be 
  13008. reused, the mutex semaphores that are closed must be deleted from the 
  13009. muxwait-semaphore list by calling DosDeleteMuxWaitSem. 
  13010.  
  13011. The operating system maintains a usage count for each semaphore. 
  13012. DosCreateMuxWaitSem initializes the usage count to 1. Thereafter, each call to 
  13013. DosOpenMuxWaitSem increments the count, and each call to DosCloseMuxWaitSem 
  13014. decrements it. 
  13015.  
  13016. One parameter of this function is a pointer to an array of SEMRECORD data 
  13017. structures. Each data structure contains one semaphore record for each of the 
  13018. semaphores to be included in the muxwait semaphore. A semaphore record contains 
  13019. the handle and a programmer-defined identifier for that semaphore. 
  13020.  
  13021.  
  13022. ΓòÉΓòÉΓòÉ 16.4.2. Opening a Muxwait Semaphore ΓòÉΓòÉΓòÉ
  13023.  
  13024. Processes other than the semaphore-creating process must use DosOpenMuxWaitSem 
  13025. to gain access to the muxwait semaphore before they can use the semaphore in 
  13026. any other muxwait semaphore function. All of the threads that belong to the 
  13027. process that creates the muxwait semaphore have immediate access to the 
  13028. semaphore. 
  13029.  
  13030. The following code fragment opens a system muxwait semaphore. 
  13031.  
  13032.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  13033.     #include <os2.h>
  13034.     #include <stdio.h>
  13035.  
  13036.     UCHAR   Name[40];  /* Semaphore name           */
  13037.     HMUX    hmux;      /* Muxwait semaphore handle */
  13038.     APIRET  rc;        /* Return code              */
  13039.  
  13040.     strcpy(Name, "\\SEM32\\MUXWAIT1");  /* Name of the system muxwait semaphore */
  13041.  
  13042.     rc = DosOpenMuxWaitSem(Name, &hmux);
  13043.  
  13044.     if (rc != 0) {
  13045.         printf("DosOpenMuxWaitSem error: return code = %ld", rc);
  13046.         return;
  13047.     }
  13048.  
  13049.  
  13050. Opening a Muxwait Semaphore 
  13051.  
  13052. On successful return, hmux contains the handle of the system muxwait semaphore. 
  13053.  
  13054. Opening a muxwait semaphore does not open the semaphores in its muxwait list. A 
  13055. process must open each of the semaphores included in a muxwait semaphore before 
  13056. it opens the muxwait semaphore. Otherwise, DosOpenMuxWaitSem returns the 
  13057. ERROR_INVALID_HANDLE error value to the calling function. 
  13058.  
  13059. Access to semaphores is on a per-process basis. Therefore, a semaphore that has 
  13060. been opened by one thread in a process is open to all other threads in that 
  13061. process as well. 
  13062.  
  13063. Note that DosOpenMuxWaitSem merely provides access to a muxwait semaphore. In 
  13064. order to wait for a muxwait semaphore to clear, a thread must call 
  13065. DosWaitMuxWaitSem. 
  13066.  
  13067. When a process no longer requires access to a muxwait semaphore, it closes the 
  13068. semaphore by calling DosCloseMuxWaitSem. However, if a process ends without 
  13069. closing an open semaphore, the semaphore is closed by the operating system. 
  13070.  
  13071. Each call to DosOpenMuxWaitSem increments the usage count of the semaphore. 
  13072. This count is initialized to 1 when the semaphore is created and is decremented 
  13073. by each call to DosCloseMuxWaitSem. When the usage count reaches 0, the 
  13074. semaphore is deleted by the operating system. 
  13075.  
  13076. Calls to DosOpenMuxWaitSem and DosCloseMuxWaitSem can be nested, but the usage 
  13077. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  13078. number, ERROR_TOO_MANY_OPENS is returned. 
  13079.  
  13080. Even if the owner of a mutex semaphore in a muxwait-semaphore list has ended 
  13081. without releasing the semaphore, the muxwait semaphore is still opened. 
  13082. Subsequent calls to the muxwait semaphore will return ERROR_SEM_OWNER_DIED. But 
  13083. because the process has opened the semaphore, it can then call 
  13084. DosQueryMuxWaitSem to identify all the mutex semaphores in the muxwait list. 
  13085. Next, the process can call DosQueryMutexSem for each mutex semaphore in the 
  13086. list to find out which ones are in the Owner Died state. Each mutex semaphore 
  13087. that returns ERROR_SEM_OWNER_DIED from the query should be closed by calling 
  13088. DosCloseMutexSem. Also, because semaphore handles can be reused, the mutex 
  13089. semaphores that are closed should be deleted from the muxwait-semaphore list by 
  13090. calling DosDeleteMuxWaitSem. 
  13091.  
  13092.  
  13093. ΓòÉΓòÉΓòÉ 16.4.3. Closing a Muxwait Semaphore ΓòÉΓòÉΓòÉ
  13094.  
  13095. When a process no longer requires access to a muxwait semaphore, it closes the 
  13096. semaphore by calling DosCloseMuxWaitSem. However, if a process ends without 
  13097. closing an open semaphore, the semaphore is closed by the operating system. 
  13098.  
  13099. Each call to DosCloseMuxWaitSem decrements the usage count of the semaphore. 
  13100. This count is initialized to 1 when the semaphore is created and is incremented 
  13101. by each call to DosOpenMuxWaitSem. When the usage count reaches 0, the 
  13102. semaphore is deleted by the operating system. 
  13103.  
  13104. The call to DosCloseMuxWaitSem that decrements the usage count to 0 and causes 
  13105. the semaphore to be deleted is referred to as the final close. If a thread 
  13106. attempts to perform the final close for a semaphore while another thread in the 
  13107. same process is still waiting for it, ERROR_SEM_BUSY is returned. 
  13108.  
  13109. Calls to DosOpenMuxWaitSem and DosCloseMuxWaitSem can be nested, but the usage 
  13110. count for a semaphore cannot exceed 65535. If an attempt is made to exceed this 
  13111. number, ERROR_TOO_MANY_OPENS is returned. 
  13112.  
  13113.  
  13114. ΓòÉΓòÉΓòÉ 16.4.4. Waiting for a Muxwait Semaphore ΓòÉΓòÉΓòÉ
  13115.  
  13116. A thread can wait on a muxwait semaphore by using DosWaitMuxWaitSem. 
  13117.  
  13118. Any thread in the process that created a muxwait semaphore can wait for the 
  13119. semaphore to clear by calling DosWaitMuxWaitSem. Threads in other processes can 
  13120. also call DosWaitMuxWaitSem, but they must first gain access to the semaphore 
  13121. by calling DosOpenMuxWaitSem. 
  13122.  
  13123. The following code fragment waits for a muxwait semaphore to clear. Assume that 
  13124. the handle of the semaphore has been placed into hmux already. ulTimeout is the 
  13125. number of milliseconds that the calling thread will wait for the muxwait 
  13126. semaphore to clear. If the specified muxwait semaphore is not cleared during 
  13127. this time interval, the request times out. 
  13128.  
  13129.     #define INCL_DOSSEMAPHORES   /* Semaphore values */
  13130.     #include <os2.h>
  13131.     #include <stdio.h>
  13132.  
  13133.     HMUX     hmux;      /* Muxwait semaphore handle              */
  13134.     ULONG    ulTimeout; /* Number of milliseconds to wait        */
  13135.     ULONG    ulUser;    /* User field for the semaphore that was */
  13136.                         /* posted or released (returned)         */
  13137.     APIRET   rc;        /* Return code                           */
  13138.  
  13139.     ulTimeout = 60000;  /* Wait for a maximum of 1 minute        */
  13140.  
  13141.     rc = DosWaitMuxWaitSem(hmux, ulTimeout, &ulUser);
  13142.  
  13143.     if (rc == ERROR_TIMEOUT) {
  13144.         printf("DosWaitMuxWaitSem call timed out");
  13145.         return;
  13146.     }
  13147.  
  13148.     if (rc == ERROR_INTERRUPT) {
  13149.         printf("DosWaitMuxWaitSem call was interrupted");
  13150.         return;
  13151.     }
  13152.  
  13153.     if (rc != 0) {
  13154.         printf("DosWaitMuxWaitSem error: return code = %ld", rc);
  13155.         return;
  13156.     }
  13157.  
  13158.  
  13159. Waiting for a Muxwait Semaphore 
  13160.  
  13161. On successful return, the ulUser variable contains the user identifier of the 
  13162. semaphore that caused the wait to terminate. If the caller had to wait for all 
  13163. the semaphores within the muxwait semaphore to clear, then the value 
  13164. corresponds to the last semaphore within the muxwait semaphore to clear. If the 
  13165. caller had to wait for any semaphore with the muxwait semaphore to clear, then 
  13166. the value corresponds to that semaphore. 
  13167.  
  13168. An application can use the DCMW_WAIT_ANY flag in DosCreateMuxWaitSem to block a 
  13169. thread until any one of the event or mutex semaphores included in the muxwait 
  13170. semaphore is posted or released. If the muxwait semaphore refers to mutex 
  13171. semaphores, the thread only gains ownership of the one mutex semaphore that was 
  13172. released. 
  13173.  
  13174. An application can use the DCMW_WAIT_ALL flag in DosCreateMuxWaitSem to block a 
  13175. thread until all of the event or mutex semaphores included in the muxwait 
  13176. semaphore are posted or released. If the muxwait semaphore refers to mutex 
  13177. semaphores, the thread does not gain ownership of any of the mutex semaphores 
  13178. until they are all released. When all are released, the thread becomes owner of 
  13179. all the mutex semaphores included in the muxwait semaphore. If the muxwait 
  13180. semaphore refers to event semaphores, the thread will not run until all of the 
  13181. event semaphores are in the posted state at the same time. This is because 
  13182. event semaphores in a muxwait list are level-triggered, unlike individual event 
  13183. semaphores, which are edge-triggered. 
  13184.  
  13185. For example, suppose that a thread is waiting for five event semaphores in a 
  13186. muxwait list to be posted. The first semaphore is posted and then reset. Next, 
  13187. the remaining semaphores are all posted, and they remain in the posted state. 
  13188. The thread that is waiting for the muxwait semaphore will not run until the 
  13189. first semaphore is posted again. 
  13190.  
  13191. If an application specifies the DCMW_WAIT_ANY flag when the semaphore is 
  13192. created, DosWaitMuxWaitSem returns the programmer-defined identifier of the 
  13193. semaphore that is subsequently posted or released. If an application specifies 
  13194. the DCMW_WAIT_ALL flag, DosWaitMuxWaitSem returns the programmer-defined 
  13195. identifier of the last semaphore that was posted or released. 
  13196.  
  13197. The ulTimeout parameter places a limit on the amount of time a thread blocks on 
  13198. a DosWaitMuxWaitSem request. If the time limit is reached before the semaphore 
  13199. has cleared, ERROR_TIMEOUT is returned. If SEM_IMMEDIATE_RETURN is specified as 
  13200. the time limit, DosWaitMuxWaitSem returns without blocking the thread. The 
  13201. thread can then go on to perform other operations and call DosWaitMuxWaitSem 
  13202. again later to wait for the event or mutex semaphores in the muxwait list to be 
  13203. posted or released. If a time limit of SEM_INDEFINITE_WAIT is specified, the 
  13204. thread waits (is blocked) indefinitely. If the thread is unblocked by an 
  13205. external event while it is waiting for the muxwait semaphore (as when a "no 
  13206. wait" I/O request has just been completed), DosWaitMuxWaitSem returns 
  13207. ERROR_INTERRUPT. 
  13208.  
  13209. When a thread is waiting for any one of the semaphores in a muxwait list to be 
  13210. posted or released, the semaphores are checked in the order in which they are 
  13211. defined in the list. 
  13212.  
  13213. Waiting for Multiple Event Semaphores 
  13214. The following information pertains only to muxwait semaphores that consist of 
  13215. multiple event semaphores: 
  13216.  
  13217. Unlike individual event semaphores, which are edge-triggered, event semaphores 
  13218. in a muxwait list are level-triggered. This means that if a thread is waiting 
  13219. for all of the event semaphores in the muxwait list, it will not run until all 
  13220. of the event semaphores are in the posted state at the same time. 
  13221.  
  13222. For example, a thread is waiting for five event semaphores in a muxwait list to 
  13223. be posted. The first semaphore is posted and then reset. Next, the remaining 
  13224. semaphores are all posted, and they remain in the posted state. The thread that 
  13225. is waiting for the muxwait semaphore will not run until the first semaphore is 
  13226. posted again. 
  13227.  
  13228. Waiting for Multiple Mutex Semaphores 
  13229. The following information pertains only to muxwait semaphores that consist of 
  13230. multiple mutex semaphores: 
  13231.  
  13232. o If a thread is waiting for all of the mutex semaphores in a muxwait list to 
  13233.   be released, it does not receive ownership of any of the semaphores until all 
  13234.   of the semaphores have been released. 
  13235.  
  13236. o If a thread is waiting for any one of the mutex semaphores in a muxwait list, 
  13237.   then the thread gains ownership only of the first mutex semaphore that is 
  13238.   released. The ownership of all other mutex semaphores in the muxwait list 
  13239.   remains unchanged. 
  13240.  
  13241. o If two threads have the same priority, then a thread that is waiting for a 
  13242.   mutex semaphore in a muxwait list takes precedence over a thread that has 
  13243.   requested ownership of only the individual semaphore, provided all other 
  13244.   mutex semaphores in the muxwait list have been released. For example, a mutex 
  13245.   semaphore that is part of a muxwait semaphore is released. One thread has 
  13246.   requested ownership of that single mutex semaphore, and another thread with 
  13247.   the same priority is waiting for the muxwait semaphore that contains the same 
  13248.   mutex semaphore. If all of the other mutex semaphores in the muxwait list are 
  13249.   unowned and ready to be given to the muxwait semaphore, then the thread that 
  13250.   is waiting for the muxwait semaphore will run first. 
  13251.  
  13252. o If the owners of any of the mutex semaphores in the muxwait semaphore list 
  13253.   have ended without releasing them, ERROR_SEM_OWNER_DIED is returned. The 
  13254.   thread must then call DosQueryMuxWaitSem to obtain the records of all the 
  13255.   semaphores in the muxwait list. Next, the thread must call DosQueryMutexSem 
  13256.   for each mutex semaphore in the muxwait-semaphore list so that it can 
  13257.   determine which semaphores are in the Owner Died state. 
  13258.  
  13259.   Each mutex semaphore that returns ERROR_SEM_OWNER_DIED from the query should 
  13260.   be closed by calling DosCloseMutexSem. Also, because semaphore handles can be 
  13261.   reused, the mutex semaphores that are closed should be deleted from the 
  13262.   muxwait-semaphore list by calling DosDeleteMuxWaitSem. 
  13263.  
  13264. o If any of the mutex semaphores in the muxwait list are owned by the calling 
  13265.   thread, ERROR_MUTEX_OWNED is returned. 
  13266.  
  13267.  
  13268. ΓòÉΓòÉΓòÉ 16.4.5. Adding a Semaphore to a Muxwait List ΓòÉΓòÉΓòÉ
  13269.  
  13270. An application uses DosAddMuxWaitSem to add semaphores to a muxwait semaphore 
  13271. that has already been created, even while threads are waiting on the muxwait 
  13272. semaphore. 
  13273.  
  13274. Any thread in the process that created a muxwait semaphore can add a mutex 
  13275. semaphore or an event semaphore to the muxwait list by calling 
  13276. DosAddMuxWaitSem. Threads in other processes can also use this function, but 
  13277. they must first gain access to the semaphore by calling DosOpenMuxWaitSem. 
  13278.  
  13279. A maximum of 64 semaphores can be included in a muxwait-semaphore list. If an 
  13280. attempt is made to exceed this maximum, ERROR_TOO_MANY_SEMAPHORES is returned. 
  13281.  
  13282. All of the semaphores in a muxwait-semaphore list must be of the same type. 
  13283. That is, if a mutex semaphore is being added, then the other semaphores in the 
  13284. list must be mutex semaphores. If an event semaphore is being added, then the 
  13285. other semaphores in the list must be event semaphores. A shared muxwait 
  13286. semaphore can contain only shared semaphores in its list. A private muxwait 
  13287. semaphore can contain both private and shared semaphores. If any of these 
  13288. conditions is violated, ERROR_WRONG_TYPE is returned. 
  13289.  
  13290. If the semaphore is successfully added to the muxwait list, DosAddMuxWaitSem 
  13291. checks to see whether each thread that is waiting for the muxwait semaphore has 
  13292. the newly added semaphore open in its process. The muxwait semaphore is invalid 
  13293. for any waiting threads that do not have the newly added semaphore open in 
  13294. their process; these threads are unblocked with a return code of 
  13295. ERROR_INVALID_HANDLE. Any processes that opened the muxwait semaphore before 
  13296. the add operation and that do not have the new semaphore open, will have to 
  13297. open the new semaphore before making any further use of the muxwait semaphore. 
  13298. Any future calls concerning the muxwait semaphore by processes that do not have 
  13299. the new semaphore open will have ERROR_INVALID_HANDLE returned until the new 
  13300. semaphore is opened. 
  13301.  
  13302. A thread that receives a return code of ERROR_INVALID_HANDLE can take the 
  13303. following corrective action: 
  13304.  
  13305.  1. First, the thread can obtain the records of all the semaphores in the 
  13306.     muxwait list by calling DosQueryMuxWaitSem. 
  13307.  
  13308.  2. Next, it can query each semaphore in the muxwait list, using 
  13309.     DosQueryMutexSem or DosQueryEventSem, to find out which semaphore is not 
  13310.     open to its process. 
  13311.  
  13312.  3. Finally, it can open the semaphores that are not open by calling 
  13313.     DosOpenMutexSem or DosOpenEventSem. 
  13314.  
  13315. As soon as this semaphore is opened, the muxwait semaphore becomes valid again 
  13316. for the process, as long as no other changes have been made to the muxwait list 
  13317. to make it invalid. However, in order to successfully wait for the muxwait 
  13318. semaphore, the process must call DosWaitMuxWaitSem again. 
  13319.  
  13320. A semaphore must be open for a process before the process can add that 
  13321. semaphore to a muxwait semaphore. If it is not open and a thread is waiting on 
  13322. the muxwait semaphore, DosAddMuxWaitSem returns ERROR_INVALID_HANDLE to the 
  13323. process adding the new semaphore, and the waiting thread continues waiting. 
  13324.  
  13325.  
  13326. ΓòÉΓòÉΓòÉ 16.4.6. Deleting a Semaphore from a Muxwait List ΓòÉΓòÉΓòÉ
  13327.  
  13328. An application can delete semaphores from a muxwait semaphore by using 
  13329. DosDeleteMuxWaitSem. 
  13330.  
  13331. Any thread in the process that created a muxwait semaphore can delete a mutex 
  13332. or event semaphore from the muxwait list by calling DosDeleteMuxWaitSem. 
  13333. Threads in other processes can also use this function, but they must first gain 
  13334. access to the semaphore by calling DosOpenMuxWaitSem. 
  13335.  
  13336. Semaphores can be deleted from the muxwait list even while threads are 
  13337. currently waiting for the semaphore. If the deleted semaphore is the only one 
  13338. in the muxwait list that has not yet been posted or released, then threads that 
  13339. are waiting for the muxwait semaphore are unblocked. Also, if the deleted 
  13340. semaphore happens to be the last one that a particular thread was waiting for, 
  13341. that thread is unblocked. Also, if the deleted semaphore is the last one in the 
  13342. muxwait list (that is, if the list is now empty), then all the threads that are 
  13343. waiting for the muxwait semaphore are unblocked. 
  13344.  
  13345.  
  13346. ΓòÉΓòÉΓòÉ 16.4.7. Querying a Muxwait Semaphore ΓòÉΓòÉΓòÉ
  13347.  
  13348. Processes use DosQueryMuxWaitSem  to obtain the semaphore records for each of 
  13349. the semaphores included in the muxwait semaphore. 
  13350.  
  13351. Any thread in the process that created a muxwait semaphore can obtain 
  13352. information about the semaphores in the muxwait list by calling 
  13353. DosQueryMuxWaitSem. Threads in other processes can also use this function, but 
  13354. they must first gain access to the semaphore by calling DosOpenMuxWaitSem. 
  13355.  
  13356. An application must provide this function with an array in which to store the 
  13357. semaphore records. If the array is not large enough to hold all of the 
  13358. semaphore records that are in the muxwait list, then ERROR_PARAM_TOO_SMALL is 
  13359. returned, and the record-counting parameter of DosQueryMuxWaitSem will contain 
  13360. the number of semaphore records that are in the muxwait list. The calling 
  13361. thread can then allocate the correct amount of space and call 
  13362. DosQueryMuxWaitSem again with the correct amount of space for the list of 
  13363. records. 
  13364.  
  13365. If the owner of any mutex semaphore in the muxwait-semaphore list has ended 
  13366. without releasing the semaphore, the records of all the semaphores in the list 
  13367. are still returned, but DosQueryMuxWaitSem also returns ERROR_SEM_OWNER_DIED. 
  13368. The calling thread can call DosQueryMutexSem for each mutex semaphore in the 
  13369. muxwait-semaphore list so that it can determine which semaphores are in the 
  13370. Owner Died state. The process can then close the unowned mutex semaphores. 
  13371.  
  13372. Each mutex semaphore that returns ERROR_SEM_OWNER_DIED from the query should be 
  13373. closed by calling DosCloseMutexSem. Also, because semaphore handles can be 
  13374. reused, the mutex semaphores that are closed should be deleted from the 
  13375. muxwait-semaphore list by calling DosDeleteMuxWaitSem. 
  13376.  
  13377. If the specified muxwait semaphore does not exist, ERROR_INVALID_HANDLE is 
  13378. returned. 
  13379.  
  13380.  
  13381. ΓòÉΓòÉΓòÉ 16.5. Summary of Functions and Data Structures Used with Semaphores ΓòÉΓòÉΓòÉ
  13382.  
  13383. Following are the OS/2 functions and data structures used with semaphores. 
  13384.  
  13385. Semaphore Functions 
  13386.  
  13387. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  13388. ΓöéEvent Semaphore Functions     Γöé                              Γöé
  13389. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13390. ΓöéDosCloseEventSem              ΓöéCloses an event semaphore.    Γöé
  13391. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13392. ΓöéDosCreateEventSem             ΓöéCreates an event semaphore.   Γöé
  13393. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13394. ΓöéDosOpenEventSem               ΓöéOpens an event semaphore for  Γöé
  13395. Γöé                              Γöéuse.                          Γöé
  13396. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13397. ΓöéDosPostEventSem               ΓöéPosts an event semaphore.     Γöé
  13398. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13399. ΓöéDosQueryEventSem              ΓöéReturns the post count of an  Γöé
  13400. Γöé                              Γöéevent semaphore (the number ofΓöé
  13401. Γöé                              Γöétimes the semaphore has been  Γöé
  13402. Γöé                              Γöéposted).                      Γöé
  13403. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13404. ΓöéDosResetEventSem              ΓöéResets an event semaphore.    Γöé
  13405. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13406. ΓöéDosWaitEventSem               ΓöéWaits for an event semaphore  Γöé
  13407. Γöé                              Γöéto be posted.                 Γöé
  13408. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13409. ΓöéMutex Semaphore Functions     Γöé                              Γöé
  13410. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13411. ΓöéDosCloseMutexSem              ΓöéCloses a mutex semaphore.     Γöé
  13412. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13413. ΓöéDosCreateMutexSem             ΓöéCreates a mutex semaphore.    Γöé
  13414. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13415. ΓöéDosOpenMutexSem               ΓöéOpens a mutex semaphore for   Γöé
  13416. Γöé                              Γöéuse.                          Γöé
  13417. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13418. ΓöéDosQueryMutexSem              ΓöéReturns information about the Γöé
  13419. Γöé                              Γöéowner of a mutex semaphore.   Γöé
  13420. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13421. ΓöéDosReleaseMutexSem            ΓöéReleases a mutex semaphore.   Γöé
  13422. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13423. ΓöéDosRequestMutexSem            ΓöéRequests ownership of a mutex Γöé
  13424. Γöé                              Γöésemaphore.                    Γöé
  13425. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13426. ΓöéMuxwait Semaphore Functions   Γöé                              Γöé
  13427. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13428. ΓöéDosAddMuxWaitSem              ΓöéAdds a mutex or event         Γöé
  13429. Γöé                              Γöésemaphore to a                Γöé
  13430. Γöé                              Γöémuxwait-semaphore list.       Γöé
  13431. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13432. ΓöéDosCloseMuxWaitSem            ΓöéCloses a muxwait semaphore.   Γöé
  13433. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13434. ΓöéDosCreateMuxWaitSem           ΓöéCreates a muxwait semaphore.  Γöé
  13435. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13436. ΓöéDosDeleteMuxWaitSem           ΓöéDeletes a mutex or event      Γöé
  13437. Γöé                              Γöésemaphore to a                Γöé
  13438. Γöé                              Γöémuxwait-semaphore list.       Γöé
  13439. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13440. ΓöéDosOpenMuxWaitSem             ΓöéOpens a muxwait semaphore.    Γöé
  13441. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13442. ΓöéDosQueryMuxWaitSem            ΓöéReturns the semaphore records Γöé
  13443. Γöé                              Γöéfrom a muxwait-semaphore list.Γöé
  13444. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13445. ΓöéDosWaitMuxWaitSem             ΓöéWaits for a muxwait semaphore Γöé
  13446. Γöé                              Γöéto clear.                     Γöé
  13447. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  13448.  
  13449. Semaphore Data Structures 
  13450.  
  13451. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  13452. ΓöéData Structure                ΓöéDescription                   Γöé
  13453. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13454. ΓöéSEMRECORD                     ΓöéUsed when adding a semaphore  Γöé
  13455. Γöé                              Γöéto a muxwait-semaphore list.  Γöé
  13456. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  13457.  
  13458.  
  13459. ΓòÉΓòÉΓòÉ 17. Timers ΓòÉΓòÉΓòÉ
  13460.  
  13461. This chapter describes how to create and use timers. Timers enable applications 
  13462. to time events by waiting for an interval to elapse or by waiting for a 
  13463. semaphore to be posted. 
  13464.  
  13465. The following topics are related to the information in this chapter: 
  13466.  
  13467. o Program Execution and Control 
  13468. o Semaphores. 
  13469.  
  13470.  
  13471. ΓòÉΓòÉΓòÉ 17.1. About Timers ΓòÉΓòÉΓòÉ
  13472.  
  13473. Because the OS/2 operating system is a multitasking system, an application 
  13474. cannot predict when it will lose execution control or how much time will elapse 
  13475. before control returns. A timer enables an application to suspend operation for 
  13476. a specific length of time, to block a thread until an interval has elapsed, or 
  13477. to post an event semaphore at repeated intervals. 
  13478.  
  13479. Timers are managed by the operating system. When an application requests a 
  13480. timer, the system monitors the system clock and notifies the application when 
  13481. the interval has elapsed. 
  13482.  
  13483. The system clock counts the number of system-clock interrupts (clock ticks) 
  13484. that have occurred since the system was started. On most hardware, clock ticks 
  13485. occur approximately 32 times a second, so the length of a tick is approximately 
  13486. 31.25 milliseconds. 
  13487.  
  13488. When an application specifies a timer interval, the system rounds up the 
  13489. interval to the next clock tick. For example, if an application requests a 10 
  13490. millisecond interval, it will sleep for at least 31.25 milliseconds. If an 
  13491. application requests a 100 millisecond interval, the actual interval will be at 
  13492. least 125 milliseconds (4 ticks). 
  13493.  
  13494. Because the OS/2 operating system is a preemptive operating system, there is no 
  13495. guarantee that a thread will resume immediately after the timer interval. If a 
  13496. higher priority process or thread is executing, the timed thread must wait. 
  13497.  
  13498. Although timers are not absolutely accurate, they can be used where the 
  13499. inaccuracy can be ignored. In a real-time control application, for example, an 
  13500. event can be timed in seconds or minutes, so an error of a few milliseconds is 
  13501. unimportant. If an application requires as much accuracy as the system can 
  13502. provide, it can dedicate a thread to managing timer intervals and then elevate 
  13503. the priority of that thread. 
  13504.  
  13505.  
  13506. ΓòÉΓòÉΓòÉ 17.1.1. Suspending Threads ΓòÉΓòÉΓòÉ
  13507.  
  13508. An application can use DosSleep to suspend operation of a thread for a 
  13509. specified interval. The system waits the specified number of milliseconds 
  13510. (subject to the round-off error just discussed) before returning control to the 
  13511. application. Because a sleeping application yields execution control to the 
  13512. system, the system can execute other processes or threads while the application 
  13513. sleeps. 
  13514.  
  13515. The following code fragment shows how to suspend the calling thread for one 
  13516. minute: 
  13517.  
  13518.     #define INCL_DOSPROCESS   /* Process and thread values */
  13519.     #include <os2.h>
  13520.     #include <stdio.h>
  13521.  
  13522.     ULONG   TimeInterval;     /* Interval in milliseconds  */
  13523.     APIRET  rc;               /* Return code               */
  13524.  
  13525.     TimeInterval = 60000;
  13526.  
  13527.     rc = DosSleep(TimeInterval);
  13528.  
  13529.     if (rc != 0) {
  13530.         printf("DosSleep error: return code = %ld", rc);
  13531.         return;
  13532.     }
  13533.  
  13534.  
  13535. Suspending a Thread 
  13536.  
  13537. See Suspending the Current Thread for more information on DosSleep. 
  13538.  
  13539.  
  13540. ΓòÉΓòÉΓòÉ 17.1.2. Asynchronous Timers ΓòÉΓòÉΓòÉ
  13541.  
  13542. DosSleep is useful for temporarily suspending a thread but is much less useful 
  13543. for timing. Typically, an application carries out part of its task and then 
  13544. waits an interval. If the execution time varies (as it will if the application 
  13545. runs on different hardware), the overall interval varies. In these situations, 
  13546. asynchronous timers provide greater precision than DosSleep. 
  13547.  
  13548. The OS/2 operating system supports two types of asynchronous timers, 
  13549. single-interval (one-shot) and repeated. DosAsyncTimer starts a single-interval 
  13550. timer. During the timing interval, the application can carry out other tasks. 
  13551. The system posts an event semaphore when the timing interval elapses. The 
  13552. application can reset the semaphore with DosResetEventSem before starting the 
  13553. timer. DosAsyncTimer yields a more accurate timing interval than DosSleep 
  13554. because the interval is independent of the execution time. 
  13555.  
  13556. DosStartTimer starts a repeated timer. The system posts an event semaphore each 
  13557. time the interval expires. The application can reset the semaphore before 
  13558. starting the timer and after each posting. When the application resets the 
  13559. semaphore with DosResetEventSem, it can check the cPosts value to determine how 
  13560. many times the semaphore has been posted. If the semaphore has been posted more 
  13561. than once, the application has missed a timer interval. 
  13562.  
  13563.  
  13564. ΓòÉΓòÉΓòÉ 17.2. Using Timers ΓòÉΓòÉΓòÉ
  13565.  
  13566. Applications frequently need to synchronize the execution of threads, to cause 
  13567. an event to occur after a specified interval, or to cause an event to occur at 
  13568. regular intervals. Timers are typically used to enable an application to pause 
  13569. before processing user input or to carry out a task at a given time. 
  13570.  
  13571. The operating system provides the following timer functions: 
  13572.  
  13573. o DosSleep suspends the execution of the calling thread, enabling other threads 
  13574.   to run while the calling thread sleeps. 
  13575.  
  13576. o DosAsyncTimer starts a single-interval timer. 
  13577.  
  13578. o DosStartTimer starts a repeated-interval timer. 
  13579.  
  13580. o DosStopTimer stops a single-interval or repeated-interval timer. 
  13581.  
  13582. The system also provides two functions, DosGetDateTime and DosSetDateTime, for 
  13583. getting and setting the system date and time. 
  13584.  
  13585. The timers that are started by DosAsyncTimer and DosStartTimer are asynchronous 
  13586. timers; that is, the timers run independently of the calling thread, enabling 
  13587. the calling thread to perform other operations while the timer is running. When 
  13588. an asynchronous timer interval expires, the system notifies the application by 
  13589. posting an event semaphore. 
  13590.  
  13591. Time intervals for DosAsyncTimer, DosStartTimer, and DosSleep are specified in 
  13592. milliseconds; however, it is important to recognize that the actual duration of 
  13593. the specified time interval will be affected by two factors: 
  13594.  
  13595. o First, the system clock keeps track of time in less precise units known as 
  13596.   clock ticks.  On most hardware, clock ticks occur approximately 32 times a 
  13597.   second, so each tick interval lasts approximately 31.25 milliseconds. (To 
  13598.   determine the duration of a clock tick on your computer, call 
  13599.   DosQuerySysInfo, and examine the timer-interval field.) 
  13600.  
  13601.   Because clock ticks are less precise than millisecond values, any time 
  13602.   interval that is specified in milliseconds will essentially be rounded up to 
  13603.   the next clock tick. 
  13604.  
  13605. o Second, because the OS/2 operating system is a priority-based, multitasking 
  13606.   operating system, there is no guarantee that a thread will resume execution 
  13607.   immediately after the timer interval expires. If a higher priority process or 
  13608.   thread is running, or if a hardware interrupt occurs, the timed thread 
  13609.   blocks. (To minimize delays caused by preemptive scheduling, an application 
  13610.   can dedicate a thread to managing time-critical tasks, and then raise that 
  13611.   thread to a higher priority.) 
  13612.  
  13613. These factors usually cause the timer interval to be longer than requested; 
  13614. however, it will generally be within a few clock ticks. 
  13615.  
  13616. Timers for Presentation Manager applications are provided through the message 
  13617. queue. Therefore, a Presentation Manager application will not use the timer 
  13618. functions unless it performs some real-time control task. 
  13619.  
  13620. Note:  In the example code fragments that follow, error checking was left out 
  13621.        to conserve space. Applications should always check the return code that 
  13622.        the functions return. Control Program functions return an APIRET value. 
  13623.        A return code of 0 indicates success. If a non-zero value is returned, 
  13624.        an error occurred. 
  13625.  
  13626.  
  13627. ΓòÉΓòÉΓòÉ 17.2.1. Suspending the Current Thread ΓòÉΓòÉΓòÉ
  13628.  
  13629. An application can suspend a thread by using DosSleep. DosSleep suspends the 
  13630. execution of the calling thread for a specified time interval. 
  13631.  
  13632. DosSleep requires one argument-the amount of time (in milliseconds) to suspend 
  13633. the thread. This value is rounded up to the nearest clock tick. If a time 
  13634. interval of 0 is specified, the thread gives up the remainder of the current 
  13635. time slice, enabling other ready threads of equal or higher priority to run; 
  13636. the calling thread will run again during its next scheduled time slice. If 
  13637. there is no other ready thread of equal or higher priority, DosSleep returns 
  13638. immediately; it does not yield to a thread of lower priority. 
  13639.  
  13640. If there is a round-off error or if other threads in the system have higher 
  13641. priority, a thread might not resume execution immediately after the sleep 
  13642. interval. 
  13643.  
  13644. The following DosSleep call suspends a thread for at least 5 seconds: 
  13645.  
  13646.     DosSleep(5000);
  13647. Note that the specified time interval refers to execution time (accumulated 
  13648. scheduled time slices), not to elapsed real time. Elapsed real time will be 
  13649. longer and will vary, depending on the hardware and on the number and 
  13650. priorities of other threads running in the system. In addition, even though the 
  13651. calling thread is scheduled for execution as soon as the specified time 
  13652. interval has elapsed, its execution could be delayed if a higher priority 
  13653. thread is running or if a hardware interrupt occurs. 
  13654.  
  13655. Because the above factors usually cause the sleep interval to be longer than 
  13656. requested (though generally within a few clock ticks), DosSleep should not be 
  13657. used as a substitute for a real-time clock. 
  13658.  
  13659. Note: 
  13660.  
  13661.  1. Elapsed real time for the asynchronous timers (started by DosAsyncTimer and 
  13662.     DosStartTimer) will be much closer to their specified time intervals 
  13663.     because these timers run independent of the execution of the calling 
  13664.     thread. 
  13665.  
  13666.  2. To ensure optimal performance, do not use DosSleep in a single-thread 
  13667.     Presentation Manager application. (Use WinStartTimer.) 
  13668.  
  13669.  
  13670. ΓòÉΓòÉΓòÉ 17.2.2. Timing a Single Interval ΓòÉΓòÉΓòÉ
  13671.  
  13672. To carry out other tasks while the timer counts an interval, an application can 
  13673. use DosAsyncTimer. This function sets a single-interval timer without stopping 
  13674. the application-the timer runs asynchronously to the calling thread, enabling 
  13675. the thread to perform other operations while it is waiting for the specified 
  13676. time interval to expire. When the interval elapses, the operating system 
  13677. notifies the application of the expiration of the timer by posting an event 
  13678. semaphore. The application resets the semaphore before starting the timer and 
  13679. monitors the semaphore to determine when the time has elapsed. The application 
  13680. can use DosCreateEventSem with the initial state FALSE to create a reset 
  13681. semaphore. For more information on semaphores, see Semaphores. 
  13682.  
  13683. The following code fragment creates an event semaphore and then calls 
  13684. DosAsyncTimer to count an interval while the application performs other tasks: 
  13685.  
  13686.     #define INCL_DOSDATETIME    /* Date/Time and Timer Support */
  13687.     #include<os2.h>
  13688.  
  13689.     HEV hev;
  13690.     HTIMER hTimer;
  13691.  
  13692.     /* First create a private, reset, event semaphore. */
  13693.  
  13694.     DosCreateEventSem((PSZ) NULL, &hev, 0, FALSE);
  13695.  
  13696.     /* Start async (one-shot) timer; post semaphore in 10 seconds.  */
  13697.  
  13698.     DosAsyncTimer(10000,       /* Time in milliseconds (10 sec)     */
  13699.                   (HSEM) &hev, /* Semaphore handle                  */
  13700.                   &hTimer);    /* Timer handle (used to stop timer) */
  13701.  
  13702.         .
  13703.         .    /* Do other processing here, then wait for semaphore.  */
  13704.         .
  13705.  
  13706.     DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
  13707.  
  13708.  
  13709. Using a Single-Interval Timer with an Event Semaphore 
  13710.  
  13711. Before starting the timer, the thread creates the event semaphore with 
  13712. DosCreateEventSem, specifying its initial state as reset. If the semaphore was 
  13713. previously created by the same process, the thread resets it by calling 
  13714. DosResetEventSem. If the semaphore was previously created by another process, 
  13715. then the thread must call DosOpenEventSem to gain access to the semaphore 
  13716. before calling DosResetEventSem. 
  13717.  
  13718. Next, the thread calls DosAsyncTimer, specifying the handle of the event 
  13719. semaphore and the desired time interval. The thread can then perform other 
  13720. tasks. However, in order for the application to be notified of the expiration 
  13721. of the timer, one or more threads in the application must call DosWaitEventSem. 
  13722.  
  13723. When the time interval expires, the system posts the semaphore, and any threads 
  13724. that were blocked on DosWaitEventSem requests can resume their execution. If 
  13725. another time interval is required, the semaphore is reset, and both 
  13726. DosAsyncTimer and DosWaitEventSem are called again. (To time regular repeated 
  13727. intervals, use DosStartTimer.) 
  13728.  
  13729. The timer can be canceled before its time interval expires by calling 
  13730. DosStopTimer. 
  13731.  
  13732.  
  13733. ΓòÉΓòÉΓòÉ 17.2.3. Timing Repeated Intervals ΓòÉΓòÉΓòÉ
  13734.  
  13735. To count an interval repeatedly, an application can use DosStartTimer. This 
  13736. function starts a repeated-interval timer. 
  13737.  
  13738. Unlike DosAsyncTimer, DosStartTimer does not stop after the first interval is 
  13739. counted. The timer runs asynchronously to the calling thread, enabling the 
  13740. thread to perform other operations while it is waiting for the specified time 
  13741. intervals to expire. The system notifies the application of the timer's 
  13742. expirations by posting an event semaphore. 
  13743.  
  13744. The application resets the semaphore before starting the timer and whenever the 
  13745. system posts the semaphore. The application can use the value returned in the 
  13746. post-counting parameter by DosResetEventSem to assure the semaphore was posted 
  13747. only once before it was reset. 
  13748.  
  13749. The following code fragment starts a timer and then waits on and resets the 
  13750. associated event semaphore. Assume that the handle of the targeted event 
  13751. semaphore has been placed into SemHandle. 
  13752.  
  13753.     #define INCL_DOSDATETIME   /* Date and time values */
  13754.     #include <os2.h>
  13755.     #include <stdio.h>
  13756.  
  13757.     ULONG    TimeInterval; /* Interval (milliseconds) */
  13758.     HSEM     SemHandle;    /* Event-semaphore handle  */
  13759.     HTIMER   Handle;       /* Timer handle (returned) */
  13760.     APIRET   rc;           /* Return code             */
  13761.  
  13762.     TimeInterval = 30000;  /* Set the periodic time interval to */
  13763.                            /* elapse every 30 seconds           */
  13764.  
  13765.     rc = DosStartTimer(TimeInterval, SemHandle, &Handle);
  13766.  
  13767.     if (rc != 0) {
  13768.         printf("DosStartTimer error: return code = %ld", rc);
  13769.         return;
  13770.     }
  13771.  
  13772.  
  13773. Using a Repeated-Interval Timer with an Event Semaphore 
  13774.  
  13775. On successful return, Handle will contain the handle of this periodic timer. 
  13776. DosStopTimer can be used later to stop the periodic timer. 
  13777.  
  13778. A repeated timer will continue to count the interval and post the semaphore 
  13779. until the application terminates or the application uses DosStopTimer to stop 
  13780. the timer explicitly. The following code fragment shows how to stop a periodic 
  13781. timer that has been started previously with DosStartTimer: 
  13782.  
  13783.     #define INCL_DOSDATETIME   /* Date and time values */
  13784.     #include <os2.h>
  13785.     #include <stdio.h>
  13786.  
  13787.     HTIMER   Handle;    /* Handle of the timer */
  13788.     APIRET   rc;        /* Return code         */
  13789.  
  13790.     rc = DosStopTimer(Handle);
  13791.  
  13792.     if (rc != 0) {
  13793.         printf("DosStopTimer error: return code = %ld", rc);
  13794.         return;
  13795.     }
  13796.  
  13797.  
  13798. Stopping a Repeated-Interval Timer 
  13799.  
  13800. Before starting the timer, the event semaphore must be reset. If the semaphore 
  13801. does not exist, the thread can create it with DosCreateEventSem, specifying its 
  13802. initial state as reset. If the semaphore was previously created by the same 
  13803. process, the thread resets it by calling DosResetEventSem. If the semaphore was 
  13804. previously created by another process, then the thread calls DosOpenEventSem to 
  13805. gain access to the semaphore before calling DosResetEventSem. 
  13806.  
  13807. Next, the thread calls DosStartTimer, specifying the handle of the event 
  13808. semaphore and the desired time interval. The thread can then perform other 
  13809. tasks. However, in order for the application to be notified of the timer's 
  13810. expirations, one or more threads in the application must call DosWaitEventSem. 
  13811.  
  13812. When the time interval expires, the system posts the semaphore, and any threads 
  13813. that were blocked on DosWaitEventSem requests can resume their execution. Each 
  13814. time the semaphore is posted, it must be reset with DosResetEventSem before the 
  13815. next timer expiration. DosWaitEventSem must also be called to wait for the 
  13816. semaphore to be posted again. 
  13817.  
  13818. In addition to resetting the event semaphore, DosResetEventSem returns the 
  13819. semaphore's post count (the number of times the semaphore has been posted since 
  13820. the last time it was in the set state). An application can use the post count 
  13821. to ensure that it has not missed a timer interval; if the post count is greater 
  13822. than one, the application missed a timer interval. 
  13823.  
  13824.  
  13825. ΓòÉΓòÉΓòÉ 17.3. Summary of Functions Used with Timers ΓòÉΓòÉΓòÉ
  13826.  
  13827. Following are the OS/2 functions used with timers. 
  13828.  
  13829. Timer Functions 
  13830.  
  13831. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  13832. ΓöéFunction                      ΓöéDescription                   Γöé
  13833. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13834. ΓöéDosAsyncTimer                 ΓöéStarts an asynchronous,       Γöé
  13835. Γöé                              Γöésingle-interval timer.        Γöé
  13836. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13837. ΓöéDosSleep                      ΓöéSuspends the current thread   Γöé
  13838. Γöé                              Γöéfor a specified time interval.Γöé
  13839. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13840. ΓöéDosStartTimer                 ΓöéStarts an asynchronous,       Γöé
  13841. Γöé                              Γöérepeated-interval timer.      Γöé
  13842. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  13843. ΓöéDosStopTimer                  ΓöéStops an asynchronous,        Γöé
  13844. Γöé                              Γöésingle-interval or            Γöé
  13845. Γöé                              Γöérepeated-interval timer.      Γöé
  13846. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  13847.