Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
13 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1996
  6. //
  7. // File: overview.hxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /*++
  11. Overview of printui structure
  12. =============================
  13. Client usage:
  14. -------------
  15. The print user interface is a separate library that can be linked
  16. into either shell32.dll or printui.exe for independent and quick
  17. testing.
  18. To use this library, the user simply loads the dll. In
  19. DllEntryPoint routine, the library is intializes itself.
  20. To create a print queue window, the client calls:
  21. VOID
  22. vQueueCreate(
  23. LPCTSTR pszPrinter,
  24. INT nCmdShow
  25. )
  26. Note that this all does not fail: it occurs asynchronously. If base
  27. initialization fails, then a message box is put up immediately with
  28. an error.
  29. If the printer fails to open for whatever reason (such as unknown
  30. printer), then the window is left open and shows an error message
  31. in both the title and status bar.
  32. Note: this is the only public interface to creating a queue.
  33. Programming goals:
  34. ------------------
  35. There goals in order of priority are:
  36. 1. Correctness (no bugs, robust)
  37. 2. Maintainability (clean architecture, readable, extensible)
  38. 3. Portable (should run on win9x)
  39. 4. Responsive (UI should never hang)
  40. 5. Small working set
  41. 6. Fast
  42. Naming conventions:
  43. -------------------
  44. As a general rule, hungarian notation is used. Also, the nouns
  45. a placed before the verbs (PrinterCreate rather than CreatePrinter).
  46. Class names are prefixed with the following characters:
  47. Type Inheritance
  48. ---- -----------
  49. V - Virtual 0 or 1 (Types|Virtual), 0 or more Mix-ins.
  50. T - Type 0 or 1 (Types|Virtual), 0 or more Mix-ins.
  51. M - Mix-in 0 or more Mix-ins.
  52. Multiple inheritance is allowed, but this structure prevents
  53. cycles from appearing.
  54. Macros:
  55. -------
  56. ALWAYS_VALID - indicates the object is always valid, and creates
  57. an inline bValid( VOID ) function that returns TRUE.
  58. SIGNATURE( '1234' ) - Places a signature in an object. The bytes
  59. are reversed so that a dc displays the name correctly. Also
  60. creates an inline function bSigCheck() that ensures the object
  61. matches the signature.
  62. VAR( Type, name ); - Creates the field variable (prefixed by '_')
  63. and 'get' function (Type name();) that retrieves the variable.
  64. DLINK_BASE( Type, name, linkname ); - Creates the head base pointer
  65. for double-linked list.
  66. DLINK( Type, name ); - Creates a dlink entry and inline functions
  67. to manipulate the link (functions prefixed with "name_.")
  68. REF_LOCK( Type, name ); - Create a reference lock that acquires
  69. and releases a VRef object. The reference count is appropriately
  70. incremented and decremented.
  71. ( Debug macros )
  72. SINGLETHREAD( dwThreadId ); - The first time this is called,
  73. initializes dwThreadId to the current thread. Subsequent
  74. calls assert that the current thread is the same as dwThreadId
  75. (this first one).
  76. Library intialization:
  77. ----------------------
  78. When the dll is loaded, the window classes are registered and the
  79. libraries are initialized.
  80. Queue Creation:
  81. ---------------
  82. When the user calls vQueueCreate the following occurs:
  83. Internal structure notes:
  84. -------------------------
  85. There are three main classes:
  86. TQueue: The highest level queue object
  87. This maintains the listview and user interface elements.
  88. It maintains a reference to a TPrinter.
  89. TPrinter: Single interface to printer objects
  90. This handles retrieving printer data and sending
  91. asynchronous printer commands.
  92. VData: Abstracts client notifications and information retrieval.
  93. There are two types of notifications: notification that
  94. something changed, and actual data. This class presents
  95. a uniform interface to TPrinter, and holds all job information.
  96. Given that virtually everything executes asynchronously, (including
  97. commands), destruction of queues must be handled carefully:
  98. TPrintLib: This is referenced counted, and once all print queues
  99. have been destroyed, this object deletes itself.
  100. Each queue holds a ref count. When all queues are destroyed,
  101. the ref count reaches zero and vRefZeroed() is called.
  102. At this point we tell TThreadM to start shutting down by
  103. calling TThreadM::vDelete.
  104. TQueue: Since this is tied to the user interface, it only lives
  105. while the UI window is open, or there it is processing
  106. a notification (there is a refcount).
  107. It notifies the its TPrinter that the UI is going away, so
  108. that the TPrinter does not notify the queue.
  109. TPrinter: This receives it's notification to delete via vDelete().
  110. It disassociates itself from the TQueue then queues itself
  111. with commands to close then delete.
  112. After all other commands are processed, it deletes the TData
  113. object.
  114. VData: This is simply a data repository, so it does not require
  115. any special shutdown code.
  116. The following classes are used by the print folder to retrieve info
  117. about printers on a server.
  118. TFolder: Analagous to TQueue for print queues. It will have
  119. either (1 TConnectionNotify, 1 TDSServer, 0+ TDSConnection)
  120. or (1 TDSServer). The former case represents the local
  121. print folder where we must watch local printers + connections +
  122. check if any connections are added or deleted. The latter
  123. represents a remote printer folder (we don't need to
  124. watch connections).
  125. VDataSource: A single source of printers.
  126. TDSConnection: derived from VDataSource. Represents a single
  127. printer connection (always enumerates and returns one printer.)
  128. TDSServer: derived from VDataSource. Represents a server, which
  129. may have multiple printers.
  130. TConnectionNotify: Watches the registry to see if printer
  131. connections are added or removed.
  132. Printer States:
  133. The printer state is represented with a by a DWORD--the top
  134. three bits. Each action can modify the bits to transition to
  135. a new state.
  136. EXEC_AWAKE
  137. Print queue was restored (from iconized state), so
  138. notifications should start up again.
  139. EXEC_SLEEP
  140. Print queue minimized; shut down notifications.
  141. ?? Even in the minimized state, it should show whether
  142. the printer is paused. But if notifications are shut
  143. down, how will it update this? We could reduce notification
  144. level just to status, which would cut down on traffic but
  145. still give us Paused informations.
  146. EXEC_ERROR
  147. An error occurred such that the TPrinter should not be
  148. re-opened until the user explicitly hits refresh. This
  149. occurs when the printer name is invalid, or access is
  150. denied.
  151. EXEC_REOPEN
  152. Open printer with maximal access.
  153. From states:
  154. ALL
  155. EXEC_DELAY
  156. GetLastError() must be valid!
  157. Sleep for a while when there's an error. It will decrement
  158. _uFailCount in case it wants to retry a second time before
  159. giving up.
  160. This will also create an event in case the user tries to
  161. refresh while it's sleeping.
  162. From states:
  163. ALL
  164. EXEC_CLOSE
  165. Closes printer object.
  166. From states:
  167. ALL
  168. EXEC_REQUESTEXT
  169. Request that the printer shut down.
  170. From states:
  171. ALL
  172. EXEC_NOTIFYSTART
  173. Begin the notification process--calls VData.svNotifyStart.
  174. From states:
  175. NOTIFYEND, EXEC_REOPEN (printer must be valid)
  176. EXEC_NOTIFYEND
  177. Ends the notification--calls VData.svNotifyEnd. When the
  178. user minimizes the printer, we will close the notification
  179. so that we won't eat network bandwidth when no one's looking.
  180. From states:
  181. NOTIFYSTART, REFRESH, COMMAND
  182. EXEC_REFRESH
  183. Refresh the object.
  184. From states:
  185. COMMAND, NOTIFYSTART
  186. EXEC_REFRESH_PRINTER
  187. EXEC_REFRESH_JOBS
  188. Extra state bits used for TDataRefresh only.
  189. EXEC_COMMAND
  190. Execute a command.
  191. From states:
  192. Columns vs. Indicies
  193. --------------------
  194. A column is the UI ListView column, while an index is an index
  195. into the TData information.
  196. Column: Index:
  197. DOCUMENT DOCUMENT
  198. STATUS_STRING STATUS_STRING
  199. USER_NAME USER_NAME
  200. STATUS <- specific to Index only.
  201. Sequence of notifications
  202. -------------------------
  203. The data notifications are abstracted into the VData object.
  204. Full refresh
  205. In the downlevel case, no information is sent back with
  206. a notification, so the entire queue must be refreshed.
  207. Partial refresh
  208. For uplevel, data is sent back, and single jobs are changed.
  209. The following describes how a notification is processed. There
  210. are two main issues that result this complex system: first,
  211. the data must be processed in the UI thread so that we don't
  212. deal with dangling data. Second, we want to keep the TPrinter,
  213. TQueue, TData and TData* classes as separate as possible.
  214. 1. Notification system signals event, indicating something
  215. changed and we must be updated.
  216. 2. Notify thread (there is a single thread for all printers
  217. (unless there are > 63 queues, in which case multiple
  218. threads are used)) picks up the changed event and
  219. MNotifyWork::vProcessNotifyWork is called. This must
  220. process the request very quickly, since other printers
  221. use this thread too.
  222. a. For TDataRefresh, this routine adds a refresh job
  223. that will be executed in a separate thread.
  224. b. For TDataNotify, FindNextPrinterChangeNotification
  225. is called to retrieve the update. Since FFPCN does
  226. not hit the network, it executes quickly.
  227. 3. If there is data available from the notification, the
  228. thread calls Printer.vRequestBlockProcess which cals
  229. the Queue object with the request. The data block is
  230. totally encapsulated in the hBlock.
  231. 4. The Queue object posts a message to the queue, allows the
  232. message to be processed synchronously in the UI thread.
  233. All data is accessed from the UI thread. The message
  234. indicates whether state (which jobs are selected, which
  235. has focus) should be saved.
  236. 5. When the message is received by the UI thread, it is
  237. sent to TQueue.
  238. a. If the state must be preserved the JobIds are saved.
  239. b. The TData* is sent the Block which must be
  240. processed.
  241. 1. If a job must be modified, it updates the data then
  242. notifies the Queue that the job must be repainted.
  243. 2. If a new job has come in, it is added to the data
  244. structure, then the Queue is notified that a job
  245. must be inserted into the list view.
  246. 3. If a job is deleted, the Queue is notified before the
  247. item is deleted, since the list view may reference
  248. the job data.
  249. c. If necessary, the state is restored (generally done
  250. if the list view was reconstructed).
  251. 6. The data block is freed.
  252. Singleton class
  253. -------------------------
  254. A Sington class is a class which can have only one instance during the life of the
  255. program, however, it may have multiple referenced to this class. TPrinterDriverSetup is
  256. singleton class. This class is used to allow acccess to the DriverSetup information.
  257. The DriverSetup information is expensive to create and does not change during the life of
  258. the program. The TPrinterDriverSetup::bInstance function is a static function which is used
  259. by users of this class to obtain a reference to it. bInstance takes one argument the address
  260. where to return a reference to the singlton class and returns a boolean if a valid instance is
  261. returned. TPrinterDriverSetup::vDelete() is used to release an instance of the singleton class.
  262. There should be a matching number of bInstance() and vDelete() calls, to insure proper cleanup
  263. of the singleton class.
  264. --*/