Leaked source code of windows server 2003
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.

679 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. All Rights Reserved
  4. Module Name:
  5. util.c
  6. --*/
  7. #include "precomp.h"
  8. // @@BEGIN_DDKSPLIT
  9. #ifdef INTERNAL
  10. MODULE_DEBUG_INIT( DBG_WARN|DBG_ERROR, DBG_ERROR );
  11. #endif
  12. // @@END_DDKSPLIT
  13. CRITICAL_SECTION pjlMonSection = {0,0,0,0,0,0};
  14. PINIPORT pIniFirstPort = NULL;
  15. DWORD dwReadThreadErrorTimeout;
  16. DWORD dwReadThreadEOJTimeout;
  17. DWORD dwReadThreadIdleTimeoutOther;
  18. TCHAR cszEOJTimeout[] = TEXT("EOJTimeout");
  19. VOID
  20. SplInSem(
  21. VOID
  22. )
  23. {
  24. if ( pjlMonSection.OwningThread != (HANDLE) UIntToPtr(GetCurrentThreadId()) ) {
  25. DBGMSG(DBG_ERROR, ("Pjlmon: Not in spooler semaphore !!\n"));
  26. }
  27. }
  28. VOID
  29. SplOutSem(
  30. VOID
  31. )
  32. {
  33. if ( pjlMonSection.OwningThread == (HANDLE) UIntToPtr(GetCurrentThreadId()) ) {
  34. DBGMSG(DBG_ERROR, ("Pjlmon: Inside spooler semaphore !!\n"));
  35. }
  36. }
  37. VOID
  38. EnterSplSem(
  39. VOID
  40. )
  41. {
  42. EnterCriticalSection(&pjlMonSection);
  43. }
  44. VOID
  45. LeaveSplSem(
  46. VOID
  47. )
  48. {
  49. SplInSem();
  50. LeaveCriticalSection(&pjlMonSection);
  51. }
  52. VOID
  53. UpdateRegistryValue(
  54. IN HKEY hKey,
  55. IN LPCTSTR cszValueName,
  56. OUT LPDWORD pdwValue,
  57. IN DWORD dwDefault,
  58. IN OUT LPDWORD pdwLastError
  59. )
  60. /*++
  61. Routine Description:
  62. Gets value assoicated with give value name from the registry. If value name
  63. is not found default value is written to registry.
  64. On error last error value is set to pdwLastError.
  65. Arguments:
  66. hKey : Registry key under which value should be searched
  67. cszValueName : Value name to search in the registry
  68. pdwValue : On return will have the value
  69. dwDefault : If value name not found in the registry set to this value
  70. pdwLastError : On error set last error to this
  71. Return Value:
  72. None
  73. --*/
  74. {
  75. DWORD dwSize = sizeof(*pdwValue);
  76. if ( *pdwLastError != ERROR_SUCCESS )
  77. return;
  78. if ( ERROR_SUCCESS != RegQueryValueEx(hKey,
  79. cszValueName,
  80. NULL,
  81. NULL,
  82. (LPBYTE)pdwValue,
  83. &dwSize) ) {
  84. *pdwValue = dwDefault;
  85. *pdwLastError = RegSetValueEx(hKey,
  86. cszValueName,
  87. 0,
  88. REG_DWORD,
  89. (LPBYTE)pdwValue,
  90. sizeof(*pdwValue));
  91. }
  92. }
  93. DWORD
  94. UpdateTimeoutsFromRegistry(
  95. IN LPTSTR pszRegistryRoot
  96. )
  97. /*++
  98. Routine Description:
  99. Get the timeout values from the registry, or initialize registry with
  100. default values if entries are not found.
  101. Users/apps can change the registry to change the behavior.
  102. Arguments:
  103. pszRegistryRoot : Registry root to be used by this dll
  104. Return Value:
  105. ERROR_SUCCESS on success, else last error value
  106. --*/
  107. {
  108. HKEY hKey;
  109. DWORD dwLastError = ERROR_SUCCESS;
  110. dwLastError = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  111. pszRegistryRoot,
  112. 0,
  113. NULL,
  114. 0,
  115. KEY_READ | KEY_WRITE,
  116. NULL,
  117. &hKey,
  118. NULL);
  119. if ( dwLastError != ERROR_SUCCESS ) {
  120. goto Cleanup;
  121. }
  122. UpdateRegistryValue(hKey,
  123. cszEOJTimeout,
  124. &dwReadThreadEOJTimeout,
  125. READ_THREAD_EOJ_TIMEOUT,
  126. &dwLastError);
  127. dwReadThreadErrorTimeout = READ_THREAD_ERROR_WAITTIME;
  128. dwReadThreadIdleTimeoutOther = READ_THREAD_IDLE_WAITTIME;
  129. RegCloseKey(hKey);
  130. Cleanup:
  131. if ( dwLastError != ERROR_SUCCESS ) {
  132. DBGMSG(DBG_ERROR,
  133. ("UpdateTimeoutsFromRegistry: Failed with %d", dwLastError));
  134. }
  135. return dwLastError;
  136. }
  137. PINIPORT
  138. FindIniPort(
  139. IN LPTSTR pszName
  140. )
  141. {
  142. PINIPORT pIniPort = pIniFirstPort;
  143. if ( !pszName || !*pszName )
  144. return NULL;
  145. SplInSem();
  146. while ( pIniPort && lstrcmpi(pszName, pIniPort->pszPortName))
  147. pIniPort = pIniPort->pNext;
  148. return pIniPort;
  149. }
  150. PINIPORT
  151. CreatePortEntry(
  152. IN LPTSTR pszPortName
  153. )
  154. /*++
  155. Routine Description:
  156. Creates a IniPort entry for a port. Needs to be called inside monitor
  157. critical section.
  158. Arguments:
  159. pszPortName : Name of the port
  160. Return Value:
  161. On success pointer to the IniPort stucture.
  162. On failure NULL
  163. --*/
  164. {
  165. PINIPORT pIniPort = NULL;
  166. HANDLE DoneWriting = NULL;
  167. HANDLE DoneReading = NULL;
  168. HANDLE WakeUp = NULL;
  169. LPWSTR pszString = NULL;
  170. SplInSem();
  171. if (!(DoneWriting = CreateEvent(NULL, FALSE, TRUE, NULL)))
  172. {
  173. goto Fail;
  174. }
  175. if (!(WakeUp = CreateEvent(NULL, FALSE, FALSE, NULL)))
  176. {
  177. goto Fail;
  178. }
  179. //
  180. // manual-reset event, initially signal state
  181. //
  182. if (!(DoneReading = CreateEvent(NULL, TRUE, TRUE, NULL)))
  183. {
  184. goto Fail;
  185. }
  186. if (!(pIniPort = (PINIPORT) AllocSplMem(sizeof(*pIniPort))))
  187. {
  188. goto Fail;
  189. }
  190. if (!(pszString = AllocSplStr(pszPortName)))
  191. {
  192. goto Fail;
  193. }
  194. pIniPort->pNext = NULL;
  195. pIniPort->signature = PJ_SIGNATURE;
  196. pIniPort->DoneWriting = DoneWriting;
  197. pIniPort->DoneReading = DoneReading;
  198. pIniPort->WakeUp = WakeUp;
  199. pIniPort->hUstatusThread= NULL;
  200. pIniPort->pszPortName = pszString;
  201. pIniPort->pNext = pIniFirstPort;
  202. pIniFirstPort = pIniPort;
  203. return pIniPort;
  204. Fail:
  205. if (DoneWriting)
  206. {
  207. CloseHandle (DoneWriting);
  208. }
  209. if (DoneReading)
  210. {
  211. CloseHandle (DoneReading);
  212. }
  213. if (WakeUp)
  214. {
  215. CloseHandle (WakeUp);
  216. }
  217. FreeSplMem (pszString);
  218. FreeSplMem (pIniPort);
  219. return NULL;
  220. }
  221. VOID
  222. DeletePortEntry(
  223. IN PINIPORT pIniPort
  224. )
  225. /*++
  226. Routine Description:
  227. Deletes a port entry. Needs to be called inside monitor critical section
  228. Arguments:
  229. pIniPort : Pointer to the IniPort structure to be deleted
  230. Return Value:
  231. --*/
  232. {
  233. SplInSem();
  234. if ( pIniPort == pIniFirstPort ) {
  235. pIniFirstPort = pIniPort->pNext;
  236. } else {
  237. PINIPORT pPort;
  238. pPort = pIniFirstPort;
  239. while ( pPort && pPort->pNext != pIniPort )
  240. pPort = pPort->pNext;
  241. if (pPort) {
  242. pPort->pNext = pIniPort->pNext;
  243. } else {
  244. DBGMSG(DBG_ERROR, ("pjlmon: DeletePortEntry port not found\n"));
  245. return;
  246. }
  247. }
  248. if (pIniPort-> DoneWriting)
  249. {
  250. CloseHandle(pIniPort->DoneWriting);
  251. pIniPort->DoneWriting = NULL;
  252. }
  253. if (pIniPort-> DoneReading)
  254. {
  255. CloseHandle(pIniPort->DoneReading);
  256. pIniPort->DoneReading = NULL;
  257. }
  258. if (pIniPort-> WakeUp)
  259. {
  260. CloseHandle(pIniPort->WakeUp);
  261. pIniPort->WakeUp = NULL;
  262. }
  263. if (pIniPort-> hUstatusThread)
  264. {
  265. CloseHandle (pIniPort-> hUstatusThread);
  266. pIniPort->hUstatusThread = NULL;
  267. }
  268. FreeIniJobs(pIniPort);
  269. FreeSplStr(pIniPort->pszPortName);
  270. pIniPort->pszPortName = NULL;
  271. FreeSplMem(pIniPort);
  272. return;
  273. }
  274. VOID
  275. FreeIniJob(
  276. IN OUT PINIJOB pIniJob
  277. )
  278. /*++
  279. Routine Description:
  280. Deletes a job entry.
  281. Arguments:
  282. pIniJob : Pointer to the IniJob structure to be deleted
  283. Return Value:
  284. None
  285. --*/
  286. {
  287. SPLASSERT(pIniJob);
  288. if ( pIniJob->hPrinter )
  289. ClosePrinter(pIniJob->hPrinter);
  290. FreeSplMem(pIniJob);
  291. }
  292. VOID
  293. FreeIniJobs(
  294. PINIPORT pIniPort
  295. )
  296. /*++
  297. Routine Description:
  298. Free all the InJob structures assigned to this port
  299. Arguments:
  300. pIniPort : IniPort for the port for which all jobs need to be freed
  301. --*/
  302. {
  303. PINIJOB pIniJob, pIniNextJob;
  304. EnterSplSem();
  305. pIniJob = pIniPort->pIniJob;
  306. while ( pIniJob ) {
  307. pIniNextJob = pIniJob->pNext;
  308. FreeIniJob(pIniJob);
  309. pIniJob = pIniNextJob;
  310. }
  311. pIniPort->pIniJob = NULL;
  312. LeaveSplSem();
  313. }
  314. VOID
  315. SendLastPageEjectedForIniJob(
  316. PINIPORT pIniPort,
  317. PINIJOB pIniJob
  318. )
  319. {
  320. SplInSem();
  321. if ( !SetJob(pIniJob->hPrinter, pIniJob->JobId, 0,
  322. NULL, JOB_CONTROL_LAST_PAGE_EJECTED) ) {
  323. DBGMSG(DBG_WARNING,
  324. ("SetJob failed with last error %d\n", GetLastError()));
  325. }
  326. }
  327. PINIJOB
  328. FindIniJobFromJobId(
  329. PINIPORT pIniPort,
  330. DWORD dwJobId,
  331. PINIJOB *ppPrevIniJob
  332. )
  333. {
  334. PINIJOB pCur, pPre, pIniJob;
  335. SplInSem();
  336. //
  337. // If JOB_RESTART is given there will be multiple jobs with same id
  338. // we need to find the last entry with given id in the list
  339. //
  340. for ( pCur = pIniPort->pIniJob, pPre = pIniJob = *ppPrevIniJob = NULL ;
  341. pCur ;
  342. pPre = pCur, pCur = pCur->pNext ) {
  343. if ( pCur->JobId == dwJobId ) {
  344. *ppPrevIniJob = pPre;
  345. pIniJob = pCur;
  346. }
  347. }
  348. return pIniJob;
  349. }
  350. PINIJOB
  351. FindFirstIniJobTimedOut(
  352. PINIPORT pIniPort,
  353. DWORD dwTime,
  354. PINIJOB *ppPrevIniJob
  355. )
  356. {
  357. PINIJOB pIniJob = pIniPort->pIniJob;
  358. SplInSem();
  359. *ppPrevIniJob = NULL;
  360. //
  361. // Look for a job not in STARTDOC and timedout
  362. //
  363. while ( pIniJob &&
  364. ( (pIniJob->status & PP_INSTARTDOC) ||
  365. pIniJob->TimeoutCount > dwTime ) ) {
  366. *ppPrevIniJob = pIniJob;
  367. pIniJob = pIniJob->pNext;
  368. }
  369. if ( !pIniJob )
  370. *ppPrevIniJob = NULL;
  371. return pIniJob;
  372. }
  373. VOID
  374. SendJobLastPageEjected(
  375. PINIPORT pIniPort,
  376. DWORD dwValue,
  377. BOOL bTime
  378. )
  379. /*++
  380. Routine Description:
  381. Send LastPageEjected notification for 1 or more jobs to spooler
  382. Arguments:
  383. pIniPort : IniPort for the port for which all jobs need to be freed
  384. dwValue : if bTime is TRUE send EOJ to any jobs rcvd before dwValue
  385. else dwValue is JobId -- ALL_JOBS is for all jobs
  386. bTime : Tells how to interpret dwValue
  387. --*/
  388. {
  389. PINIJOB pIniJob;
  390. EnterSplSem();
  391. //
  392. // JobId == ALL_JOBS is a special case where we want to send LastPage
  393. // ejected for all jobs pending
  394. //
  395. if ( !bTime && dwValue == ALL_JOBS ) {
  396. pIniJob = pIniPort->pIniJob;
  397. pIniPort->pIniJob = NULL;
  398. while ( pIniJob ) {
  399. PINIJOB pTempJob = pIniJob;
  400. SendLastPageEjectedForIniJob(pIniPort, pIniJob);
  401. pIniJob = pIniJob->pNext;
  402. FreeIniJob(pTempJob);
  403. }
  404. } else {
  405. PINIJOB pPrevIniJob = NULL;
  406. pIniJob = pIniPort->pIniJob;
  407. //
  408. // If bTime we want to send LastPageEjected for all jobs timedout
  409. //
  410. if ( bTime ) {
  411. pIniJob = FindFirstIniJobTimedOut(pIniPort, dwValue, &pPrevIniJob);
  412. } else {
  413. pIniJob = FindIniJobFromJobId(pIniPort, dwValue, &pPrevIniJob);
  414. }
  415. if ( pIniJob ) {
  416. //
  417. // Send notifications for any previous jobs too
  418. //
  419. if ( pIniPort->pIniJob == pIniJob )
  420. pIniPort->pIniJob = NULL;
  421. else
  422. pPrevIniJob->pNext = NULL;
  423. do {
  424. SendLastPageEjectedForIniJob(pIniPort, pIniJob);
  425. pPrevIniJob = pIniJob;
  426. pIniJob = pIniJob->pNext;
  427. FreeIniJob(pPrevIniJob);
  428. } while ( pIniJob );
  429. }
  430. }
  431. LeaveSplSem();
  432. }
  433. // -----------------------------------------------------------------------
  434. //
  435. // String helper function to remove crt dependency
  436. //
  437. // -----------------------------------------------------------------------
  438. LPSTR
  439. mystrchr(
  440. LPSTR cs,
  441. char c
  442. )
  443. {
  444. while (*cs != 0)
  445. {
  446. if (IsDBCSLeadByte(*cs))
  447. cs++;
  448. else
  449. if (*cs == c)
  450. return cs;
  451. cs++;
  452. }
  453. // fail to find c in cs
  454. return NULL;
  455. }
  456. int
  457. mystrncmp(
  458. LPSTR cs,
  459. LPSTR ct,
  460. int n
  461. )
  462. {
  463. char ret = 0;
  464. while (n--)
  465. {
  466. ret = *cs - *ct;
  467. if (ret)
  468. break;
  469. cs++;
  470. ct++;
  471. }
  472. return (int)ret;
  473. }
  474. // @@BEGIN_DDKSPLIT
  475. #ifndef INTERNAL
  476. // @@END_DDKSPLIT
  477. LPWSTR
  478. AllocSplStr(
  479. LPWSTR pStr
  480. )
  481. /*++
  482. Routine Description:
  483. This function will allocate enough local memory to store the specified
  484. string, and copy that string to the allocated memory
  485. Arguments:
  486. pStr - Pointer to the string that needs to be allocated and stored
  487. Return Value:
  488. NON-NULL - A pointer to the allocated memory containing the string
  489. FALSE/NULL - The operation failed. Extended error status is available
  490. using GetLastError.
  491. --*/
  492. {
  493. LPWSTR pMem;
  494. DWORD cbStr;
  495. if (!pStr) {
  496. return NULL;
  497. }
  498. cbStr = wcslen(pStr)*sizeof(WCHAR) + sizeof(WCHAR);
  499. if (pMem = AllocSplMem( cbStr )) {
  500. CopyMemory( pMem, pStr, cbStr );
  501. }
  502. return pMem;
  503. }
  504. LPVOID
  505. AllocSplMem(
  506. DWORD cbAlloc
  507. )
  508. {
  509. PVOID pvMemory;
  510. pvMemory = GlobalAlloc(GMEM_FIXED, cbAlloc);
  511. if( pvMemory ){
  512. ZeroMemory( pvMemory, cbAlloc );
  513. }
  514. return pvMemory;
  515. }
  516. // @@BEGIN_DDKSPLIT
  517. #endif
  518. // @@END_DDKSPLIT