2025-11-28 00:35:46 +09:00

449 lines
16 KiB
C++

//
// This is part of the Microsoft Tablet PC Platform SDK
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Tablet PC Platform SDK Reference and related electronic
// documentation provided with the Software Development Kit.
// See these sources for more detailed information.
//
// Module:
// TPCInfo.cpp
//
// Description:
// This program checks the presence and configuration of the
// Microsoft Tablet PC Platform core components.
// It finds out whether Tablet PC components are enabled in the
// operating system, shows the names and version info of the
// core controls and default handwriting and speech recognizers.
//
// This application is discussed in the Getting Started guide.
//
//--------------------------------------------------------------------------
// Windows header files
#include <windows.h>
#include <comdef.h>
#include <wchar.h>
// Headers for Tablet PC Automation interfaces
#include <msinkaut.h>
#include <msinkaut_i.c>
// Header for Safe String Operations
#include <strsafe.h>
// The sample's resource header file
#include "resource.h"
// The system metrics index for checking on Tablet PC components
#ifndef SM_TABLETPC
#define SM_TABLETPC 86
#endif
// A useful macro to calculate the number of elements in an array
#ifndef countof
// 'A' must be the name of an array, not just a pointer,
// so that sizeof(A) would give the size of the array
#define countof(A) (sizeof(A)/sizeof(A[0]))
#endif
// IDs of the dialog static controls
#define NUM_CONTROLS 2
const UINT gc_uiCtrlId[NUM_CONTROLS][2] = {{IDC_CTL1_NAME, IDC_CTL1_VER},
{IDC_CTL2_NAME, IDC_CTL2_VER}};
// ProgID's of the Tablet PC controls to check on
LPCOLESTR gc_wszProgId[NUM_CONTROLS] = {L"InkEd.InkEdit", L"msinkaut.InkPicture"};
// The key to the registry settings of the installed speech recognizers
const WCHAR* gc_wszSpeechKey = L"Software\\Microsoft\\Speech\\Recognizers";
// CLSID of the Text Services Framework's ThreadManager object
const CLSID CLSID_TF_ThreadMgr =
{ 0x529A9E6B,0x6587,0x4F23,{ 0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50 } };
// A helper structure, used in the GetComponentInfo function
typedef struct
{
WCHAR wchName[256];
WCHAR wchVersion[256];
} SInfo;
const WCHAR gc_wszAppName[] = L"TPCInfo Sample Application";
/////////////////////////////////////////////////////////
//
// GetComponentInfo
//
// This helper function, provided with a component
// ProgId, gathers the component's name and version
// info and formats them into output strings
//
// Parameters:
// CLSID clsid : [in] component's CLSID
// SInfo& info : [in, out] a structure of buffers
// to get the formatted strings into
//
// Return Values:
// TRUE, if the function succeeds
// FALSE, if it fails
//
/////////////////////////////////////////////////////////
BOOL GetComponentInfo(CLSID clsid, SInfo& info)
{
info.wchName[0] = info.wchVersion[0] = 0;
// Format Registry Key string
WCHAR wszKey[45] = L"CLSID\\"; // the key buffer should be large enough for a string
// like "CLSID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
// Convert CLSID to String
UINT uPos = lstrlenW(wszKey);
if (0 == StringFromGUID2(clsid, &wszKey[uPos], countof(wszKey) - uPos))
return FALSE;
wszKey[countof(wszKey)-1] = 0;
// Open key to find path of application
HKEY hKeyRoot;
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszKey, 0, KEY_READ, &hKeyRoot) != ERROR_SUCCESS)
return FALSE;
// Query value of key to get the name of the component
ULONG cSize = sizeof(info.wchName); // size of the buffer in bytes
if (RegQueryValueExW(hKeyRoot, NULL, NULL, NULL, (BYTE*)info.wchName, &cSize) != ERROR_SUCCESS)
{
RegCloseKey(hKeyRoot);
return FALSE;
}
info.wchName[countof(info.wchName) - 1] = 0;
// Open the version info subkey
UINT iVersionMaxLen = countof(info.wchVersion);
HKEY hKey = NULL;
if (RegOpenKeyExW(hKeyRoot, L"Version", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
const WCHAR* pcwsVersion = L"version ";
UINT iLen = lstrlenW(pcwsVersion);
// Query value of key to get version string
if (iLen < iVersionMaxLen)
{
// copy the "version " string including terminating 0
wcsncpy_s(info.wchVersion, iVersionMaxLen, pcwsVersion, iLen + 1);
// get the version string
cSize = (iVersionMaxLen - iLen) * sizeof(WCHAR); // the size is in bytes
if (RegQueryValueExW(hKey, NULL, NULL, NULL,
(BYTE*)&info.wchVersion[iLen],
&cSize) == ERROR_SUCCESS)
{
info.wchVersion[iVersionMaxLen-1] = 0;
}
}
RegCloseKey(hKey);
}
// Open InprocServer32 subkey to get the path to the component
if (RegOpenKeyExW(hKeyRoot, L"InprocServer32", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
// Query value of key to get the path string
WCHAR wchPath[MAX_PATH];
cSize = sizeof(wchPath);
if (RegQueryValueExW(hKey, NULL, NULL, NULL, (BYTE*)wchPath, &cSize) == ERROR_SUCCESS)
{
// Get the build number from the file version info
DWORD dwHandle = 0;
cSize = GetFileVersionInfoSizeW(wchPath, &dwHandle); // returns the size in bytes
WCHAR* pwchFileVerInfo = NULL;
if (cSize)
{
pwchFileVerInfo = (WCHAR*)new BYTE[cSize];
}
if (NULL != pwchFileVerInfo)
{
// Retrieve version information for the file
if (GetFileVersionInfoW(wchPath, 0, cSize, pwchFileVerInfo))
{
// Get the default language id and code page number
UINT *pdwLang;
UINT cch = 0;
if (VerQueryValueW(pwchFileVerInfo, L"\\VarFileInfo\\Translation",
(void**)&pdwLang, &cch) == TRUE)
{
// Read the file description for the language and code page.
const int MAX_SUBBLOCK = 40;
WCHAR wchSubBlock[MAX_SUBBLOCK]; // large enough for the string
StringCchPrintfExW(wchSubBlock,
MAX_SUBBLOCK,
NULL,
NULL,
STRSAFE_NULL_ON_FAILURE,
L"\\StringFileInfo\\%04x%04x\\FileVersion",
LOWORD(*pdwLang), HIWORD(*pdwLang));
WCHAR* pwchBuildVer = NULL;
if ((VerQueryValueW(pwchFileVerInfo, wchSubBlock,
(void**)&pwchBuildVer, &cch) == TRUE)
&& (NULL != pwchBuildVer))
{
// Format the version string
UINT iLen = (UINT)lstrlenW(info.wchVersion);
if (0 < iLen)
{
if (iLen < iVersionMaxLen)
{
const WCHAR* pcwsBuild = L", build ";
wcsncpy_s(info.wchVersion + iLen, iVersionMaxLen - iLen, pcwsBuild, iVersionMaxLen - iLen);
iLen += lstrlenW(pcwsBuild);
if (iLen < iVersionMaxLen)
{
wcsncpy_s(info.wchVersion + iLen, iVersionMaxLen - iLen, pwchBuildVer, iVersionMaxLen - iLen);
}
}
}
else
{
wcsncpy_s(info.wchVersion, iVersionMaxLen, pwchBuildVer, iVersionMaxLen);
}
info.wchVersion[iVersionMaxLen-1] = 0;
}
}
}
delete [] pwchFileVerInfo;
}
}
RegCloseKey(hKey);
}
RegCloseKey(hKeyRoot);
return TRUE;
}
/////////////////////////////////////////////////////////
//
// DlgProc
//
// The DlgProc function is an application-defined
// function that processes messages sent to the dialog
//
// Parameters:
// HWND hwnd : [in] handle to dialog window
// UINT uMsg : [in] message identifier
// WPARAM wParam : [in] first message parameter
// LPARAM lParam : [in] second message parameter
//
// Return Values:
// The return value is the result of the
// message processing and depends on the message sent
//
/////////////////////////////////////////////////////////
BOOL CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM /* lParam */)
{
BOOL bReturn = FALSE; // the value to return
switch (uMsg)
{
case WM_INITDIALOG:
{
// Initialize the COM
if (FAILED(CoInitialize(NULL)))
{
MessageBoxW(NULL, L"Unable to initialize the COM library",
gc_wszAppName, MB_OK | MB_ICONINFORMATION);
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
}
// Gather and show the information we're interested in
// Check out if Microsoft Tablet PC Platform components of the
// Microsoft Windows XP Professional Operating System are enabled
int bTabletPC = GetSystemMetrics(SM_TABLETPC);
SetDlgItemTextW(hwnd, IDC_TABLETPC,
bTabletPC ? L"Available" : L"Not available");
// Get the version of the Text Services Framework components
SInfo info;
if (GetComponentInfo(CLSID_TF_ThreadMgr, info) == TRUE)
{
SetDlgItemTextW(hwnd, IDC_TSF, info.wchVersion);
}
// Find out the name and the version of the default handwriting recognizer
// Create the enumerator for the installed recognizers
IInkRecognizers* pIInkRecognizers = NULL;
HRESULT hr = CoCreateInstance(CLSID_InkRecognizers,
NULL,
CLSCTX_INPROC_SERVER,
IID_IInkRecognizers,
(void **)&pIInkRecognizers);
if (SUCCEEDED(hr))
{
IInkRecognizer* pIInkRecognizer = NULL;
// The first parameter is the language id, passing 0 means that the language
// id will be retrieved using the user default-locale identifier
hr = pIInkRecognizers->GetDefaultRecognizer(0, &pIInkRecognizer);
if (SUCCEEDED(hr))
{
// Get the recognizer's friendly name
BSTR bstr;
if (SUCCEEDED(pIInkRecognizer->get_Name(&bstr)))
{
SetDlgItemTextW(hwnd, IDC_HWR_NAME, bstr);
SysFreeString(bstr);
}
else
{
SetDlgItemTextW(hwnd, IDC_HWR_NAME, L"Failed");
}
// Get the recognizer's vendor info
if (SUCCEEDED(pIInkRecognizer->get_Vendor(&bstr)))
{
SetDlgItemTextW(hwnd, IDC_HWR_VENDOR, bstr);
SysFreeString(bstr);
}
else
{
SetDlgItemTextW(hwnd, IDC_HWR_VENDOR, L"Failed");
}
// Release it
pIInkRecognizer->Release();
pIInkRecognizer = NULL;
}
// Release the collection object
pIInkRecognizers->Release();
pIInkRecognizers = NULL;
}
// Find out the name and the version of the default speech recognizer
// Open key to find path of application
HKEY hkeySpeech;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, gc_wszSpeechKey, 0, KEY_READ,
&hkeySpeech) == ERROR_SUCCESS)
{
// Query value of key to get the name of the component
WCHAR wchValue[265];
ULONG cSize = sizeof(wchValue);
if (RegQueryValueExW(hkeySpeech, L"DefaultDefaultTokenId", NULL, NULL,
(BYTE*)wchValue, &cSize) == ERROR_SUCCESS)
{
int ndx = lstrlenW(L"HKEY_LOCAL_MACHINE\\");
int len = lstrlenW(wchValue);
if (ndx < len
&& RegOpenKeyExW(HKEY_LOCAL_MACHINE, &wchValue[ndx], 0,
KEY_READ, &hkeySpeech) == ERROR_SUCCESS)
{
cSize = sizeof(wchValue);
if (RegQueryValueExW(hkeySpeech, NULL, NULL, NULL,
(BYTE*)wchValue, &cSize) == ERROR_SUCCESS)
{
SetDlgItemTextW(hwnd, IDC_SPR_NAME, wchValue);
}
}
}
}
// Find out which of the controls are installed and show their version info
for (int i = 0, j = 0; i < NUM_CONTROLS; i++)
{
// Get the component info
CLSID clsid;
if (SUCCEEDED(CLSIDFromProgID(gc_wszProgId[i], &clsid))
&& GetComponentInfo(clsid, info) == TRUE)
{
SetDlgItemTextW(hwnd, gc_uiCtrlId[j][0], info.wchName);
SetDlgItemTextW(hwnd, gc_uiCtrlId[j][1], info.wchVersion);
j++;
}
}
// Done with the COM
CoUninitialize();
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCLOSE: // User clicked on the "Close" button in the dialog.
case IDCANCEL: // User clicked the close button ([X]) in the caption
// or pressed Alt+F4.
DestroyWindow(hwnd);
bReturn = TRUE;
break;
}
break;
}
return bReturn;
}
/////////////////////////////////////////////////////////
//
// WinMain
//
// The WinMain function is called by the system as the
// initial entry point for a Win32-based application.
// It contains typical boilerplate code to create and
// show the main window, and pump messages.
//
// Parameters:
// HINSTANCE hInstance, : [in] handle to current instance
// HINSTANCE hPrevInstance, : [in] handle to previous instance
// LPSTR lpCmdLine, : [in] command line
// int nCmdShow : [in] show state
//
// Return Values:
// 0 : The function terminated before entering the message loop.
// non zero: Value of the wParam when receiving the WM_QUIT message
//
/////////////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// unused parameters
hPrevInstance, lpCmdLine, nCmdShow; // silence the compiler warnings
int iRet = 0;
// Create the application window
HWND hwndDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);
if (NULL != hwndDlg)
{
ShowWindow(hwndDlg, SW_SHOW);
// Start the message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
if (!IsDialogMessage(hwndDlg, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
iRet = (int)msg.wParam;
}
else
{
MessageBoxW(NULL, L"Unable to create the dialog box",
gc_wszAppName, MB_OK | MB_ICONINFORMATION);
}
return iRet;
}