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.
498 lines
12 KiB
498 lines
12 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|