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.

535 lines
14 KiB

  1. /****************************************************************************
  2. *
  3. * (C) COPYRIGHT 2000, MICROSOFT CORP.
  4. *
  5. * FILE: wiaudbg.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * DATE: 11/21/2000
  10. *
  11. * AUTHOR:
  12. *
  13. * DESCRIPTION:
  14. * Implementation of debugging functions.
  15. *
  16. *****************************************************************************/
  17. #include "pch.h"
  18. //#include "cplusinc.h"
  19. #include "stdlib.h"
  20. #include "stdio.h"
  21. #include <sddl.h>
  22. // debug log is saved to this file
  23. #define WIAUDBG_FILE_NAME "%userprofile%\\wiadebug.log"
  24. // registry key location
  25. #define WIAUDBG_FLAGS_REGKEY "System\\CurrentControlSet\\Control\\StillImage\\Debug"
  26. // registry DWORD value name
  27. #define WIAUDBG_FLAGS_REGVAL "DebugFlags"
  28. // registry DWORD for max log file size
  29. #define WIAUDBG_REGVAL_FILE_SIZE_LIMIT "DebugFileSizeLimit"
  30. #define WIAUDBG_FILE_SIZE_LIMIT (512 * 1024) // bytes
  31. // Prefix for all messages
  32. const CHAR PREFIX_WIA[] = "WIA: ";
  33. // if we fail to acquire mutex within this time, shutdown tracing
  34. const INT WIAUDBG_DEBUG_TIMEOUT = 10000;
  35. // globals
  36. DWORD g_dwDebugFlags = WIAUDBG_DEFAULT_FLAGS;
  37. HANDLE g_hDebugFile = INVALID_HANDLE_VALUE;
  38. DWORD g_dwDebugFileSizeLimit = WIAUDBG_FILE_SIZE_LIMIT;
  39. BOOL g_bDebugInited = FALSE;
  40. static CHAR g_szDebugFileName[MAX_PATH] = "";
  41. static CHAR g_szModuleName[MAX_PATH] = "";
  42. static HANDLE g_hDebugFileMutex = NULL;
  43. static BOOL g_bInited = FALSE;
  44. static BOOL g_bBannerPrinted = FALSE;
  45. #undef TRACE
  46. #ifdef DEBUG
  47. #define TRACE(x) WiauInternalTrace x
  48. #else
  49. #define TRACE(x)
  50. #endif
  51. ////////////////////////////////////////////////
  52. // WiauInternalTrace
  53. //
  54. // Internal tracing for problems in DebugWrite
  55. //
  56. static void WiauInternalTrace(LPCSTR fmt, ...)
  57. {
  58. char buffer[1024] = {0};
  59. size_t len = 0;
  60. va_list marker;
  61. va_start(marker, fmt);
  62. _vsnprintf(buffer, sizeof(buffer) - 2, fmt, marker);
  63. len = strlen(buffer);
  64. if ((len > 0) && (len < sizeof(buffer) - 1))
  65. {
  66. // make sure the line has terminating "\n"
  67. if(buffer[len - 1] != '\n') {
  68. buffer[len++] = '\n';
  69. buffer[len] = '\0';
  70. }
  71. OutputDebugStringA(buffer);
  72. }
  73. va_end(marker);
  74. }
  75. ////////////////////////////////////////////////
  76. // WiauCreateLogFileMutex
  77. //
  78. // Create logfile mutex with appropriate DACL
  79. //
  80. BOOL WiauCreateLogFileMutex(void)
  81. {
  82. #undef CHECK
  83. #define CHECK(x) if(!(x)) { \
  84. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  85. goto Cleanup; }
  86. #undef CHECK2
  87. #define CHECK2(x, y) if(!(x)) { \
  88. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  89. TRACE(y); goto Cleanup; }
  90. const TCHAR *COREDBG_OBJECT_DACLS= TEXT("D:(A;OICI;GA;;;BA)") // Admin
  91. TEXT( "(A;OICI;GA;;;LS)") // Local Service
  92. TEXT( "(A;OICI;GA;;;AU)"); // Authenticated Users.
  93. SECURITY_ATTRIBUTES SA = {0};
  94. BOOL bSuccess = FALSE;
  95. SA.nLength = sizeof(SECURITY_ATTRIBUTES);
  96. SA.bInheritHandle = FALSE;
  97. SA.lpSecurityDescriptor = NULL;
  98. if (ConvertStringSecurityDescriptorToSecurityDescriptor(
  99. COREDBG_OBJECT_DACLS,
  100. SDDL_REVISION_1,
  101. &(SA.lpSecurityDescriptor),
  102. NULL))
  103. {
  104. CHECK((g_hDebugFileMutex = CreateMutexA(&SA, FALSE, "Global\\WiaDebugFileMut")) != NULL);
  105. bSuccess = TRUE;
  106. }
  107. Cleanup:
  108. if (SA.lpSecurityDescriptor)
  109. {
  110. LocalFree(SA.lpSecurityDescriptor);
  111. }
  112. return bSuccess;
  113. }
  114. ////////////////////////////////////////////////
  115. // DebugWrite
  116. //
  117. // Writes specified number of bytes to a debug
  118. // file, creating it if needed. Thread-safe.
  119. // Registers any failure and from that point returns
  120. // immediately.
  121. //
  122. static void
  123. DebugWrite(LPCSTR buffer, DWORD n)
  124. {
  125. #undef CHECK
  126. #define CHECK(x) if(!(x)) { \
  127. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  128. bCatastrophicFailure = TRUE; goto Cleanup; }
  129. #undef CHECK2
  130. #define CHECK2(x, y) if(!(x)) { \
  131. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  132. TRACE(y); bCatastrophicFailure = TRUE; goto Cleanup; }
  133. DWORD cbWritten;
  134. DWORD dwWaitResult;
  135. LARGE_INTEGER newPos = { 0, 0 };
  136. static BOOL bCatastrophicFailure = FALSE;
  137. BOOL bMutexAcquired = FALSE;
  138. // if something is broken, return immediately
  139. if(bCatastrophicFailure) return;
  140. // make sure we have file mutex
  141. if(!g_hDebugFileMutex)
  142. {
  143. CHECK(WiauCreateLogFileMutex());
  144. }
  145. // acquire mutex
  146. dwWaitResult = WaitForSingleObject(g_hDebugFileMutex, WIAUDBG_DEBUG_TIMEOUT);
  147. // if we failed to acquire mutex within the specified timeout,
  148. // shutdown tracing (on free builds users will not know this)
  149. CHECK(dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED);
  150. bMutexAcquired = TRUE;
  151. // make sure we have open file
  152. if(g_hDebugFile == INVALID_HANDLE_VALUE)
  153. {
  154. // attempt to open file
  155. CHECK(ExpandEnvironmentStringsA(WIAUDBG_FILE_NAME, g_szDebugFileName, MAX_PATH));
  156. g_hDebugFile = CreateFileA(g_szDebugFileName, GENERIC_WRITE,
  157. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  158. CHECK2(g_hDebugFile != INVALID_HANDLE_VALUE,
  159. ("g_szDebugFileName = '%s'", g_szDebugFileName));
  160. }
  161. // seek to the end of file
  162. CHECK(SetFilePointerEx(g_hDebugFile, newPos, &newPos, SEEK_END));
  163. // check the file size
  164. if(newPos.HighPart != 0 || newPos.LowPart > g_dwDebugFileSizeLimit)
  165. {
  166. static CHAR LogFullMessage[128];
  167. TRACE(("Reached log file maximum size of %d", g_dwDebugFileSizeLimit));
  168. sprintf(LogFullMessage, "Log file reached maximum size of %d, logging stopped.", g_dwDebugFileSizeLimit);
  169. CHECK2(WriteFile(g_hDebugFile, LogFullMessage, strlen(LogFullMessage), &cbWritten, NULL), ("%d", cbWritten));
  170. bCatastrophicFailure = TRUE;
  171. }
  172. // write data
  173. CHECK2(WriteFile(g_hDebugFile, buffer, n, &cbWritten, NULL),
  174. ("%d %d", cbWritten, n));
  175. // make sure we write to the disk now.
  176. FlushFileBuffers(g_hDebugFile);
  177. CHECK2(cbWritten == n, ("%d %d", n, cbWritten))
  178. Cleanup:
  179. if(bMutexAcquired) ReleaseMutex(g_hDebugFileMutex);
  180. return;
  181. }
  182. ////////////////////////////////////////////////
  183. // PrintBanner
  184. //
  185. // Since we append to the log file, we need a
  186. // seperator of some sort so we know when a
  187. // new execution has started.
  188. //
  189. void PrintBanner(void)
  190. {
  191. char buffer[1024] = {0};
  192. size_t len = 0;
  193. SYSTEMTIME SysTime;
  194. GetLocalTime(&SysTime);
  195. if (g_dwDebugFlags)
  196. {
  197. _snprintf(buffer,
  198. sizeof(buffer) - 1,
  199. "====================Start '%s' Debug - Time: %d/%02d/%02d %02d:%02d:%02d:%02d\\r\\n====================",
  200. g_szModuleName,
  201. SysTime.wYear,
  202. SysTime.wMonth,
  203. SysTime.wDay,
  204. SysTime.wHour,
  205. SysTime.wMinute,
  206. SysTime.wSecond,
  207. SysTime.wMilliseconds);
  208. buffer[sizeof(buffer) - 1] = '\0';
  209. }
  210. len = strlen(buffer);
  211. if(len > 0)
  212. {
  213. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_FILE))
  214. {
  215. DebugWrite(buffer, len);
  216. }
  217. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_DEBUGGER))
  218. {
  219. OutputDebugStringA(buffer);
  220. }
  221. }
  222. return;
  223. }
  224. ////////////////////////////////////////////////
  225. // wiauDbgHelper
  226. //
  227. // Formats message and writes it into log file
  228. // and/or debugger;
  229. //
  230. void wiauDbgHelper(LPCSTR prefix,
  231. LPCSTR fname,
  232. LPCSTR fmt,
  233. va_list marker)
  234. {
  235. char buffer[1024] = {0};
  236. size_t len = 0;
  237. if(!g_bDebugInited)
  238. {
  239. wiauDbgInit(NULL);
  240. }
  241. //
  242. // The first time we ever print a debug statement, lets
  243. // output a seperator line since when we output to file
  244. // we append, this way we can seperate different execution
  245. // sessions.
  246. //
  247. if (!g_bBannerPrinted)
  248. {
  249. PrintBanner();
  250. g_bBannerPrinted = TRUE;
  251. }
  252. if (g_dwDebugFlags & WIAUDBG_PRINT_TIME)
  253. {
  254. SYSTEMTIME MsgTime;
  255. GetLocalTime(&MsgTime);
  256. _snprintf(buffer,
  257. sizeof(buffer) - 1,
  258. "%s%s[%02d:%02d:%02d.%03d] %s: ",
  259. PREFIX_WIA,
  260. prefix,
  261. MsgTime.wHour,
  262. MsgTime.wMinute,
  263. MsgTime.wSecond,
  264. MsgTime.wMilliseconds,
  265. fname);
  266. buffer[sizeof(buffer) - 1] = '\0';
  267. }
  268. else
  269. {
  270. _snprintf(buffer,
  271. sizeof(buffer) - 1,
  272. "%s%s%s: ",
  273. PREFIX_WIA,
  274. prefix,
  275. fname);
  276. buffer[sizeof(buffer) - 1] = '\0';
  277. }
  278. len = strlen(buffer);
  279. if (len < sizeof(buffer) - 2)
  280. {
  281. _vsnprintf(buffer + len,
  282. sizeof(buffer) - len - 2,
  283. fmt,
  284. marker);
  285. buffer[sizeof(buffer) - 1] = '\0';
  286. }
  287. len = strlen(buffer);
  288. if ((len > 0) && (len <= sizeof(buffer)))
  289. {
  290. if (len > sizeof(buffer) - 2)
  291. {
  292. len = sizeof(buffer) - 2;
  293. }
  294. // make sure the line has terminating "\n"
  295. if (buffer[len - 1] != '\n')
  296. {
  297. buffer[len++] = '\r';
  298. buffer[len++] = '\n';
  299. buffer[len] = '\0';
  300. }
  301. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_FILE))
  302. {
  303. DebugWrite(buffer, len);
  304. }
  305. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_DEBUGGER))
  306. {
  307. OutputDebugStringA(buffer);
  308. }
  309. }
  310. }
  311. ////////////////////////////////////////////////
  312. // wiauDbgHelper2
  313. //
  314. // Takes printf style arguments and calls wiauDbgHelper
  315. //
  316. void wiauDbgHelper2(LPCSTR prefix,
  317. LPCSTR fname,
  318. LPCSTR fmt,
  319. ...)
  320. {
  321. va_list marker;
  322. va_start(marker, fmt);
  323. wiauDbgHelper(prefix, fname, fmt, marker);
  324. va_end(marker);
  325. }
  326. ////////////////////////////////////////////////
  327. // GetRegDWORD
  328. //
  329. // Attempts to get a DWORD from the specified
  330. // location. If bSetIfNotExist is set, it
  331. // writes the registry setting to the current
  332. // value in pdwValue.
  333. //
  334. LRESULT GetRegDWORD(HKEY hKey,
  335. const CHAR *pszRegValName,
  336. DWORD *pdwValue,
  337. BOOL bSetIfNotExist)
  338. {
  339. LRESULT lResult = ERROR_SUCCESS;
  340. DWORD dwSize = 0;
  341. DWORD dwType = REG_DWORD;
  342. if ((hKey == NULL) ||
  343. (pszRegValName == NULL) ||
  344. (pdwValue == NULL))
  345. {
  346. return ERROR_INVALID_HANDLE;
  347. }
  348. dwSize = sizeof(DWORD);
  349. lResult = RegQueryValueExA(hKey,
  350. pszRegValName,
  351. NULL,
  352. &dwType,
  353. (BYTE*) pdwValue,
  354. &dwSize);
  355. // if we didn't find the key, create it.
  356. if (bSetIfNotExist)
  357. {
  358. if ((lResult != ERROR_SUCCESS) ||
  359. (dwType != REG_DWORD))
  360. {
  361. lResult = RegSetValueExA(hKey,
  362. pszRegValName,
  363. 0,
  364. REG_DWORD,
  365. (BYTE*) pdwValue,
  366. dwSize);
  367. }
  368. }
  369. return lResult;
  370. }
  371. ////////////////////////////////////////////////
  372. // wiauDbgInit
  373. //
  374. // Overwrite g_dwDebugFlags and g_dwDebugFileSizeLimit
  375. // from registry
  376. //
  377. void wiauDbgInit(HINSTANCE hInstance)
  378. {
  379. HKEY hKey = NULL;
  380. DWORD dwDispositon = 0;
  381. DWORD dwData;
  382. DWORD dwDisposition = 0;
  383. CHAR szModulePath[MAX_PATH + 1] = {0};
  384. CHAR szDebugKey[1023 + 1] = {0};
  385. CHAR *pszFileName = NULL;
  386. GetModuleFileNameA(hInstance, szModulePath, sizeof(szModulePath) - 1);
  387. pszFileName = strrchr(szModulePath, '\\');
  388. if (pszFileName == NULL)
  389. {
  390. pszFileName = szModulePath;
  391. }
  392. else
  393. {
  394. pszFileName++;
  395. }
  396. //
  397. // build the registry key.
  398. //
  399. _snprintf(szDebugKey, sizeof(szDebugKey) - 1, "%s\\%s", WIAUDBG_FLAGS_REGKEY, pszFileName);
  400. lstrcpynA(g_szModuleName, pszFileName, sizeof(g_szModuleName));
  401. //
  402. // get/set the debug subkey. The DebugValues value is stored on a per module
  403. // basis
  404. //
  405. if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  406. szDebugKey,
  407. 0,
  408. NULL,
  409. 0,
  410. KEY_READ,
  411. NULL,
  412. &hKey,
  413. &dwDisposition) == ERROR_SUCCESS)
  414. {
  415. dwData = g_dwDebugFlags;
  416. if (GetRegDWORD(hKey, WIAUDBG_FLAGS_REGVAL, &dwData, TRUE) == ERROR_SUCCESS)
  417. {
  418. g_dwDebugFlags = dwData;
  419. }
  420. RegCloseKey(hKey);
  421. hKey = NULL;
  422. }
  423. //
  424. // get/set the Max File Size value. This is global to all debug modules since
  425. // the all write to the same file.
  426. //
  427. if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  428. WIAUDBG_FLAGS_REGKEY,
  429. 0,
  430. NULL,
  431. 0,
  432. KEY_READ,
  433. NULL,
  434. &hKey,
  435. &dwDisposition) == ERROR_SUCCESS)
  436. {
  437. dwData = g_dwDebugFileSizeLimit;
  438. if (GetRegDWORD(hKey, WIAUDBG_REGVAL_FILE_SIZE_LIMIT, &dwData, TRUE) == ERROR_SUCCESS)
  439. {
  440. g_dwDebugFileSizeLimit = dwData;
  441. }
  442. RegCloseKey(hKey);
  443. hKey = NULL;
  444. }
  445. g_bDebugInited = TRUE;
  446. return;
  447. }