/****************************************************************************/ /* Module: nutint.cpp */ /* */ /* Purpose: Utilities - Win32 version */ /* */ /* Copyright(C) Microsoft Corporation 1997-1998 */ /****************************************************************************/ #include #undef TRC_FILE #define TRC_FILE "nutint" #define TRC_GROUP TRC_GROUP_UTILITIES extern "C" { #include #ifndef OS_WINCE #include #endif } #include "autil.h" /****************************************************************************/ /* Name: UTStartThread */ /* */ /* Purpose: Start a new thread */ /* */ /* Returns: TRUE if successful, FALSE otherwise */ /* */ /* Params: IN entryFunction - pointer to thread entry point */ /* OUT threadID - thread ID */ /* */ /* Operation: Call UTThreadEntry: new thread (Win32) / immediate (Win16) */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTStartThread( UTTHREAD_PROC entryFunction, PUT_THREAD_DATA pThreadData, PDCVOID threadParam ) { HANDLE hndArray[2]; DCUINT32 rc = FALSE; DWORD dwrc; DWORD threadID; UT_THREAD_INFO info; DC_BEGIN_FN("UTStartThread"); info.pFunc = entryFunction; /************************************************************************/ /* For Win32, create a thread - use an Event to signal when the thread */ /* has started OK. */ /* Create event - initially non-signalled; manual control. */ /************************************************************************/ hndArray[0] = CreateEvent(NULL, TRUE, FALSE, NULL); if (hndArray[0] == 0) { TRC_SYSTEM_ERROR("CreateEvent"); DC_QUIT; } TRC_NRM((TB, _T("event %p created - now create thread"), hndArray[0])); info.sync = (ULONG_PTR)hndArray[0]; info.threadParam = threadParam; /************************************************************************/ /* Start a new thread to run the DC-Share core task. */ /* Use C runtime (which calls CreateThread) to avoid memory leaks. */ /************************************************************************/ hndArray[1] = (HANDLE) #if i386 _beginthreadex #else CreateThread #endif (NULL, /* security - default */ 0, /* stack size - default */ #if i386 ((unsigned (__stdcall *)(void*))UTStaticThreadEntry), #else ((unsigned long (__stdcall *)(void*))UTStaticThreadEntry), #endif (PDCVOID)&info, /* thread parameter */ 0, /* creation flags */ #if i386 (unsigned *)&threadID /* thread ID */ #else (unsigned long *)&threadID/* thread ID */ #endif ); if (hndArray[1] == 0) { /********************************************************************/ /* Failed! */ /********************************************************************/ TRC_SYSTEM_ERROR("_beginthreadex"); DC_QUIT; } TRC_NRM((TB, _T("thread %p created - now wait signal"), hndArray[1])); /************************************************************************/ /* Wait for thread exit or event to be set. */ /************************************************************************/ dwrc = WaitForMultipleObjects(2, hndArray, FALSE, INFINITE); switch (dwrc) { case WAIT_OBJECT_0: { /****************************************************************/ /* Event triggered - thread initialised OK. */ /****************************************************************/ TRC_NRM((TB, _T("event signalled"))); rc = TRUE; } break; case WAIT_OBJECT_0 + 1: { /****************************************************************/ /* Thread exit */ /****************************************************************/ if (GetExitCodeThread(hndArray[1], &dwrc)) { TRC_ERR((TB, _T("Thread exited with rc %x"), dwrc)); } else { TRC_ERR((TB, _T("Thread exited with unknown rc"))); } } break; default: { TRC_NRM((TB, _T("Wait returned %d"), dwrc)); } break; } pThreadData->threadID = threadID; pThreadData->threadHnd = (ULONG_PTR)(hndArray[1]); TRC_ALT((TB, _T("Thread ID %#x handle %#x started"), pThreadData->threadID, pThreadData->threadHnd)); DC_EXIT_POINT: /************************************************************************/ /* Destroy event object. */ /************************************************************************/ if (hndArray[0] != 0) { TRC_NRM((TB, _T("Destroy event object"))); CloseHandle(hndArray[0]); } DC_END_FN(); return(rc); } /* UTStartThread */ /****************************************************************************/ /* Name: UTStaticThreadEntry */ /* */ /* Purpose: STATIC Thread entry point. */ /* */ /* Returns: 0 */ /* */ /* Params: IN pInfo - pointer to thread entry function+sync object */ /* */ /* Operation: signal started OK and call the thread enty function - which */ /* enters a message loop. */ /* */ /****************************************************************************/ DCUINT WINAPI CUT::UTStaticThreadEntry(UT_THREAD_INFO * pInfo) { UTTHREAD_PROC pFunc; PDCVOID pThreadParam; DC_BEGIN_FN("UTStaticThreadEntry"); /************************************************************************/ /* Take a copy of the target function, before signalling that the */ /* thread has started. */ /************************************************************************/ pFunc = pInfo->pFunc; /************************************************************************/ /* Take a copy of the instance info before signalling that the */ /* thread has started. */ /************************************************************************/ pThreadParam = pInfo->threadParam; /************************************************************************/ /* Flag that initialisation has succeeded. */ /* NOTE: from now on, pInfo is not valid. Set it to NULL to make sure */ /* no-one tries to dereference it. */ /************************************************************************/ SetEvent((HANDLE)pInfo->sync); pInfo = NULL; /************************************************************************/ /* Call the thread entry point. This executes a message loop. */ /************************************************************************/ pFunc(pThreadParam); DC_END_FN(); return(0); } /****************************************************************************/ /* Name: UTStopThread */ /* */ /* Purpose: End a child thread */ /* */ /* Returns: TRUE if successful, FALSE otherwise */ /* */ /* Params: IN threadData - thread data */ /* */ /* Operation: Post WM_QUIT to the thread. */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTStopThread(UT_THREAD_DATA threadData, BOOL fPumpMessages) { DCBOOL rc; DWORD retval; DWORD dwThreadTimeout; DC_BEGIN_FN("UTStopThread"); // // Bail out if we try to end a thread that never got created in the first // place // if (0 == threadData.threadID) { rc = FALSE; TRC_ERR((TB, _T("Trying to end thread ID %#x hnd: 0x%x"), threadData.threadID, threadData.threadHnd)); DC_QUIT; } // // Post WM_QUIT to the thread. // TRC_NRM((TB, _T("Attempt to stop thread %#x"), threadData.threadID)); if (PostThreadMessage(threadData.threadID, WM_QUIT, 0, 0)) { rc = TRUE; } else { TRC_ERR((TB, _T("Failed to end thread ID %#x"), threadData.threadID)); rc = FALSE; } // // Free build waits forever, checked build can be set to timeout // to help debug deadlocks. A lot of problems become apparent // in stress if the wait times out and the code is allowed to continue. // #ifdef DC_DEBUG dwThreadTimeout = _UT.dwDebugThreadWaitTimeout; #else dwThreadTimeout = INFINITE; #endif // // Wait for thread to complete. // TRC_NRM((TB, _T("Wait for thread %#x to die"), threadData.threadID)); if (fPumpMessages) { retval = CUT::UT_WaitWithMessageLoop((HANDLE)(threadData.threadHnd), dwThreadTimeout); } else { retval = WaitForSingleObject((HANDLE)(threadData.threadHnd), dwThreadTimeout); } if (retval == WAIT_TIMEOUT) { TRC_ABORT((TB, _T("Timeout waiting for threadID %#x handle %#x termination"), threadData.threadID, threadData.threadHnd)); } else { TRC_ALT((TB, _T("Thread id %#x exited."), threadData.threadID)); } DC_EXIT_POINT: DC_END_FN(); return(rc); } /* UTStopThread */ /****************************************************************************/ /* FUNCTION: UTGetCurrentTime(...) */ /* */ /* DESCRIPTION: */ /* ============ */ /* Get the current system time. */ /* */ /* PARAMETERS: */ /* =========== */ /* pTime : pointer to the time structure to be filled with the */ /* current time. */ /* */ /* RETURNS: */ /* ======== */ /* Nothing. */ /* */ /****************************************************************************/ DCVOID DCINTERNAL CUT::UTGetCurrentTime(PDC_TIME pTime) { SYSTEMTIME sysTime; DC_BEGIN_FN("UTGetCurrentTime"); /************************************************************************/ /* Get the system time */ /************************************************************************/ GetSystemTime(&sysTime); /************************************************************************/ /* Now convert it to a DC_TIME - this isn't hard since the structures */ /* are very similar. */ /************************************************************************/ pTime->hour = (DCUINT8)sysTime.wHour; pTime->min = (DCUINT8)sysTime.wMinute; pTime->sec = (DCUINT8)sysTime.wSecond; pTime->hundredths = (DCUINT8)(sysTime.wMilliseconds / 10); DC_END_FN(); return; } /* UTGetCurrentTime */ /****************************************************************************/ /* FUNCTION: UTGetCurrentDate(...) */ /* */ /* DESCRIPTION: */ /* ============ */ /* Get the current system date. */ /* */ /* PARAMETERS: */ /* =========== */ /* pDate : pointer to the date structure to be filled with the */ /* current date. */ /* */ /* RETURNS: */ /* ======== */ /* Nothing. */ /* */ /****************************************************************************/ DCVOID DCINTERNAL CUT::UTGetCurrentDate(PDC_DATE pDate) { SYSTEMTIME sysTime; DC_BEGIN_FN("UTGetCurrentDate"); /************************************************************************/ /* Get the system time */ /************************************************************************/ GetSystemTime(&sysTime); /************************************************************************/ /* Now convert it to a DC_DATE - this isn't hard since the structures */ /* are very similar. */ /************************************************************************/ pDate->day = (DCUINT8)sysTime.wDay; pDate->month = (DCUINT8)sysTime.wMonth; pDate->year = (DCUINT16)sysTime.wYear; DC_END_FN(); return; } /* UTGetCurrentDate */ /****************************************************************************/ /* Name: UTReadEntry */ /* */ /* Purpose: Read an entry from the given section of the registry */ /* */ /* Returns: TRUE if successful, FALSE otherwise */ /* */ /* Params: . */ /* topLevelKey : one of: */ /* - HKEY_CURRENT_USER */ /* - HKEY_LOCAL_MACHINE */ /* pSection : the section name to read from. The product prefix */ /* string is prepended to give the full name. */ /* pEntry : the entry name to read. */ /* pBuffer : a buffer to read the entry to. */ /* bufferSize : the size of the buffer. */ /* expectedDataType : the type of data stored in the entry. */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTReadEntry(HKEY topLevelKey, PDCTCHAR pSection, PDCTCHAR pEntry, PDCUINT8 pBuffer, DCINT bufferSize, DCINT32 expectedDataType) { LONG sysrc; HKEY key; DCINT32 dataType; DCINT32 dataSize; DCTCHAR subKey[UT_MAX_SUBKEY]; DCBOOL keyOpen = FALSE; DCBOOL rc = FALSE; DC_BEGIN_FN("UTReadEntry"); /************************************************************************/ /* Get a subkey for the value. */ /************************************************************************/ UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection); /************************************************************************/ /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */ /* fail. */ /************************************************************************/ sysrc = RegOpenKeyEx(topLevelKey, subKey, 0, /* reserved */ KEY_READ, &key); if (sysrc != ERROR_SUCCESS) { /********************************************************************/ /* Don't trace an error here since the subkey may not exist... */ /********************************************************************/ TRC_NRM((TB, _T("Failed to open key %s, rc = %ld"), subKey, sysrc)); DC_QUIT; } keyOpen = TRUE; /************************************************************************/ /* We successfully opened the key so now try to read the value. Again */ /* it may not exist. */ /************************************************************************/ dataSize = (DCINT32)bufferSize; sysrc = RegQueryValueEx(key, pEntry, 0, /* reserved */ (LPDWORD)&dataType, (LPBYTE)pBuffer, (LPDWORD)&dataSize); if (sysrc != ERROR_SUCCESS) { TRC_NRM((TB, _T("Failed to read value of [%s] %s, rc = %ld"), pSection, pEntry, sysrc)); DC_QUIT; } /************************************************************************/ /* Check that the type is correct. Special case: allow REG_BINARY */ /* instead of REG_DWORD, as long as the length is 32 bits. */ /************************************************************************/ if ((dataType != expectedDataType) && ((dataType != REG_BINARY) || (expectedDataType != REG_DWORD) || (dataSize != 4))) { TRC_ALT((TB,_T("Read value from [%s] %s, but type is %ld - expected %ld"), pSection, pEntry, dataType, expectedDataType)); DC_QUIT; } rc = TRUE; DC_EXIT_POINT: /************************************************************************/ /* Close the key (if required). */ /************************************************************************/ if (keyOpen) { sysrc = RegCloseKey(key); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc)); } } DC_END_FN(); return(rc); } /* UTReadEntry */ /****************************************************************************/ /* Name: UTWriteEntry */ /* */ /* Purpose: Write an entry to the given section of the registry */ /* */ /* Returns: TRUE if successful, FALSE otherwise */ /* */ /* Params: . */ /* topLevelKey : one of: */ /* - HKEY_CURRENT_USER */ /* - HKEY_LOCAL_MACHINE */ /* pSection : the section name to write to. The product prefix */ /* string is prepended to give the full name. */ /* pEntry : the entry name to write */ /* pData : a pointer to the data to write */ /* dataSize : the size of the data to be written. For strings */ /* this must include the NULL terminator */ /* expectedDataType : the type of data to be written */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTWriteEntry(HKEY topLevelKey, PDCTCHAR pSection, PDCTCHAR pEntry, PDCUINT8 pData, DCINT dataSize, DCINT32 dataType) { LONG sysrc; HKEY key; DCTCHAR subKey[UT_MAX_SUBKEY]; DWORD disposition; DCBOOL keyOpen = FALSE; DCBOOL rc = FALSE; DC_BEGIN_FN("UTWriteEntry"); /************************************************************************/ /* Get a subkey for the value. */ /************************************************************************/ UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection); /************************************************************************/ /* Try to create the key. If the entry already exists, RegCreateKeyEx */ /* will open the existing entry. */ /************************************************************************/ sysrc = RegCreateKeyEx(topLevelKey, subKey, 0, /* reserved */ NULL, /* class */ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, /* security attributes */ &key, &disposition); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to create / open key %s, rc = %ld"), subKey, sysrc)); DC_QUIT; } keyOpen = TRUE; TRC_NRM((TB, _T("%s key %s"), (disposition == REG_CREATED_NEW_KEY) ? "Created" : "Opened", subKey)); /************************************************************************/ /* We've got the key, so set the value. */ /************************************************************************/ sysrc = RegSetValueEx(key, pEntry, 0, /* reserved */ dataType, (LPBYTE)pData, (DCINT32)dataSize); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to write value to [%s] %s, rc = %ld"), pSection, pEntry, sysrc)); DC_QUIT; } rc = TRUE; DC_EXIT_POINT: /************************************************************************/ /* Close the key (if required) */ /************************************************************************/ if (keyOpen) { sysrc = RegCloseKey(key); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc)); } } DC_END_FN(); return(rc); } /* UTWriteEntry */ /****************************************************************************/ /* Name: UTDeleteEntry */ /* */ /* Purpose: Deletes an entry from the registry */ /* */ /* Returns: TRUE if successful, FALSE otherwise */ /* */ /* Params: IN pSection - the section name of the entry to delete */ /* IN pEntry - the actual entry to delete */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTDeleteEntry(PDCTCHAR pSection, PDCTCHAR pEntry) { LONG sysrc; HKEY key; DCTCHAR subKey[UT_MAX_SUBKEY]; DCBOOL keyOpen = FALSE; DCBOOL rc = FALSE; DC_BEGIN_FN("UTDeleteEntry"); /************************************************************************/ /* Get a subkey for the value. */ /************************************************************************/ UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection); /************************************************************************/ /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */ /* fail. */ /************************************************************************/ sysrc = RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, /* reserved */ KEY_WRITE, &key); if (sysrc != ERROR_SUCCESS) { /********************************************************************/ /* Don't trace an error here since the subkey may not exist... */ /********************************************************************/ TRC_NRM((TB, _T("Failed to open key %s, rc = %ld"), subKey, sysrc)); DC_QUIT; } keyOpen = TRUE; /************************************************************************/ /* Now try to delete the entry. */ /************************************************************************/ sysrc = RegDeleteValue(key, pEntry); if (sysrc != ERROR_SUCCESS) { /********************************************************************/ /* We failed to delete the entry - this is quite acceptable as it */ /* may never have existed... */ /********************************************************************/ TRC_NRM((TB, _T("Failed to delete entry %s from section %s"), pEntry, pSection)); } rc = TRUE; DC_EXIT_POINT: /************************************************************************/ /* Close the key (if required). */ /************************************************************************/ if (keyOpen) { sysrc = RegCloseKey(key); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc)); } } DC_END_FN(); return(rc); } /* UTDeleteEntry */ /****************************************************************************/ /* Name: UTEnumRegistry */ /* */ /* Purpose: Enumerate keys from registry */ /* */ /* Returns: TRUE - registry key returned */ /* FALSE - no more registry keys to enumerate */ /* */ /* Params: IN pSection - registy section */ /* IN index - index of key to enumerate */ /* OUT pBuffer - output buffer */ /* IN bufferSize - output buffer size */ /* */ /* Operation: */ /* */ /****************************************************************************/ DCBOOL DCINTERNAL CUT::UTEnumRegistry( PDCTCHAR pSection, DCUINT32 index, PDCTCHAR pBuffer, PDCINT pBufferSize ) { LONG sysrc; DCTCHAR subKey[UT_MAX_SUBKEY]; DCBOOL rc = FALSE; FILETIME fileTime; DC_BEGIN_FN("UTEnumRegistry"); /************************************************************************/ /* Get a subkey for the value. */ /************************************************************************/ UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection); /************************************************************************/ /* First time - open the key. Try HKCU first. */ /************************************************************************/ if (index == 0) { sysrc = RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &_UT.enumHKey); TRC_NRM((TB, _T("Open HKCU %s, rc %d"), subKey, sysrc)); if (sysrc != ERROR_SUCCESS) { /****************************************************************/ /* Didn't find HKCU - try HKLM */ /****************************************************************/ sysrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &_UT.enumHKey); TRC_NRM((TB, _T("Open HKLM %s, rc %d"), subKey, sysrc)); if (sysrc != ERROR_SUCCESS) { /************************************************************/ /* Didn't find HKLM either - give up */ /************************************************************/ TRC_ALT((TB, _T("Didn't find subkey %s - give up"), subKey)); DC_QUIT; } } } TRC_ASSERT((_UT.enumHKey != 0), (TB,_T("0 hKey"))); /************************************************************************/ /* If we get here, we have opened a key - do the enumeration now */ /************************************************************************/ sysrc = RegEnumKeyEx(_UT.enumHKey, index, pBuffer, (PDCUINT32)pBufferSize, NULL, NULL, NULL, &fileTime); /************************************************************************/ /* If it worked, set the return code */ /************************************************************************/ if (sysrc == ERROR_SUCCESS) { TRC_NRM((TB, _T("Enumerated key OK"))); rc = TRUE; } else { /********************************************************************/ /* End of enumeration - close the key */ /********************************************************************/ TRC_NRM((TB, _T("End of enumeration, rc %ld"), sysrc)); sysrc = RegCloseKey(_UT.enumHKey); if (sysrc != ERROR_SUCCESS) { TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc)); } _UT.enumHKey = 0; } DC_EXIT_POINT: DC_END_FN(); return(rc); } /* UTEnumRegistry */