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

455 lines
13 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
////////////////////////////////////////////////////////////////////////////////
// Public Headers
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <functiondiscovery.h>
// Sample Headers
#include "SimpleThermostat.h"
#include "SimpleThermostatProxy.h"
//
// Function Declarations
//
VOID DeviceControl(
__in IFunctionInstance* pFunInst
);
LONG GetDesiredTempFromUser();
HRESULT GetDeviceFiFromUser(
__deref_out IFunctionInstance** ppFunInst
);
HRESULT PrintDeviceFiInfo(
__in IFunctionInstance* pFunInst
);
//
// Globals
//
const ULONG GUID_CCH_LEN = 40;
//------------------------------------------------------------------------------
// wmain
//------------------------------------------------------------------------------
int __cdecl wmain( int argc, __in_ecount(argc) wchar_t* argv[] )
{
HRESULT hr = E_FAIL;
IFunctionInstance* pFunInst = NULL;
wprintf( L"\n" );
wprintf( L"*** Simple Thermostat Client ***\n\n" );
wprintf( L"Searching for installed ISimpleThermostat devices...\n\n" );
wprintf( L"CoInitializeEx..." );
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
wprintf( L"0x%x\n", hr );
//
// Search for ISimpleThermostat devices in PnP and ask the user
// which one to use.
//
if( S_OK == hr )
{
hr = GetDeviceFiFromUser( &pFunInst );
}
//
// Allow the user to interact with the selected device
//
if( S_OK == hr )
{
DeviceControl( pFunInst );
}
wprintf( L"Exiting...\n" );
//
// Cleanup
//
if( NULL != pFunInst )
{
pFunInst->Release();
pFunInst = NULL;
}
return hr;
}// wmain
//------------------------------------------------------------------------------
// DeviceControl
// Presents the user with information about the device represented by the
// FI. Also allows minimum interaction with the device.
//------------------------------------------------------------------------------
VOID DeviceControl(
IFunctionInstance* pFunInst
)
{
HRESULT hr = S_OK;
ULONG i = 0;
LONG lCurrentTemp = 0;
LONG lDesiredTemp = 0;
PROPVARIANT pvID = {0};
PROPVARIANT pvName = {0};
IPropertyStore* pPropStore = NULL;
ISimpleThermostat* pSimpleThermostat = NULL;
//
// Ask for the simple thermostat object from the function instance
//
wprintf( L"Query service on the FI for ISimpleThermostat...\n" );
hr = pFunInst->QueryService(
__uuidof(SimpleThermostatProxy),
__uuidof(ISimpleThermostat),
reinterpret_cast<void**>(&pSimpleThermostat)
);
wprintf( L"Query service for ISimpleThermostat returned...0x%x\n", hr );
//
// Grab the name and ID of the device
//
if( S_OK == hr )
{
wprintf( L"OpenPropertyStore on the FI..." );
hr = pFunInst->OpenPropertyStore( STGM_READ, &pPropStore );
wprintf( L"0x%x\n", hr );
}
if( S_OK == hr )
{
wprintf( L"GetValue of PKEY_PNPX_FriendlyName..." );
hr = pPropStore->GetValue( PKEY_PNPX_FriendlyName, &pvName );
wprintf( L"0x%x\n", hr );
}
if( S_OK == hr )
{
wprintf( L"GetValue of PKEY_PNPX_GlobalIdentity..." );
hr = pPropStore->GetValue( PKEY_PNPX_GlobalIdentity, &pvID );
wprintf( L"0x%x\n", hr );
}
//
// Respond to commands from the user until they choose to exit
//
while( S_OK == hr &&
i != 3 )
{
wprintf( L"GetCurrentTemp from thermostat (remote call)..." );
hr = pSimpleThermostat->GetCurrentTemp( &lCurrentTemp );
wprintf( L"0x%x\n", hr );
wprintf( L"GetDesiredTemp from thermostat (remote call)..." );
hr = pSimpleThermostat->GetDesiredTemp( &lDesiredTemp );
wprintf( L"0x%x\n\n", hr );
wprintf( L" __________________________\n" );
wprintf( L"| Simple Thermostat Device |\n" );
wprintf( L"|__________________________|_________________________\n" );
wprintf( L"| |\n" );
wprintf( L"| Name: %-43.43s |\n", pvName.pwszVal );
wprintf( L"| ID: %-45.45s |\n", pvID.pwszVal );
wprintf( L"| Current Temp: %-35d |\n", lCurrentTemp );
wprintf( L"| Desired Temp: %-35d |\n", lDesiredTemp );
wprintf( L"| |\n" );
wprintf( L"| MENU |\n" );
wprintf( L"| 1) Refresh Device Info |\n" );
wprintf( L"| 2) Set Desired Temp |\n" );
wprintf( L"| 3) Exit |\n" );
wprintf( L"|____________________________________________________|\n" );
wprintf( L"> " );
i = _getche() - '0';
wprintf( L"\n\n" );
switch( i )
{
case 1:
wprintf( L"Refreshing device info...\n" );
//
// Nothing needs to be done here since the device info is refreshed
// with every loop.
//
break;
case 2:
lDesiredTemp = GetDesiredTempFromUser();
wprintf( L"SetDesiredTemp on thermostat (remote call)..." );
hr = pSimpleThermostat->SetDesiredTemp( lDesiredTemp );
wprintf( L"0x%x\n", hr );
break;
case 3:
break;
default:
wprintf( L"Invalid selection...\n" );
break;
}
}
//
// Cleanup
//
PropVariantClear( &pvID );
PropVariantClear( &pvName );
if( NULL != pPropStore )
{
pPropStore->Release();
pPropStore = NULL;
}
if( NULL != pSimpleThermostat )
{
pSimpleThermostat->Release();
pSimpleThermostat = NULL;
}
return;
}// DeviceControl
//------------------------------------------------------------------------------
// GetDesiredTempFromUser
// Prompts the user to input a desired temperature and returns the value to
// the caller.
//------------------------------------------------------------------------------
LONG GetDesiredTempFromUser()
{
HRESULT hr = S_OK;
LONG lDesiredTemp = 0;
WCHAR szTemp[5] = {0};
wprintf( L"Enter Desired Temp (4 digit max)> " );
hr = StringCchGetsW( szTemp, 5 );
wprintf( L"\n" );
if( S_OK == hr )
{
lDesiredTemp = _wtol( szTemp );
}
else
{
wprintf( L"Failed to get input string, hr = 0x%x", hr );
}
return lDesiredTemp;
}// GetDesiredTempFromUser
//------------------------------------------------------------------------------
// GetDeviceFiFromUser
// Presents the user with a list of ISimpleThermostat devices and returns
// the FI representing the device the user chooses.
//------------------------------------------------------------------------------
HRESULT GetDeviceFiFromUser(
IFunctionInstance** ppFunInst
)
{
ULONG ulCount = 0;
HRESULT hr = S_OK;
ULONG i = 0;
IFunctionDiscovery* pFunDisc = NULL;
IFunctionInstance* pFunInst = NULL;
IFunctionInstanceCollection* pFunInsts = NULL;
IFunctionInstanceCollectionQuery* pFunInstsQuery = NULL;
WCHAR szInterface[GUID_CCH_LEN] = {0};
wprintf( L"CoCreate the Function Discovery object..." );
hr = CoCreateInstance(
__uuidof(FunctionDiscovery),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IFunctionDiscovery),
reinterpret_cast<void**>(&pFunDisc)
);
wprintf( L"0x%x\n", hr );
if ( S_OK == hr )
{
wprintf( L"Create an PnP instance collection query..." );
hr = pFunDisc->CreateInstanceCollectionQuery(
FCTN_CATEGORY_PNP,
NULL,
FALSE,
NULL,
NULL,
&pFunInstsQuery
);
wprintf( L"0x%x\n", hr );
}
if ( S_OK == hr )
{
wprintf( L"Adding ISimpleThermostat as an interface constraint on the query..." );
StringFromGUID2( __uuidof(ISimpleThermostat), szInterface, GUID_CCH_LEN );
hr = pFunInstsQuery->AddQueryConstraint(
PROVIDERPNP_QUERYCONSTRAINT_INTERFACECLASS,
szInterface
);
wprintf( L"0x%x\n", hr );
}
if ( S_OK == hr )
{
wprintf( L"Execute the query..." );
hr = pFunInstsQuery->Execute( &pFunInsts );
wprintf( L"0x%x\n", hr );
}
if( S_OK == hr )
{
wprintf( L"Get the number of results..." );
hr = pFunInsts->GetCount( &ulCount );
wprintf( L"0x%x\n\n", hr );
wprintf( L"RESULTS (Only listing first 5)\n\n" );
wprintf( L" # Friendly Name Device Identity\n" );
wprintf( L" - ------------------------- ---------------------------------------------\n" );
if( S_OK == hr &&
ulCount < 1 )
{
wprintf( L" No ISimpleThermostat devices found\n" );
hr = E_FAIL;
}
if( S_OK == hr )
{
for( i = 0; i < ulCount; i++ )
{
hr = pFunInsts->Item( i, &pFunInst );
wprintf( L" %d) ", i+1 );
if( S_OK == hr )
{
hr = PrintDeviceFiInfo( pFunInst );
}
if( S_OK != hr )
{
wprintf( L"Error retrieving device info" );
}
wprintf( L"\n" );
hr = S_OK;
}
}
wprintf( L" ---------------------------------------------------------------------------\n" );
}
if( S_OK == hr &&
ulCount > 0 )
{
wprintf( L" Select a device> " );
i = _getche() - '0';
wprintf( L"\n\n" );
if( 0 >= i ||
ulCount < i )
{
wprintf( L"Invalid selection...\n" );
hr = E_FAIL;
}
}
if( S_OK == hr )
{
wprintf( L"Grabbing device %d...", i );
hr = pFunInsts->Item( i-1, &pFunInst );
wprintf( L"0x%x\n", hr );
*ppFunInst = pFunInst;
pFunInst->AddRef();
}
//
// Cleanup
//
if( NULL != pFunInst )
{
pFunInst->Release();
pFunInst = NULL;
}
if( NULL != pFunInsts )
{
pFunInsts->Release();
pFunInsts = NULL;
}
if( NULL != pFunInstsQuery )
{
pFunInstsQuery->Release();
pFunInstsQuery = NULL;
}
if( NULL != pFunDisc )
{
pFunDisc->Release();
pFunDisc = NULL;
}
return hr;
}// GetDeviceFiFromUser
//------------------------------------------------------------------------------
// PrintDeviceFiInfo
// Prints basic information about a device to the console.
//------------------------------------------------------------------------------
HRESULT PrintDeviceFiInfo(
IFunctionInstance* pFunInst
)
{
HRESULT hr = S_OK;
PROPVARIANT pvName = {0};
PROPVARIANT pvID = {0};
IPropertyStore* pPropStore = NULL;
if( NULL == pFunInst )
{
return E_INVALIDARG;
}
hr = pFunInst->OpenPropertyStore( STGM_READ, &pPropStore );
if( S_OK == hr )
{
hr = pPropStore->GetValue( PKEY_PNPX_FriendlyName, &pvName );
}
if( S_OK == hr )
{
hr = pPropStore->GetValue( PKEY_PNPX_GlobalIdentity, &pvID );
}
if( S_OK == hr &&
VT_LPWSTR == pvName.vt &&
VT_LPWSTR == pvID.vt )
{
wprintf( L"%-25.25s %-45.45s", pvName.pwszVal, pvID.pwszVal );
}
//
// Cleanup
//
PropVariantClear( &pvName );
PropVariantClear( &pvID );
if( NULL != pPropStore )
{
pPropStore->Release();
pPropStore = NULL;
}
return hr;
}// PrintDeviceFiInfo