652 lines
16 KiB
C++
652 lines
16 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.
|
|
|
|
#include "precomp.h"
|
|
#include "resource.h"
|
|
#include "shvui.h"
|
|
#include "shvuicf.h"
|
|
#include "regutil.h"
|
|
|
|
SHVUIClassFactoryData* g_FactoryData = NULL;
|
|
HWND g_hwndDlg = NULL;
|
|
HINSTANCE g_hInst = NULL;
|
|
|
|
// Cache of the remote configuration
|
|
// or non-default configuration (multi-config)
|
|
BYTE g_config = 0;
|
|
|
|
//
|
|
// g_fConfigModeMemoryOnly indicates that we are on remote configuration
|
|
// or non-default configuration (multi-config).
|
|
// Hence instead of reading the configuration settings from registry, read it
|
|
// from g_config, which a cache of the configuration result,
|
|
// and the caller (NPS UI) will call SetConfig() or SetConfigToID() to persist it.
|
|
|
|
// When configuring the remote machine, the local machine invokes
|
|
// INapComponentConfig::GetConfig() on remote machine to obtain the remote
|
|
// machine configuration, it then invokes local UI by calling
|
|
// INapComponentConfig2::InvokeUIFromConfigBlob() and obtains user's changes.
|
|
// It sets the new changes to remote machine using
|
|
// INapComponentConfig::SetConfig().
|
|
//
|
|
|
|
// When configuring a multi-config configuration, the scenario is similar to
|
|
// the remote configuration. The only difference is that
|
|
// INapComponentConfig::GetConfig() is replaced with INapComponentConfig3::GetConfigFromID()
|
|
// and INapComponentConfig::SetConfig() is replaced with INapComponentConfig3::SetConfigToID()
|
|
//
|
|
BOOL g_fConfigModeMemoryOnly = FALSE;
|
|
|
|
INT_PTR CALLBACK DlgProcSHVPage(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM //lParam
|
|
);
|
|
|
|
// Caller needs to pass in an array of size of MAX_PATH or bigger to use this function safely.
|
|
void AssembleRegkeyPathWithID (__out_ecount(MAX_PATH) LPTSTR pwszConfigRegkeyWithID, __in UINT32 uConfigID);
|
|
|
|
int __stdcall wWinMain(
|
|
__in HINSTANCE hInst,
|
|
__in_opt HINSTANCE, // unreferenced hPrevInst
|
|
__in_opt LPWSTR lpCmdLine,
|
|
__in int // unreferenced nCmdShow
|
|
)
|
|
{
|
|
BOOL bExit = FALSE ;
|
|
BOOL bShow = TRUE;
|
|
BOOL bCOMInvoked = FALSE;
|
|
|
|
int bRetCode = TRUE;
|
|
BOOL bIsCOMInitialized = FALSE;
|
|
|
|
WCHAR wszCmd[64];
|
|
int nMax = sizeof(wszCmd)/sizeof(WCHAR);
|
|
|
|
|
|
g_hInst = hInst;
|
|
|
|
g_FactoryData = new SHVUIClassFactoryData();
|
|
if (g_FactoryData == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
HRESULT hr = CoInitialize(NULL) ;
|
|
if (FAILED(hr))
|
|
{
|
|
bRetCode = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
bIsCOMInitialized = TRUE;
|
|
|
|
// Check for "/RegServer" or "/UnRegServer" parameters.
|
|
LPWSTR szTokens = L"-/" ;
|
|
LPWSTR szNextToken = NULL;
|
|
LPWSTR szToken = wcstok_s(lpCmdLine, szTokens, &szNextToken) ;
|
|
while (szToken != NULL)
|
|
{
|
|
LoadString(hInst, IDS_CMD_EMBEDDED, wszCmd, nMax);
|
|
if (_wcsicmp(szToken, wszCmd) == 0)
|
|
{
|
|
//Called through INapComponentConfig. Hide until InvokeUI() call.
|
|
bCOMInvoked = TRUE;
|
|
bShow = FALSE;
|
|
}
|
|
LoadString(hInst, IDS_CMD_UNREGSERVER, wszCmd, nMax);
|
|
if (_wcsicmp(szToken, wszCmd) == 0)
|
|
{
|
|
ShvUIClassFactory::Unregister() ;
|
|
// We are done, so exit.
|
|
bExit = TRUE ;
|
|
}
|
|
LoadString(hInst, IDS_CMD_REGSERVER, wszCmd, nMax);
|
|
if (_wcsicmp(szToken, wszCmd) == 0)
|
|
{
|
|
ShvUIClassFactory::Register() ;
|
|
// We are done, so exit.
|
|
bExit = TRUE ;
|
|
}
|
|
|
|
szToken = wcstok_s(NULL, szTokens, &szNextToken) ;
|
|
}
|
|
|
|
if (bExit)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
ShvUIClassFactory::StartFactory();
|
|
|
|
if (bCOMInvoked)
|
|
{
|
|
//Process / dispatch messages, allow system to wait for COM method calls
|
|
BOOL bContinue = TRUE;
|
|
DWORD dwResult;
|
|
while (bContinue)
|
|
{
|
|
dwResult = MsgWaitForMultipleObjects (
|
|
1,
|
|
NULL,
|
|
FALSE,
|
|
INFINITE,
|
|
QS_ALLINPUT);
|
|
switch (dwResult)
|
|
{
|
|
case WAIT_OBJECT_0 + 1:
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
{
|
|
bContinue = FALSE;
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
ShvUIClassFactory::StopFactory();
|
|
|
|
if (bIsCOMInitialized)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
if (g_FactoryData != NULL)
|
|
{
|
|
delete (g_FactoryData);
|
|
g_FactoryData = NULL;
|
|
}
|
|
|
|
return bRetCode ;
|
|
}
|
|
|
|
ShvUI::~ShvUI()
|
|
{
|
|
//The only supported interface is destroyed...quit the application
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
|
|
//Implementation of INapComponentConfig
|
|
STDMETHODIMP ShvUI::QueryInterface(const IID& iid, void** ppv)
|
|
{
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
*ppv = static_cast<INapComponentConfig*>(this);
|
|
}
|
|
else if (iid == IID_INapComponentConfig)
|
|
{
|
|
*ppv = static_cast<INapComponentConfig*>(this);
|
|
}
|
|
else if (iid == IID_INapComponentConfig2)
|
|
{
|
|
*ppv = static_cast<INapComponentConfig2*>(this);
|
|
}
|
|
else if (iid == IID_INapComponentConfig3)
|
|
{
|
|
*ppv = static_cast<INapComponentConfig3*>(this);
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG ShvUI::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
ULONG ShvUI::Release()
|
|
{
|
|
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
|
|
STDMETHODIMP ShvUI::IsUISupported(BOOL* isSupported)
|
|
{
|
|
*isSupported = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP ShvUI::InvokeUI(HWND hwndParent)
|
|
{
|
|
DialogBox(
|
|
g_hInst,
|
|
MAKEINTRESOURCE(IDD_SDKSHV_DIALOG),
|
|
hwndParent,
|
|
DlgProcSHVPage
|
|
);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
ShvUI::GetConfig(UINT16 *bCount, BYTE** data)
|
|
{
|
|
if (!bCount || !data)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD result = ERROR_SUCCESS;
|
|
DWORD dwIsChecked = TRUE;
|
|
|
|
result = ShvuiGetRegistryValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
SDKSHV_DEFAULT_CONFIG_KEY,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PVOID*)&dwIsChecked
|
|
);
|
|
|
|
*bCount = (UINT16) sizeof(BYTE);
|
|
*data = (BYTE*) CoTaskMemAlloc(sizeof(BYTE));
|
|
if (*data)
|
|
{
|
|
**data = (BYTE) dwIsChecked;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
ShvUI::SetConfig(UINT16 bCount, BYTE* data)
|
|
{
|
|
if (!data)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (bCount == sizeof(g_config))
|
|
{
|
|
// set the cached data
|
|
g_config = *data;
|
|
|
|
// commit the cache
|
|
BOOL isChecked = g_config;
|
|
ShvuiSetRegistryValue(
|
|
SDKSHV_DEFAULT_CONFIG_KEY,
|
|
NULL,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PBYTE)&isChecked,
|
|
sizeof(DWORD)
|
|
);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
ShvUI::IsRemoteConfigSupported(BOOL* isSupported, UINT8* remoteConfigType)
|
|
{
|
|
*isSupported = TRUE;
|
|
*remoteConfigType = remoteConfigTypeConfigBlob;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
ShvUI::InvokeUIForMachine(HWND hwndParent, CountedString* machineName)
|
|
{
|
|
MessageBox(hwndParent, L"InvokeUIForMachine", machineName->string, MB_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
ShvUI::InvokeUIFromConfigBlob(
|
|
HWND hwndParent,
|
|
UINT16 inbCount,
|
|
BYTE* inData,
|
|
UINT16* outbCount,
|
|
BYTE** outdata,
|
|
BOOL *fConfigChanged
|
|
)
|
|
{
|
|
if (inbCount != sizeof(g_config))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
g_fConfigModeMemoryOnly = TRUE;
|
|
|
|
//
|
|
// We should have set it TRUE only if the results before and after are different.
|
|
// To keep it simple, set it TRUE without comparison.
|
|
//
|
|
*fConfigChanged = TRUE;
|
|
|
|
g_config = *inData;
|
|
|
|
DialogBox(
|
|
g_hInst,
|
|
MAKEINTRESOURCE(IDD_SDKSHV_DIALOG),
|
|
hwndParent,
|
|
DlgProcSHVPage
|
|
);
|
|
|
|
*outbCount = (UINT16) inbCount;
|
|
*outdata = (BYTE*)CoTaskMemAlloc(*outbCount);
|
|
**outdata = g_config;
|
|
|
|
g_fConfigModeMemoryOnly = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// *********************************************************************
|
|
// INapComponentConfig3 methods:
|
|
// *********************************************************************
|
|
|
|
STDMETHODIMP ShvUI::NewConfig(UINT32 configID)
|
|
{
|
|
// We have no action to take, and we act when SetConfigToID is called.
|
|
UNREFERENCED_PARAMETER(configID);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP ShvUI::DeleteConfig(UINT32 configID)
|
|
{
|
|
WCHAR wszConfigRegkeyWithID[MAX_PATH] = {0};
|
|
AssembleRegkeyPathWithID(wszConfigRegkeyWithID, configID);
|
|
ShvuiDeleteRegistryKey(wszConfigRegkeyWithID);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP ShvUI::DeleteAllConfig()
|
|
{
|
|
ShvuiDeleteRegistryKey(SDKSHV_MULTI_CONFIG_KEY);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP ShvUI::GetConfigFromID(UINT32 configID, UINT16* bCount, BYTE** outdata)
|
|
{
|
|
if (!bCount || !outdata)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (configID == DEFAULT_CONFIGURATION_ID)
|
|
{
|
|
return GetConfig(bCount, outdata);
|
|
}
|
|
|
|
DWORD result = ERROR_SUCCESS;
|
|
DWORD dwIsChecked = TRUE;
|
|
|
|
WCHAR wszConfigRegkeyWithID[MAX_PATH] = {0};
|
|
AssembleRegkeyPathWithID(wszConfigRegkeyWithID, configID);
|
|
|
|
result = ShvuiGetRegistryValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
wszConfigRegkeyWithID,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PVOID*)&dwIsChecked
|
|
);
|
|
|
|
*bCount = (UINT16) sizeof(BYTE);
|
|
*outdata = (BYTE*) CoTaskMemAlloc(sizeof(BYTE));
|
|
if (*outdata)
|
|
{
|
|
**outdata = (BYTE)dwIsChecked;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
STDMETHODIMP ShvUI::SetConfigToID(UINT32 configID, UINT16 bCount, BYTE* outdata)
|
|
{
|
|
if (!outdata)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (configID == DEFAULT_CONFIGURATION_ID)
|
|
{
|
|
return SetConfig(bCount, outdata);
|
|
}
|
|
|
|
WCHAR wszConfigRegkeyWithID[MAX_PATH] = {0};
|
|
AssembleRegkeyPathWithID(wszConfigRegkeyWithID, configID);
|
|
|
|
if (bCount == sizeof(g_config))
|
|
{
|
|
// commit the cache
|
|
BOOL isChecked = *outdata;
|
|
ShvuiSetRegistryValue(
|
|
wszConfigRegkeyWithID,
|
|
NULL,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PBYTE)&isChecked,
|
|
sizeof(DWORD)
|
|
);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD
|
|
ProcessCheckBox(
|
|
HWND hDlg,
|
|
int nIDCheckBox)
|
|
{
|
|
DWORD result = ERROR_SUCCESS;
|
|
BOOL isChecked = FALSE;
|
|
|
|
isChecked = (BST_CHECKED == (BOOL)IsDlgButtonChecked(
|
|
hDlg,
|
|
nIDCheckBox
|
|
));
|
|
if(nIDCheckBox == IDC_SDKSHV_FW)
|
|
{
|
|
if (!g_fConfigModeMemoryOnly)
|
|
{
|
|
result = ShvuiSetRegistryValue(
|
|
SDKSHV_DEFAULT_CONFIG_KEY,
|
|
NULL,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PBYTE)&isChecked,
|
|
sizeof(DWORD));
|
|
}
|
|
else
|
|
{
|
|
if(isChecked)
|
|
{
|
|
g_config = 1;
|
|
}
|
|
else
|
|
{
|
|
g_config = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
OnClickOk(HWND hDlg)
|
|
{
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
result = ProcessCheckBox(
|
|
hDlg,
|
|
IDC_SDKSHV_FW);
|
|
DEBUGLOGRESULT(L"OnClickOk-ProcessCheckBox(IDC_SHV_FW)", result);
|
|
|
|
cleanup:
|
|
return result;
|
|
}
|
|
|
|
|
|
DWORD
|
|
InitializeCheckBoxes(HWND hDlg)
|
|
{
|
|
DWORD result = ERROR_SUCCESS;
|
|
DWORD dwIsChecked = FALSE;
|
|
|
|
if (g_fConfigModeMemoryOnly)
|
|
{
|
|
dwIsChecked = g_config;
|
|
}
|
|
else
|
|
{
|
|
result = ShvuiGetRegistryValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
SDKSHV_DEFAULT_CONFIG_KEY,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PVOID*)&dwIsChecked
|
|
);
|
|
}
|
|
|
|
// if the value is not present, we will try and set a defautl value of 1
|
|
if (result == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
dwIsChecked = TRUE;
|
|
result = ShvuiSetRegistryValue(
|
|
SDKSHV_DEFAULT_CONFIG_KEY,
|
|
NULL,
|
|
SHV_CONFIG_BLOB,
|
|
REG_DWORD,
|
|
(PBYTE)&dwIsChecked,
|
|
sizeof(DWORD));
|
|
|
|
DEBUGLOGRESULT(L"SetCheckBox-ShvuiSetRegistryValue", result);
|
|
}
|
|
else
|
|
{
|
|
DEBUGLOGRESULT(L"SetCheckBox-ShvuiGetRegistryValue", result);
|
|
}
|
|
|
|
if (dwIsChecked == TRUE)
|
|
{
|
|
if (FALSE == CheckDlgButton(
|
|
hDlg,
|
|
IDC_SDKSHV_FW,
|
|
(dwIsChecked == TRUE) ? BST_CHECKED : BST_UNCHECKED
|
|
))
|
|
{
|
|
result = GetLastError();
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
return result;
|
|
|
|
}
|
|
|
|
static BOOLEAN bInitializing = TRUE;
|
|
|
|
// DlgProc
|
|
INT_PTR CALLBACK DlgProcSHVPage(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM //lParam
|
|
)
|
|
{
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
//
|
|
// process message
|
|
//
|
|
switch(message)
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
// read from the registries and set the check boxes as appropriate
|
|
InitializeCheckBoxes(hDlg);
|
|
bInitializing = FALSE;
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
//Ignore check-boxes, these are processed in OnClickOK()
|
|
case IDC_SDKSHV_FW:
|
|
return TRUE;
|
|
|
|
case IDOK:
|
|
result = OnClickOk(hDlg);
|
|
if(ERROR_SUCCESS == result)
|
|
{
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
return TRUE;
|
|
|
|
case IDAPPLY:
|
|
result = OnClickOk(hDlg);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
// end the dialog
|
|
EndDialog(hDlg, 0);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_QUIT:
|
|
// end the dialog
|
|
EndDialog(hDlg, 0);
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void AssembleRegkeyPathWithID (__out_ecount(MAX_PATH) LPTSTR pwszConfigRegkeyWithID, __in UINT32 uConfigID)
|
|
{
|
|
ZeroMemory(pwszConfigRegkeyWithID, MAX_PATH);
|
|
WCHAR wszConfigID[20] = {0};
|
|
StringCchPrintf (wszConfigID, 20, L"\\%u", uConfigID);
|
|
StringCchCopy (pwszConfigRegkeyWithID, MAX_PATH, SDKSHV_MULTI_CONFIG_KEY);
|
|
StringCchCat (pwszConfigRegkeyWithID, MAX_PATH, wszConfigID);
|
|
} |