/*++ Copyright (C) 1999- Microsoft Corporation Module Name: ptputil.cpp Abstract: This module implements PTP data structure manipulating functions Author: William Hsieh (williamh) created Revision History: --*/ #include "ptppch.h" // // This function converts a PTP datetime string to Windows FILETIME. // // Input: // pptpTime -- the PTP datetime string // SystemTime -- SYSTEMTIME structure to receive the converted time // // Notes: // PTP timestamp is a string with the format "YYYYMMDDThhmmss.s", where // YYYY is the year // MM is the month(1 - 12) // DD is the day(1 - 31) // T is the constant used to separate date and time // hh is the hour(0 - 23) // mm is the minute(0 - 59) // ss is the second(0 - 59) // .s is the optional 10th of second // // Append it with 'Z' means it is a UTC time. // Append it with "+/-hhmm" means it is relative to a time zone. // Append neither means the time zone is unknown, assume time zone of the host. // HRESULT PtpTime2SystemTime( CBstr *pptpTime, SYSTEMTIME *pSystemTime ) { DBG_FN("PTPTime2FileTime"); HRESULT hr = S_OK; if (!pSystemTime || !pptpTime || !pptpTime->String() || pptpTime->Length() < 4 + 2 + 2 + 1 + 2 + 2 + 2 || L'T' != pptpTime->String()[4 + 2 + 2]) { wiauDbgTrace("PtpTime2SystemTime", "Invalid arg"); return E_INVALIDARG; } WCHAR TimeString[MAX_PATH]; ZeroMemory(TimeString, sizeof(TimeString)); hr = StringCchCopyW(TimeString, ARRAYSIZE(TimeString), pptpTime->String()); if (FAILED(hr)) { wiauDbgErrorHr(hr, "PtpTime2SystemTime", "StringCchCopyW failed"); goto Cleanup; } WCHAR wch; LPWSTR pwcsEnd; wch = TimeString[4]; TimeString[4] = UNICODE_NULL; pSystemTime->wYear = (WORD)wcstol(TimeString, &pwcsEnd, 10); TimeString[4] = wch; wch = TimeString[6]; TimeString[6] = UNICODE_NULL; pSystemTime->wMonth = (WORD)wcstol(TimeString + 4, &pwcsEnd, 10); TimeString[6] = wch; wch = TimeString[8]; TimeString[8] = UNICODE_NULL; pSystemTime->wDay = (WORD)wcstol(TimeString + 6 , &pwcsEnd, 10); TimeString[8] = wch; wch = TimeString[11]; TimeString[11] = UNICODE_NULL; pSystemTime->wHour = (WORD)wcstol(TimeString + 9, &pwcsEnd, 10); TimeString[11] = wch; wch = TimeString[13]; TimeString[13] = UNICODE_NULL; pSystemTime->wMinute = (WORD)wcstol(TimeString + 11, &pwcsEnd, 10); TimeString[13] = wch; wch = TimeString[15]; TimeString[15] = UNICODE_NULL; pSystemTime->wSecond = (WORD)wcstol(TimeString + 13, &pwcsEnd, 10); TimeString[15] = wch; if (L'.' == wch) { wch = TimeString[17]; TimeString[17] = UNICODE_NULL; pSystemTime->wMilliseconds = 100 * (WORD)wcstol(TimeString + 16, &pwcsEnd, 10); TimeString[17] = wch; } else { pSystemTime->wMilliseconds = 0; } pSystemTime->wDayOfWeek = 0; // // WIAFIX-8/17/2000-davepar Time zone information is being ignored // Cleanup: return hr; } // // This function converts a SYSTEMTIME to PTP datetime string. // // Input: // pSystemTime -- the SYSTEMTIME // pptpTime -- target PTP datatime string // HRESULT SystemTime2PtpTime( SYSTEMTIME *pSystemTime, CBstr *pptpTime, BOOL bTwoDigitsForMilliseconds ) { DBG_FN("SystemTime2PTPTime"); HRESULT hr = S_OK; if (!pptpTime || !pSystemTime) { wiauDbgError("SystemTime2PtpTime", "Invalid arg"); return E_INVALIDARG; } WCHAR ptpTimeStr[MAX_PATH]; WCHAR *pwstr; pwstr = ptpTimeStr; // // Four digits for year, two for month, and two for day // swprintf(pwstr, L"%04d%02d%02d", pSystemTime->wYear, pSystemTime->wMonth, pSystemTime->wDay); // // Separator // pwstr[8] = L'T'; pwstr += 9; // // Two digits for hour, two for minute, and two for second // swprintf(pwstr, L"%02d%02d%02d", pSystemTime->wHour, pSystemTime->wMinute, pSystemTime->wSecond); pwstr += 6; // // Optional tenth second // if (pSystemTime->wMilliseconds) { *pwstr++ = L'.'; // // In XP, PTP driver was sending DATETIME string to camera with two digits for milliseconds (bug 699699) // Some cameras may still expect this format. In this case, vendor should provide custom INF file for // the camera and include the following string entry under DeviceData key: // // [ModelName.DeviceData] // ... // TwoDigitsMillisecondsOutput=1 // ... // if (bTwoDigitsForMilliseconds) { swprintf(pwstr, L"%02d", pSystemTime->wMilliseconds / 10); pwstr += 2; } else { swprintf(pwstr, L"%01d", pSystemTime->wMilliseconds / 100); pwstr += 1; } } // // NULL terminates the string // *pwstr = UNICODE_NULL; hr = pptpTime->Copy(ptpTimeStr); if (FAILED(hr)) { wiauDbgError("SystemTime2PtpTime", "Copy failed"); return hr; } return hr; } // // This function dumps a PTP command block to the log // // Input: // pCommand -- pointer to a PTP command // NumParams -- number of parameters in the command // VOID DumpCommand( PTP_COMMAND *pCommand, DWORD NumParams ) { if (!pCommand) { wiauDbgError("DumpCommand", "Invalid arg"); return; } if (NumParams > COMMAND_NUMPARAMS_MAX) { NumParams = COMMAND_NUMPARAMS_MAX; } wiauDbgDump("DumpCommand", "Dumping command:"); wiauDbgDump("DumpCommand", " Opcode = 0x%04x", pCommand->OpCode); wiauDbgDump("DumpCommand", " Session id = 0x%08x", pCommand->SessionId); wiauDbgDump("DumpCommand", " Transaction id = 0x%08x", pCommand->TransactionId); if (NumParams) { for (DWORD count = 0; count < NumParams; count++) { wiauDbgDump("DumpCommand", " Parameter %d = 0x%08x = %d", count, pCommand->Params[count], pCommand->Params[count]); } } } // // This function dumps a PTP response block to the log // // Input: // pResponse -- pointer to a PTP response // VOID DumpResponse( PTP_RESPONSE *pResponse ) { if (!pResponse) { wiauDbgError("DumpResponse", "Invalid arg"); return; } wiauDbgDump("DumpResponse", "Dumping response:"); wiauDbgDump("DumpResponse", " Response code = 0x%04x", pResponse->ResponseCode); wiauDbgDump("DumpResponse", " Session id = 0x%08x", pResponse->SessionId); wiauDbgDump("DumpResponse", " Transaction id = 0x%08x", pResponse->TransactionId); for (DWORD count = 0; count < RESPONSE_NUMPARAMS_MAX; count++) { wiauDbgDump("DumpResponse", " Parameter %d = 0x%08x = %d", count, pResponse->Params[count], pResponse->Params[count]); } } // // This function dumps a PTP event block to the log // // Input: // pEvent -- pointer to a PTP event // VOID DumpEvent( PTP_EVENT *pEvent ) { if (!pEvent) { wiauDbgError("DumpEvent", "Invalid arg"); return; } wiauDbgDump("DumpEvent", "Dumping event:"); wiauDbgDump("DumpEvent", " Event code = 0x%04x", pEvent->EventCode); wiauDbgDump("DumpEvent", " Session id = 0x%08x", pEvent->SessionId); wiauDbgDump("DumpEvent", " Transaction id = 0x%08x", pEvent->TransactionId); for (DWORD count = 0; count < EVENT_NUMPARAMS_MAX; count++) { wiauDbgDump("DumpEvent", " Parameter %d = 0x%08x = %d", count, pEvent->Params[count], pEvent->Params[count]); } } // // This function dumps a GUID to the log // // Input: // pGuid -- GUID to dump // VOID DumpGuid( GUID *pGuid ) { HRESULT hr = S_OK; if (!pGuid) { wiauDbgError("DumpGuid", "Invalid arg"); return; } WCHAR GuidStringW[128]; hr = StringFromGUID2(*pGuid, GuidStringW, sizeof(GuidStringW) / sizeof(WCHAR)); if (FAILED(hr)) { wiauDbgError("DumpGuid", "StringFromGUID2 failed"); return; } wiauDbgDump("DumpGuid", "Guid = %S", GuidStringW); return; } // // This function opens a registry key // HRESULT CPTPRegistry::Open( HKEY hkAncestor, LPCTSTR KeyName, REGSAM Access ) { DBG_FN("CPTPRegistry::Open"); HRESULT hr = S_OK; if (m_hKey) { wiauDbgError("Open", "Registry is already open"); return E_ACCESSDENIED; } DWORD Win32Err; Win32Err = ::RegOpenKeyEx(hkAncestor, KeyName, 0, Access, &m_hKey); if (Win32Err != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(Win32Err); wiauDbgErrorHr(hr, "Open", "RegOpenKeyEx failed"); return hr; } return hr; } // // This function gets a string type registry value // // Input: // ValueName -- the value's name // pptpStr -- the receive the value // HRESULT CPTPRegistry::GetValueStr( LPCTSTR ValueName, TCHAR *string, DWORD *pcbStringBytes ) { DBG_FN("CPTPRegistry::GetValueStr"); HRESULT hr = S_OK; if (!ValueName || !string) { wiauDbgError("GetValueStr", "Invalid arg"); return E_INVALIDARG; } // // Need to handle non-Unicode // DWORD Win32Err; Win32Err = ::RegQueryValueEx(m_hKey, ValueName, NULL, NULL, (BYTE *) string, pcbStringBytes); if (Win32Err != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(Win32Err); wiauDbgErrorHr(hr, "GetValueStr", "RegQueryValueEx failed"); return hr; } return hr; } // // This function gets a string type registry value and converts it to a DWORD // // Input: // ValueName -- the value's name // pptpStr -- the receive the value // HRESULT CPTPRegistry::GetValueDword( LPCTSTR ValueName, DWORD *pValue ) { DBG_FN("CPTPRegistry::GetValueDword"); HRESULT hr = S_OK; if (!ValueName || !pValue) { wiauDbgError("GetValueDword", "Invalid arg"); return E_INVALIDARG; } // // Get the string from the registry // TCHAR string[MAX_PATH]; DWORD stringLen = sizeof(string); hr = GetValueStr(ValueName, string, &stringLen); if (FAILED(hr)) { wiauDbgError("GetValueDword", "GetValueStr failed"); return hr; } *pValue = _tcstol(string, NULL, 0); return hr; } // // This function gets a list of codes registry value // // Input: // ValueName -- the value's name // // pptpStr -- the receive the value // HRESULT CPTPRegistry::GetValueCodes( LPCTSTR ValueName, CArray16 *pCodeArray ) { DBG_FN("CPTPRegistry::GetValueCodes"); HRESULT hr = S_OK; if (!ValueName || !pCodeArray) { wiauDbgError("GetValueCodes", "Invalid arg"); return E_INVALIDARG; } // // Get the string from the registry // TCHAR valueString[MAX_PATH]; DWORD stringLen = sizeof(valueString); hr = GetValueStr(ValueName, valueString, &stringLen); if (FAILED(hr)) { wiauDbgError("GetValueCodes", "GetValueStr failed"); return hr; } // // Parse the string for codes // TCHAR *pCurrent = _tcstok(valueString, TEXT(",")); WORD code; while (pCurrent) { code = (WORD) _tcstol(pCurrent, NULL, 0); pCodeArray->Add(code); pCurrent = _tcstok(NULL, TEXT(",")); } return hr; }