mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-25 01:14:07 +00:00
248 lines
7.5 KiB
C++
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
|