goldendict-ng/sphelper.hh
2018-07-07 17:33:15 +08:00

248 lines
7.5 KiB
C++

#ifndef __SPHELPER_HH_INCLUDED__
#define __SPHELPER_HH_INCLUDED__
#ifndef SR_LOCALIZED_DESCRIPTION
#define SR_LOCALIZED_DESCRIPTION L"Description"
#endif
#ifndef REG_MUI_STRING_TRUNCATE
#define REG_MUI_STRING_TRUNCATE 0x00000001
#endif
#ifndef SPERR_NOT_FOUND
#define FACILITY_SAPI FACILITY_ITF
#define SAPI_ERROR_BASE 0x5000
#define MAKE_SAPI_HRESULT(sev, err) MAKE_HRESULT(sev, FACILITY_SAPI, err)
#define MAKE_SAPI_ERROR(err) MAKE_SAPI_HRESULT(SEVERITY_ERROR, err + SAPI_ERROR_BASE)
#define SPERR_NOT_FOUND MAKE_SAPI_ERROR(0x03a)
#endif
#ifdef _SAPI_VER
#undef _SAPI_VER
#endif
#define _SAPI_VER 0x053
inline void SpHexFromUlong(WCHAR * psz, ULONG ul)
{
// If for some reason we cannot convert a number, set it to 0
if (_ultow(ul, psz, 16))
{
psz[0] = L'0';
psz[1] = 0;
}
}
inline HRESULT SpGetTokenFromId(
const WCHAR * pszTokenId,
ISpObjectToken ** ppToken,
BOOL fCreateIfNotExist = FALSE)
{
HRESULT hr;
ISpObjectToken * cpToken;
hr = CoCreateInstance(CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER,
IID_ISpObjectToken, (void**)&cpToken);
if (SUCCEEDED(hr))
{
hr = cpToken->SetId(NULL, pszTokenId, fCreateIfNotExist);
if (SUCCEEDED(hr))
{
*ppToken = cpToken;
}
else
cpToken->Release();
}
return hr;
}
inline HRESULT SpGetCategoryFromId(
const WCHAR * pszCategoryId,
ISpObjectTokenCategory ** ppCategory,
BOOL fCreateIfNotExist = FALSE)
{
HRESULT hr;
ISpObjectTokenCategory * cpTokenCategory;
hr = CoCreateInstance(CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER,
IID_ISpObjectTokenCategory, (void**)&cpTokenCategory );
if (SUCCEEDED(hr))
{
hr = cpTokenCategory->SetId(pszCategoryId, fCreateIfNotExist);
if (SUCCEEDED(hr))
{
*ppCategory = cpTokenCategory;
}
else
cpTokenCategory->Release();
}
return hr;
}
HRESULT SpEnumTokens(
const WCHAR * pszCategoryId,
const WCHAR * pszReqAttribs,
const WCHAR * pszOptAttribs,
IEnumSpObjectTokens ** ppEnum)
{
HRESULT hr = S_OK;
ISpObjectTokenCategory * cpCategory;
hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
if (SUCCEEDED(hr))
{
hr = cpCategory->EnumTokens(
pszReqAttribs,
pszOptAttribs,
ppEnum);
cpCategory->Release();
}
return hr;
}
inline HRESULT SpGetDescription(ISpObjectToken * pObjToken, WCHAR ** ppszDescription, LANGID Language = GetUserDefaultUILanguage())
{
WCHAR szLangId[10];
HRESULT hr = S_OK;
if (ppszDescription == NULL)
{
return E_POINTER;
}
*ppszDescription = NULL;
#if _SAPI_VER >= 0x053
WCHAR* pRegKeyPath = 0;
WCHAR* pszTemp = 0;
HKEY Handle = NULL;
// Windows Vista does not encourage localized strings in the registry
// When running on Windows Vista query the localized engine name from a resource dll
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof( ver );
if( ( ::GetVersionEx( &ver ) == TRUE ) && ( ver.dwMajorVersion >= 6 ) )
{
// If we reach this code we are running under Windows Vista
HMODULE hmodAdvapi32Dll = NULL;
typedef HRESULT (WINAPI* LPFN_RegLoadMUIStringW)(HKEY, LPCWSTR, LPWSTR, DWORD, LPDWORD, DWORD, LPCWSTR);
LPFN_RegLoadMUIStringW pfnRegLoadMUIStringW = NULL;
// Delay bind with RegLoadMUIStringW since this function is not supported on previous versions of advapi32.dll
// RegLoadMUIStringW is supported only on advapi32.dll that ships with Windows Vista and above
// Calling RegLoadMUIStringW directly makes the loader try to resolve the function reference at load time which breaks,
// hence we manually load advapi32.dll, query for the function pointer and invoke it.
hmodAdvapi32Dll = ::LoadLibrary(TEXT("advapi32.dll"));
if(hmodAdvapi32Dll)
{
pfnRegLoadMUIStringW = (LPFN_RegLoadMUIStringW) ::GetProcAddress(hmodAdvapi32Dll, "RegLoadMUIStringW");
if (!pfnRegLoadMUIStringW)
{
// This should not happen in Vista
// _ASSERT (pfnRegLoadMUIStringW);
hr = TYPE_E_DLLFUNCTIONNOTFOUND;
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND);
}
if (SUCCEEDED(hr))
{
hr = pObjToken->GetId(&pszTemp);
}
if (SUCCEEDED(hr))
{
LONG lErrorCode = ERROR_SUCCESS;
pRegKeyPath = wcschr(pszTemp, L'\\'); // Find the first occurrence of '\\' in the absolute registry key path
if(pRegKeyPath)
{
*pRegKeyPath = L'\0';
pRegKeyPath++; // pRegKeyPath now points to the path to the recognizer token under the HKLM or HKCR hive
*ppszDescription = 0;
// Open the registry key for read and get the handle
if (wcsncmp(pszTemp, L"HKEY_LOCAL_MACHINE", MAX_PATH) == 0)
{
lErrorCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pRegKeyPath, 0, KEY_QUERY_VALUE, &Handle);
}
else if (wcsncmp(pszTemp, L"HKEY_CURRENT_USER", MAX_PATH) == 0)
{
lErrorCode = RegOpenKeyExW(HKEY_CURRENT_USER, pRegKeyPath, 0, KEY_QUERY_VALUE, &Handle);
}
else
{
lErrorCode = ERROR_BAD_ARGUMENTS;
}
// Use MUI RegLoadMUIStringW API to load the localized string
if(ERROR_SUCCESS == lErrorCode)
{
*ppszDescription = (WCHAR*) CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR)); // This should be enough memory to allocate the localized Engine Name
lErrorCode = (*pfnRegLoadMUIStringW) (Handle, SR_LOCALIZED_DESCRIPTION, *ppszDescription, MAX_PATH * sizeof(WCHAR), NULL, REG_MUI_STRING_TRUNCATE, NULL);
}
}
else
{
// pRegKeyPath should never be 0 if we are querying for relative hkey path
lErrorCode = ERROR_BAD_ARGUMENTS;
}
hr = HRESULT_FROM_WIN32(lErrorCode);
}
// Close registry key handle
if(Handle)
{
RegCloseKey(Handle);
}
// Free memory allocated to locals
if(pszTemp)
{
CoTaskMemFree(pszTemp);
}
if (hmodAdvapi32Dll)
{
::FreeLibrary(hmodAdvapi32Dll);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
// If running on OSes released before Windows Vista query the localized string from the registry
// If RegLoadMUIStringW failed to retrieved the localized Engine name retrieve the localized string from the fallback (Default) attribute
#else
hr = E_FAIL;
#endif // _SAPI_VER >= 0x053
if (FAILED(hr))
{
// Free memory allocated above if necessary
if (*ppszDescription != NULL)
{
CoTaskMemFree(*ppszDescription);
*ppszDescription = NULL;
}
SpHexFromUlong(szLangId, Language);
hr = pObjToken->GetStringValue(szLangId, ppszDescription);
if (hr == SPERR_NOT_FOUND)
{
hr = pObjToken->GetStringValue(NULL, ppszDescription);
}
}
return hr;
}
#endif