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.

529 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. // debug log is saved to this file
  22. #define WIAUDBG_FILE_NAME "%systemroot%\\wiadebug.log"
  23. // registry key location
  24. #define WIAUDBG_FLAGS_REGKEY "System\\CurrentControlSet\\Control\\StillImage\\Debug"
  25. // registry DWORD value name
  26. #define WIAUDBG_FLAGS_REGVAL "DebugFlags"
  27. // registry DWORD for max log file size
  28. #define WIAUDBG_REGVAL_FILE_SIZE_LIMIT "DebugFileSizeLimit"
  29. #define WIAUDBG_FILE_SIZE_LIMIT (512 * 1024) // bytes
  30. // Prefix for all messages
  31. const CHAR PREFIX_WIA[] = "WIA: ";
  32. // if we fail to acquire mutex within this time, shutdown tracing
  33. const INT WIAUDBG_DEBUG_TIMEOUT = 10000;
  34. // globals
  35. DWORD g_dwDebugFlags = WIAUDBG_DEFAULT_FLAGS;
  36. HANDLE g_hDebugFile = INVALID_HANDLE_VALUE;
  37. DWORD g_dwDebugFileSizeLimit = WIAUDBG_FILE_SIZE_LIMIT;
  38. BOOL g_bDebugInited = FALSE;
  39. static CHAR g_szDebugFileName[MAX_PATH] = "";
  40. static CHAR g_szModuleName[MAX_PATH] = "";
  41. static HANDLE g_hDebugFileMutex = NULL;
  42. static BOOL g_bInited = FALSE;
  43. static BOOL g_bBannerPrinted = FALSE;
  44. #undef TRACE
  45. #ifdef DEBUG
  46. #define TRACE(x) WiauInternalTrace x
  47. #else
  48. #define TRACE(x)
  49. #endif
  50. ////////////////////////////////////////////////
  51. // WiauInternalTrace
  52. //
  53. // Internal tracing for problems in DebugWrite
  54. //
  55. static void WiauInternalTrace(LPCSTR fmt, ...)
  56. {
  57. char buffer[1024];
  58. size_t len = 0;
  59. va_list marker;
  60. va_start(marker, fmt);
  61. _vsnprintf(buffer, 1024, fmt, marker);
  62. len = strlen(buffer);
  63. if(len > 0)
  64. {
  65. // make sure the line has terminating "\n"
  66. if(buffer[len - 1] != '\n') {
  67. buffer[len++] = '\n';
  68. buffer[len] = '\0';
  69. }
  70. OutputDebugStringA(buffer);
  71. }
  72. va_end(marker);
  73. }
  74. ////////////////////////////////////////////////
  75. // WiauCreateLogFileMutex
  76. //
  77. // Create logfile mutex with appropriate DACL
  78. //
  79. BOOL WiauCreateLogFileMutex(void)
  80. {
  81. #undef CHECK
  82. #define CHECK(x) if(!(x)) { \
  83. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  84. goto Cleanup; }
  85. #undef CHECK2
  86. #define CHECK2(x, y) if(!(x)) { \
  87. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  88. TRACE(y); goto Cleanup; }
  89. BOOL success = FALSE;
  90. char rgchSD[SECURITY_DESCRIPTOR_MIN_LENGTH];
  91. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) &rgchSD;
  92. SECURITY_ATTRIBUTES sa;
  93. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  94. PSID AuthenticatedUsers = NULL;
  95. PSID BuiltinAdministrators = NULL;
  96. ULONG AclSize;
  97. ACL *pAcl = NULL;
  98. CHECK(AllocateAndInitializeSid(&NtAuthority, 2,
  99. SECURITY_BUILTIN_DOMAIN_RID,
  100. DOMAIN_ALIAS_RID_ADMINS,
  101. 0, 0, 0, 0, 0, 0,
  102. &BuiltinAdministrators));
  103. CHECK(AllocateAndInitializeSid(&NtAuthority, 1,
  104. SECURITY_BUILTIN_DOMAIN_RID,
  105. SECURITY_AUTHENTICATED_USER_RID,
  106. 0, 0, 0, 0, 0, 0,
  107. &AuthenticatedUsers));
  108. AclSize = sizeof(ACL) +
  109. 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG)) +
  110. GetLengthSid(BuiltinAdministrators) +
  111. GetLengthSid(AuthenticatedUsers);
  112. pAcl = (ACL *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AclSize);
  113. CHECK(pAcl);
  114. CHECK(InitializeAcl(pAcl, AclSize, ACL_REVISION));
  115. CHECK(AddAccessAllowedAce(pAcl, ACL_REVISION,
  116. GENERIC_ALL, BuiltinAdministrators));
  117. CHECK(AddAccessAllowedAce(pAcl, ACL_REVISION,
  118. SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
  119. AuthenticatedUsers));
  120. CHECK(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
  121. sa.nLength = sizeof(sa);
  122. sa.bInheritHandle = TRUE;
  123. CHECK(SetSecurityDescriptorDacl(pSD, TRUE, pAcl, FALSE));
  124. sa.lpSecurityDescriptor = pSD;
  125. CHECK((g_hDebugFileMutex = CreateMutexA(&sa, FALSE, "Global\\WiaDebugFileMut")) != NULL);
  126. success = TRUE;
  127. Cleanup:
  128. if(!success) {
  129. if(BuiltinAdministrators) FreeSid(BuiltinAdministrators);
  130. if(AuthenticatedUsers) FreeSid(AuthenticatedUsers);
  131. if(pAcl) HeapFree(GetProcessHeap(), 0, pAcl);
  132. }
  133. return success;
  134. }
  135. ////////////////////////////////////////////////
  136. // DebugWrite
  137. //
  138. // Writes specified number of bytes to a debug
  139. // file, creating it if needed. Thread-safe.
  140. // Registers any failure and from that point returns
  141. // immediately.
  142. //
  143. static void
  144. DebugWrite(LPCSTR buffer, DWORD n)
  145. {
  146. #undef CHECK
  147. #define CHECK(x) if(!(x)) { \
  148. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  149. bCatastrophicFailure = TRUE; goto Cleanup; }
  150. #undef CHECK2
  151. #define CHECK2(x, y) if(!(x)) { \
  152. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  153. TRACE(y); bCatastrophicFailure = TRUE; goto Cleanup; }
  154. DWORD cbWritten;
  155. DWORD dwWaitResult;
  156. LARGE_INTEGER newPos = { 0, 0 };
  157. static BOOL bCatastrophicFailure = FALSE;
  158. BOOL bMutexAcquired = FALSE;
  159. // if something is broken, return immediately
  160. if(bCatastrophicFailure) return;
  161. // make sure we have file mutex
  162. if(!g_hDebugFileMutex)
  163. {
  164. CHECK(WiauCreateLogFileMutex());
  165. }
  166. // acquire mutex
  167. dwWaitResult = WaitForSingleObject(g_hDebugFileMutex, WIAUDBG_DEBUG_TIMEOUT);
  168. // if we failed to acquire mutex within the specified timeout,
  169. // shutdown tracing (on free builds users will not know this)
  170. CHECK(dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED);
  171. bMutexAcquired = TRUE;
  172. // make sure we have open file
  173. if(g_hDebugFile == INVALID_HANDLE_VALUE)
  174. {
  175. // attempt to open file
  176. CHECK(ExpandEnvironmentStringsA(WIAUDBG_FILE_NAME, g_szDebugFileName, MAX_PATH));
  177. g_hDebugFile = CreateFileA(g_szDebugFileName, GENERIC_WRITE,
  178. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  179. CHECK2(g_hDebugFile != INVALID_HANDLE_VALUE,
  180. ("g_szDebugFileName = '%s'", g_szDebugFileName));
  181. }
  182. // seek to the end of file
  183. CHECK(SetFilePointerEx(g_hDebugFile, newPos, &newPos, SEEK_END));
  184. // check the file size
  185. if(newPos.HighPart != 0 || newPos.LowPart > g_dwDebugFileSizeLimit)
  186. {
  187. static CHAR LogFullMessage[128];
  188. TRACE(("Reached log file maximum size of %d", g_dwDebugFileSizeLimit));
  189. sprintf(LogFullMessage, "Log file reached maximum size of %d, logging stopped.", g_dwDebugFileSizeLimit);
  190. CHECK2(WriteFile(g_hDebugFile, LogFullMessage, strlen(LogFullMessage), &cbWritten, NULL), ("%d", cbWritten));
  191. bCatastrophicFailure = TRUE;
  192. }
  193. // write data
  194. CHECK2(WriteFile(g_hDebugFile, buffer, n, &cbWritten, NULL),
  195. ("%d %d", cbWritten, n));
  196. // make sure we write to the disk now.
  197. FlushFileBuffers(g_hDebugFile);
  198. CHECK2(cbWritten == n, ("%d %d", n, cbWritten))
  199. Cleanup:
  200. if(bMutexAcquired) ReleaseMutex(g_hDebugFileMutex);
  201. return;
  202. }
  203. ////////////////////////////////////////////////
  204. // PrintBanner
  205. //
  206. // Since we append to the log file, we need a
  207. // seperator of some sort so we know when a
  208. // new execution has started.
  209. //
  210. void PrintBanner(void)
  211. {
  212. char buffer[1024];
  213. size_t len = 0;
  214. SYSTEMTIME SysTime;
  215. GetLocalTime(&SysTime);
  216. if (g_dwDebugFlags)
  217. {
  218. _snprintf(buffer, sizeof(buffer),
  219. "====================Start '%s' Debug - Time: %d/%02d/%02d %02d:%02d:%02d:%02d====================",
  220. g_szModuleName,
  221. SysTime.wYear,
  222. SysTime.wMonth,
  223. SysTime.wDay,
  224. SysTime.wHour,
  225. SysTime.wMinute,
  226. SysTime.wSecond,
  227. SysTime.wMilliseconds);
  228. }
  229. len = strlen(buffer);
  230. if(len > 0)
  231. {
  232. // make sure the line has terminating "\n"
  233. if(buffer[len - 1] != '\n')
  234. {
  235. buffer[len++] = '\r';
  236. buffer[len++] = '\n';
  237. buffer[len] = '\0';
  238. }
  239. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_FILE))
  240. {
  241. DebugWrite(buffer, len);
  242. }
  243. if(!(g_dwDebugFlags & WIAUDBG_DONT_LOG_TO_DEBUGGER))
  244. {
  245. OutputDebugStringA(buffer);
  246. }
  247. }
  248. return;
  249. }
  250. ////////////////////////////////////////////////
  251. // wiauDbgHelper
  252. //
  253. // Formats message and writes it into log file
  254. // and/or debugger;
  255. //
  256. void wiauDbgHelper(LPCSTR prefix,
  257. LPCSTR fname,
  258. LPCSTR fmt,
  259. va_list marker)
  260. {
  261. char buffer[1024];
  262. size_t len = 0;
  263. if(!g_bDebugInited)
  264. {
  265. wiauDbgInit(NULL);
  266. }
  267. //
  268. // The first time we ever print a debug statement, lets
  269. // output a seperator line since when we output to file
  270. // we append, this way we can seperate different execution
  271. // sessions.
  272. //
  273. if (!g_bBannerPrinted)
  274. {
  275. PrintBanner();
  276. g_bBannerPrinted = TRUE;
  277. }
  278. lstrcpyA(buffer, PREFIX_WIA);
  279. lstrcatA(buffer, prefix);
  280. if (g_dwDebugFlags & WIAUDBG_PRINT_TIME) {
  281. SYSTEMTIME MsgTime;
  282. GetLocalTime(&MsgTime);
  283. sprintf(buffer + strlen(buffer),
  284. "[%02d:%02d:%02d.%03d] ", MsgTime.wHour, MsgTime.wMinute, MsgTime.wSecond, MsgTime.wMilliseconds);
  285. }
  286. lstrcatA(buffer, fname);
  287. len = strlen(buffer);
  288. buffer[len++] = ':';
  289. buffer[len++] = ' ';
  290. _vsnprintf(buffer + len, 1024, fmt, marker);
  291. len = strlen(buffer);
  292. if(len > 0)
  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));
  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), "%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 | KEY_WRITE,
  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 | KEY_WRITE,
  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. }