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.

671 lines
13 KiB

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