windows-nt/Source/XPSP1/NT/base/ntsetup/oobe/msobmain/api.cpp

1169 lines
33 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//*********************************************************************
//* Microsoft Windows **
//* Copyright(c) Microsoft Corp., 1999 **
//*********************************************************************
//
// API.CPP - Header for the implementation of CAPI
//
// HISTORY:
//
// 1/27/99 a-jaswed Created.
//
#include "api.h"
#include "appdefs.h"
#include "dispids.h"
#include "msobmain.h"
#include "resource.h"
#include <shlobj.h> // bugbug SHGetFolderPath should be used in the future
#include <shlwapi.h>
#include <util.h>
//
// List of characters that are not legal in netnames.
//
static const WCHAR IllegalNetNameChars[] = L"\"/\\[]:|<>+=;,.?* ";
#define REGSTR_PATH_COMPUTERNAME \
L"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
#define REGSTR_PATH_ACTIVECOMPUTERNAME \
L"System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"
#define REGSTR_PATH_TCPIP_PARAMETERS \
L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
#define REGSTR_PATH_VOLATILEENVIRONMENT \
L"VolatileEnvironment"
#define REGSTR_VALUE_HOSTNAME L"Hostname"
#define REGSTR_VALUE_LOGONSERVER L"LOGONSERVER"
DISPATCHLIST APIExternalInterface[] =
{
{L"SaveFile", DISPID_API_SAVEFILE },
{L"SaveFileByCSIDL", DISPID_API_SAVEFILEBYCSIDL },
{L"get_INIKey", DISPID_API_GET_INIKEY },
{L"get_RegValue", DISPID_API_GET_REGVALUE },
{L"set_RegValue", DISPID_API_SET_REGVALUE },
{L"DeleteRegValue", DISPID_API_DELETEREGVALUE },
{L"DeleteRegKey", DISPID_API_DELETEREGKEY },
{L"get_SystemDirectory", DISPID_API_GET_SYSTEMDIRECTORY },
{L"get_CSIDLDirectory", DISPID_API_GET_CSIDLDIRECTORY },
{L"LoadFile", DISPID_API_LOADFILE, },
{L"get_UserDefaultLCID", DISPID_API_GET_USERDEFAULTLCID },
{L"get_ComputerName", DISPID_API_GET_COMPUTERNAME },
{L"set_ComputerName", DISPID_API_SET_COMPUTERNAME },
{L"FlushRegKey", DISPID_API_FLUSHREGKEY },
{L"ValidateComputername", DISPID_API_VALIDATECOMPUTERNAME },
{L"OEMComputername", DISPID_API_OEMCOMPUTERNAME },
{L"FormatMessage", DISPID_API_FORMATMESSAGE },
{L"set_ComputerDesc", DISPID_API_SET_COMPUTERDESC },
{L"get_UserDefaultUILanguage", DISPID_API_GET_USERDEFAULTUILANGUAGE }
};
/////////////////////////////////////////////////////////////
// CAPI::CAPI
CAPI::CAPI(HINSTANCE hInstance)
{
m_cRef = 0;
}
/////////////////////////////////////////////////////////////
// CAPI::~CAPI
CAPI::~CAPI()
{
MYASSERT(m_cRef == 0);
}
////////////////////////////////////////////////
////////////////////////////////////////////////
//// GET / SET :: APILocale
////
HRESULT CAPI::SaveFile(LPCWSTR szPath, LPCWSTR szURL, LPCWSTR szNewFileName)
{
WCHAR szFilePath[MAX_PATH];
lstrcpy(szFilePath, szPath);
lstrcat(szFilePath, szNewFileName);
return URLDownloadToFile(NULL, szURL, szFilePath, 0, NULL);
}
//SHGetSpecialFolderPath is only available if you have the new shell32.dll that came with IE 4.0
typedef BOOL (WINAPI* PFNSHGetPath)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
// bugbug SHGetFolderPath should be used in the future
HRESULT CAPI::WrapSHGetSpecialFolderPath(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate)
{
HRESULT hr = E_NOTIMPL;
HINSTANCE hShell32 = LoadLibrary(L"SHELL32.DLL");
if (NULL != hShell32)
{
PFNSHGetPath pfnGetPath = (PFNSHGetPath)GetProcAddress(hShell32, "SHGetSpecialFolderPathW");
if (NULL != pfnGetPath)
{
hr = pfnGetPath(hwndOwner, lpszPath, nFolder, fCreate) ? S_OK : E_FAIL;
}
FreeLibrary(hShell32);
}
return hr;
}
HRESULT CAPI::SaveFile(INT iCSIDLPath, BSTR bstrURL, BSTR bstrNewFileName)
{
WCHAR szFilePath[MAX_PATH];
// bugbug should we always create this?
HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szFilePath, iCSIDLPath, TRUE);
if (FAILED(hr))
return (hr);
lstrcat(szFilePath, L"\\");
return SaveFile(szFilePath, bstrURL, bstrNewFileName);
}
HRESULT CAPI::SaveFile(BSTR bstrPath, BSTR bstrURL)
{
WCHAR szURLPath[MAX_PATH];
lstrcpy(szURLPath, bstrURL);
LPWSTR pchFileName = wcsrchr(szURLPath, L'/');
if (NULL != pchFileName)
{
*pchFileName++;
return SaveFile(bstrPath, szURLPath, pchFileName);
}
else
return E_FAIL;
}
HRESULT CAPI::SaveFile(INT iCSIDLPath, BSTR bstrURL)
{
WCHAR szURLPath[MAX_PATH];
WCHAR szFilePath[MAX_PATH];
// bugbug should we always create this?
HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szFilePath, iCSIDLPath, TRUE);
if (FAILED(hr))
return (hr);
lstrcpy(szURLPath, bstrURL);
LPWSTR pchFileName = wcsrchr(szURLPath, L'/');
if (NULL != pchFileName)
{
*pchFileName++;
lstrcat(szFilePath, L"\\");
return SaveFile(szFilePath, szURLPath, pchFileName);
}
else
return E_FAIL;
}
HRESULT CAPI::get_INIKey(BSTR bstrINIFileName, BSTR bstrSectionName, BSTR bstrKeyName, LPVARIANT pvResult)
{
WCHAR szItem[1024]; //bugbug bad constants
VariantInit(pvResult);
if (GetPrivateProfileString(bstrSectionName, bstrKeyName, L"",
szItem, MAX_CHARS_IN_BUFFER(szItem), bstrINIFileName))
{
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(szItem);
return S_OK;
}
else
return S_FALSE;
}
bool VerifyHKEY(HKEY hkey)
{
if (HKEY_CLASSES_ROOT == hkey ||
HKEY_CURRENT_USER == hkey ||
HKEY_LOCAL_MACHINE == hkey ||
HKEY_USERS == hkey ||
HKEY_PERFORMANCE_DATA == hkey ||
HKEY_CURRENT_CONFIG == hkey ||
HKEY_DYN_DATA == hkey)
return true;
return false;
}
HRESULT CAPI::FlushRegKey(HKEY hkey)
{
DWORD dwResult;
dwResult = RegFlushKey(hkey);
return ERROR_SUCCESS == dwResult ? S_OK : E_FAIL;
}
HRESULT CAPI::set_RegValue(HKEY hkey, BSTR bstrSubKey, BSTR bstrValue, LPVARIANT pvData)
{
if (!VerifyHKEY(hkey))
return E_INVALIDARG;
DWORD dwResult, dwData;
switch (V_VT(pvData))
{
default:
dwResult = E_FAIL;
break;
case VT_R8:
dwData = (DWORD) V_R8(pvData);
dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
REG_DWORD, (LPVOID) &dwData, sizeof(dwData));
break;
case VT_I4:
dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
REG_DWORD, (LPVOID) &V_I4(pvData), sizeof(V_I4(pvData)));
break;
case VT_BSTR:
dwResult = SHSetValue(hkey, bstrSubKey, bstrValue,
REG_SZ, (LPVOID) (V_BSTR(pvData)), BYTES_REQUIRED_BY_SZ(V_BSTR(pvData)));
break;
}
return ERROR_SUCCESS == dwResult ? S_OK : E_FAIL;
}
HRESULT CAPI::get_RegValue(HKEY hkey, BSTR bstrSubKey,
BSTR bstrValue, LPVARIANT pvResult)
{
if (!VerifyHKEY(hkey))
return E_INVALIDARG;
DWORD dwType = REG_DWORD, cbData = 1024;
BYTE rgbData[1024]; // bugbug data size
HRESULT hr = ERROR_SUCCESS == SHGetValue(hkey, bstrSubKey, bstrValue,
&dwType, (LPVOID) rgbData, &cbData) ? S_OK : E_FAIL;
VariantInit(pvResult);
switch (dwType)
{
default:
case REG_DWORD:
V_VT(pvResult) = VT_I4;
V_I4(pvResult) = (SUCCEEDED(hr) && cbData >= sizeof(long)) ? * (long *) &rgbData : 0;
break;
case REG_SZ:
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(SUCCEEDED(hr) ? (LPCWSTR) rgbData : L"");
break;
}
return hr;
}
HRESULT CAPI::DeleteRegKey(HKEY hkey, BSTR bstrSubKey)
{
if (!VerifyHKEY(hkey))
return E_INVALIDARG;
return ERROR_SUCCESS == SHDeleteKey(hkey, bstrSubKey) ? S_OK : E_FAIL;
}
HRESULT CAPI::DeleteRegValue(HKEY hkey, BSTR bstrSubKey, BSTR bstrValue)
{
if (!VerifyHKEY(hkey))
return E_INVALIDARG;
return ERROR_SUCCESS == SHDeleteValue(hkey, bstrSubKey, bstrValue) ? S_OK : E_FAIL;
}
HRESULT CAPI::get_SystemDirectory(LPVARIANT pvResult)
{
WCHAR szSysPath[MAX_PATH];
if (0 == GetSystemDirectory(szSysPath, MAX_PATH))
return E_FAIL;
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(szSysPath);
return S_OK;
};
HRESULT CAPI::get_CSIDLDirectory(UINT iCSIDLPath, LPVARIANT pvResult)
{
WCHAR szSysPath[MAX_PATH];
// bugbug should we always create this?
HRESULT hr = WrapSHGetSpecialFolderPath(NULL, szSysPath, iCSIDLPath, TRUE);
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(SUCCEEDED(hr) ? (LPCWSTR) szSysPath : L"");
return hr ;
};
HRESULT CAPI::LoadFile(BSTR bstrPath, LPVARIANT pvResult)
{
HANDLE fh = INVALID_HANDLE_VALUE;
HRESULT hr = E_FAIL;
VariantInit(pvResult);
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = NULL;
fh = CreateFile(bstrPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh != INVALID_HANDLE_VALUE)
{
DWORD cbSizeHigh = 0;
DWORD cbSizeLow = GetFileSize(fh, &cbSizeHigh);
BYTE* pbContents = new BYTE[cbSizeLow+1];
// We don't plan to read files greater than a DWORD in length, but we
// want to know if we do.
MYASSERT(0 == cbSizeHigh);
if (NULL != pbContents)
{
if (ReadFile(fh, pbContents, cbSizeLow, &cbSizeHigh, NULL))
{
// File contains ANSI chars
//
USES_CONVERSION;
LPSTR szContents = (LPSTR) pbContents;
pbContents[cbSizeLow] = '\0';
// Make sure there's no imbedded NULs because we rely on lstrlen
MYASSERT( strlen((const char *)pbContents) == cbSizeLow );
V_BSTR(pvResult) = SysAllocString(A2W(szContents));
if (V_BSTR(pvResult)
)
{
hr = S_OK;
}
szContents = NULL;
}
delete [] pbContents;
pbContents = NULL;
}
CloseHandle(fh);
fh = INVALID_HANDLE_VALUE;
}
return hr;
}
HRESULT CAPI::get_UserDefaultLCID(LPVARIANT pvResult)
{
VariantInit(pvResult);
V_VT(pvResult) = VT_I4;
V_I4(pvResult) = GetUserDefaultLCID();
return S_OK;
};
STDMETHODIMP
CAPI::get_UserDefaultUILanguage(
LPVARIANT pvResult
)
{
if (pvResult != NULL) {
VariantInit(pvResult);
V_VT(pvResult) = VT_I4;
V_I4(pvResult) = GetUserDefaultUILanguage();
}
return S_OK;
}
HRESULT
CAPI::get_ComputerName(
LPVARIANT pvResult
)
{
HRESULT hr = S_OK;
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD cch = sizeof(szComputerName) / sizeof(WCHAR);
if (! ::GetComputerName( szComputerName, &cch))
{
DWORD dwErr = ::GetLastError();
TRACE1(L"GetComputerName failed (0x%08X)", dwErr);
szComputerName[0] = '\0';
hr = HRESULT_FROM_WIN32(dwErr);
}
if (SUCCEEDED(hr))
{
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(szComputerName);
if (NULL == V_BSTR(pvResult))
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// set_ComputerName
//
// Sets the computer name to a given string. SetComputerNameEx adjusts most
// of the registry entries. However, the following need to be changed
// directly because WinLogon changes them prior to running msoobe.exe:
// * System\CurrentControlSet\Control\ComputerName\\ActiveComputerName
// \ComputerName
// * HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
// \Hostname
// * HKEY_CURRENT_USER\VolatileEnvironment
// \LOGONSERVER
//
// The ActiveComputerName key contains the name currently used by the computer
// and returned by GetComputerName.
//
// The Tcpip\Parameters\Hostname value contains the non-volatile hostname
// returned by ??.
//
// The LOGONSERVER value is used as the value of the LOGONSERVER environment
// variable.
//
HRESULT
CAPI::set_ComputerName(
BSTR bstrComputerName
)
{
HRESULT hr = S_OK;
LRESULT lResult;
HKEY hkey = NULL;
MYASSERT(NULL != bstrComputerName);
if ( NULL == bstrComputerName
|| MAX_COMPUTERNAME_LENGTH < lstrlen((LPCWSTR)bstrComputerName)
)
{
return E_INVALIDARG;
}
// Trim spaces before we use the name
StrTrim(bstrComputerName, TEXT(" "));
// SetComputerNameEx validates the name,sets
// HKLM\System\CurrentControlSet\Control\ComputerName\ComputerName, and
// changes the appropriate network registry entries.
if (! ::SetComputerNameEx(ComputerNamePhysicalDnsHostname,
(LPCWSTR)bstrComputerName)
)
{
DWORD dwErr = ::GetLastError();
TRACE2(L"SetComputerNameEx(%s) failed (0x%08X)",
(LPCWSTR)bstrComputerName, dwErr
);
return HRESULT_FROM_WIN32(dwErr);
}
// The following keys must be set explicitly because SetComputerNameEx does
// not set them.
//
// HKLM\System\CurrentControlSet\Control\ComputerName\ActiveComputerName
// must be set because it is the key that is used to determine the
// current computer name.
//
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_ACTIVECOMPUTERNAME,
0,
KEY_WRITE,
&hkey
);
if (ERROR_SUCCESS == lResult)
{
lResult = RegSetValueEx(hkey,
REGSTR_VAL_COMPUTERNAME,
0,
REG_SZ,
(LPBYTE)bstrComputerName,
BYTES_REQUIRED_BY_SZ(bstrComputerName)
);
RegCloseKey(hkey);
hkey = NULL;
}
if (ERROR_SUCCESS != lResult)
{
TRACE3(L"Failed to set %s to %s (0x%08X)\n",
REGSTR_VAL_COMPUTERNAME,
(LPCWSTR)bstrComputerName,
lResult
);
}
// HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Hostname
// contains the volatile hostname (ie this is the entry that is changed on
// the fly) Winlogon has already updated this entry during boot so we
// must update it ourselves.
//
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_TCPIP_PARAMETERS,
0,
KEY_WRITE,
&hkey
);
if (ERROR_SUCCESS == lResult)
{
lResult = RegSetValueEx(hkey,
REGSTR_VALUE_HOSTNAME,
0,
REG_SZ,
(LPBYTE)bstrComputerName,
BYTES_REQUIRED_BY_SZ(bstrComputerName)
);
RegCloseKey(hkey);
hkey = NULL;
}
if (ERROR_SUCCESS != lResult)
{
TRACE3(L"Failed to set %s to %s (0x%08X)\n",
REGSTR_VALUE_HOSTNAME,
(LPCWSTR)bstrComputerName,
lResult
);
}
// Key should have been closed already.
//
MYASSERT(NULL == hkey);
if (!SetAccountsDomainSid(0, bstrComputerName))
{
TRACE(L"SetAccountsDomainSid failed\n\r",);
}
return S_OK;
}
HRESULT CAPI::ValidateComputername(BSTR bstrComputername)
{
HRESULT hr = E_FAIL;
UINT Length,u;
if (!bstrComputername)
return hr;
// Trim spaces before validation.
StrTrim(bstrComputername, TEXT(" "));
Length = lstrlen(bstrComputername);
if ((Length == 0) || (Length > MAX_COMPUTERNAME_LENGTH))
return hr;
u = 0;
hr = S_OK;
while ((hr == S_OK) && (u < Length))
{
//
// Control chars are invalid, as are characters in the illegal chars list.
//
if((bstrComputername[u] < L' ') || wcschr(IllegalNetNameChars,bstrComputername[u]))
{
hr = E_FAIL;
}
u++;
}
return hr;
}
STDMETHODIMP CAPI::OEMComputername()
{
WCHAR szIniFile[MAX_PATH] = L"";
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
HRESULT hr = E_FAIL;
// Get the name from the INI file.
if (GetCanonicalizedPath(szIniFile, INI_SETTINGS_FILENAME))
{
if (GetPrivateProfileString(USER_INFO_KEYNAME,
L"Computername",
L"\0",
szComputerName,
MAX_CHARS_IN_BUFFER(szComputerName),
szIniFile) != 0)
{
if (SUCCEEDED(hr = ValidateComputername(szComputerName)))
{
hr = set_ComputerName(szComputerName);
if (hr != S_OK)
{
TRACE2(TEXT("OEMComputername: set_ComputerName on %s failed with %lx"), szComputerName, hr);
}
}
else
{
TRACE1(TEXT("OEMComputername: Computername %s is invalid"), szComputerName);
}
}
}
return hr;
}
STDMETHODIMP CAPI::FormatMessage( LPVARIANT pvResult, // message buffer
BSTR bstrSource, // message source
int cArgs, // number of inserts
VARIANTARG *rgArgs // array of message inserts
)
{
DWORD dwErr;
BSTR* rgbstr = NULL;
LPTSTR str = NULL;
if (pvResult == NULL)
{
return S_OK;
}
VariantInit(pvResult);
if (bstrSource == NULL)
{
return E_FAIL;
}
if (cArgs > 0 && rgArgs != NULL)
{
rgbstr = (BSTR*)LocalAlloc(LPTR, cArgs * sizeof(BSTR));
if (rgbstr == NULL)
{
return E_FAIL;
}
// Since IDispatch::Invoke gets argument right to left, and
// since we need to pass argument to FormatMessage left to right,
// we need to reverse the order of argument while copying.
for (int i = 0; i < cArgs; i++)
{
rgbstr[cArgs - 1 - i] = V_BSTR(&rgArgs[i]);
}
}
dwErr = ::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
bstrSource,
0,
0,
(LPTSTR)&str,
MAX_PATH,
(va_list *)rgbstr
);
if (dwErr != 0)
{
V_VT(pvResult) = VT_BSTR;
V_BSTR(pvResult) = SysAllocString(str);
}
if (str != NULL)
{
LocalFree(str);
}
if (rgbstr != NULL)
{
LocalFree(rgbstr);
}
return (dwErr != 0 ? S_OK : E_FAIL);
}
STDMETHODIMP CAPI::set_ComputerDesc(BSTR bstrComputerDesc)
{
WCHAR szKeyName[] = REG_KEY_OOBE_TEMP;
HKEY hKey;
if ( bstrComputerDesc )
{
if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS )
{
RegSetValueEx(hKey, REG_VAL_COMPUTERDESCRIPTION, 0, REG_SZ, (LPBYTE) bstrComputerDesc, BYTES_REQUIRED_BY_SZ(bstrComputerDesc));
RegFlushKey(hKey);
RegCloseKey(hKey);
}
}
return S_OK;
}
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////// IUnknown implementation
///////
///////
/////////////////////////////////////////////////////////////
// CAPI::QueryInterface
STDMETHODIMP CAPI::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
// must set out pointer parameters to NULL
*ppvObj = NULL;
if ( riid == IID_IUnknown)
{
AddRef();
*ppvObj = (IUnknown*)this;
return ResultFromScode(S_OK);
}
if (riid == IID_IDispatch)
{
AddRef();
*ppvObj = (IDispatch*)this;
return ResultFromScode(S_OK);
}
// Not a supported interface
return ResultFromScode(E_NOINTERFACE);
}
/////////////////////////////////////////////////////////////
// CAPI::AddRef
STDMETHODIMP_(ULONG) CAPI::AddRef()
{
return ++m_cRef;
}
/////////////////////////////////////////////////////////////
// CAPI::Release
STDMETHODIMP_(ULONG) CAPI::Release()
{
return --m_cRef;
}
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////// IDispatch implementation
///////
///////
/////////////////////////////////////////////////////////////
// CAPI::GetTypeInfo
STDMETHODIMP CAPI::GetTypeInfo(UINT, LCID, ITypeInfo**)
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////
// CAPI::GetTypeInfoCount
STDMETHODIMP CAPI::GetTypeInfoCount(UINT* pcInfo)
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////
// CAPI::GetIDsOfNames
STDMETHODIMP CAPI::GetIDsOfNames(REFIID riid,
OLECHAR** rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgDispId)
{
HRESULT hr = DISP_E_UNKNOWNNAME;
rgDispId[0] = DISPID_UNKNOWN;
for (int iX = 0; iX < sizeof(APIExternalInterface)/sizeof(DISPATCHLIST); iX ++)
{
if(lstrcmp(APIExternalInterface[iX].szName, rgszNames[0]) == 0)
{
rgDispId[0] = APIExternalInterface[iX].dwDispID;
hr = NOERROR;
break;
}
}
// Set the disid's for the parameters
if (cNames > 1)
{
// Set a DISPID for function parameters
for (UINT i = 1; i < cNames ; i++)
rgDispId[i] = DISPID_UNKNOWN;
}
return hr;
}
/////////////////////////////////////////////////////////////
// CAPI::Invoke
HRESULT CAPI::Invoke
(
DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr
)
{
// Assume everything is hunky-dory. Only return an HRESULT other than S_OK
// in case of a catastrophic failure. Result codes should be returned to
// script via pvarResult.
//
HRESULT hr = S_OK;
switch(dispidMember)
{
case DISPID_API_SAVEFILE:
{
TRACE(L"DISPID_API_SAVEFILE\n");
if (NULL != pdispparams)
{
if (2 < pdispparams->cArgs)
SaveFile(V_BSTR(&pdispparams->rgvarg[2]), V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
else
if (1 < pdispparams->cArgs)
SaveFile(V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
}
break;
}
// bugbug If VariantChangeType returns DISP_E_TYPEMISMATCH, the implementor would set *puArgErr to 0 (indicating the argument in error) and return DISP_E_TYPEMISMATCH from IDispatch::Invoke.
case DISPID_API_SAVEFILEBYCSIDL:
{
TRACE(L"DISPID_API_SAVEFILEBYCSIDL\n");
if (NULL != pdispparams)
{
VARIANTARG vaConverted;
VariantInit(&vaConverted);
if (2 < pdispparams->cArgs)
{
hr = VariantChangeType(&vaConverted, &pdispparams->rgvarg[2], 0, VT_I4);
if (SUCCEEDED(hr))
hr = SaveFile(V_I4(&vaConverted), V_BSTR(&pdispparams->rgvarg[1]), V_BSTR(&pdispparams->rgvarg[0]));
}
else
if (1 < pdispparams->cArgs)
{
hr = VariantChangeType(&vaConverted, &pdispparams->rgvarg[1], 0, VT_I4);
if (SUCCEEDED(hr))
hr = SaveFile(V_I4(&vaConverted), V_BSTR(&pdispparams->rgvarg[0]));
}
}
hr = S_OK; // don't cause script engine to throw exception
break;
}
case DISPID_API_GET_INIKEY:
{
TRACE(L"DISPID_API_GET_INIKEY\n");
if (pdispparams != NULL && pvarResult != NULL)
{
if (pdispparams->cArgs > 2)
{
get_INIKey(
V_BSTR(&pdispparams->rgvarg[2]),
V_BSTR(&pdispparams->rgvarg[1]),
V_BSTR(&pdispparams->rgvarg[0]),
pvarResult
);
}
else if (pdispparams->cArgs == 2)
{
BSTR bstrFile = SysAllocStringLen(NULL, MAX_PATH);
if (bstrFile)
{
if (GetCanonicalizedPath(bstrFile, INI_SETTINGS_FILENAME))
{
get_INIKey(
bstrFile,
V_BSTR(&pdispparams->rgvarg[1]),
V_BSTR(&pdispparams->rgvarg[0]),
pvarResult
);
}
SysFreeString(bstrFile);
}
}
}
break;
}
case DISPID_API_SET_REGVALUE:
TRACE(L"DISPID_API_SET_REGVALUE: ");
if (NULL != pdispparams && 3 < pdispparams->cArgs)
{
BSTR bstrSubKey = NULL;
BSTR bstrValueName = NULL;
BOOL bValid = TRUE;
switch (V_VT(&pdispparams->rgvarg[1]))
{
case VT_NULL:
bstrValueName = NULL;
break;
case VT_BSTR:
bstrValueName = V_BSTR(&pdispparams->rgvarg[1]);
break;
default:
bValid = FALSE;
}
bstrSubKey = V_BSTR(&pdispparams->rgvarg[2]);
if (bValid)
{
TRACE2(L"%s, %s\n", bstrSubKey, bstrValueName);
set_RegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[3]),
bstrSubKey,
bstrValueName,
&pdispparams->rgvarg[0]);
}
}
break;
case DISPID_API_GET_REGVALUE:
TRACE(L"DISPID_API_GET_REGVALUE: ");
if (NULL != pdispparams && NULL != pvarResult && 2 < pdispparams->cArgs)
{
BSTR bstrSubKey = NULL;
BSTR bstrValueName = NULL;
BOOL bValid = TRUE;
switch (V_VT(&pdispparams->rgvarg[0]))
{
case VT_NULL:
bstrValueName = NULL;
break;
case VT_BSTR:
bstrValueName = V_BSTR(&pdispparams->rgvarg[0]);
break;
default:
bValid = FALSE;
}
bstrSubKey = V_BSTR(&pdispparams->rgvarg[1]);
if (bValid)
{
TRACE2(L"%s: %s", bstrSubKey, bstrValueName);
get_RegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[2]),
bstrSubKey,
bstrValueName,
pvarResult);
}
}
break;
case DISPID_API_DELETEREGVALUE:
TRACE(L"DISPID_API_DELETEREGVALUE\n");
if (NULL != pdispparams && 1 < pdispparams->cArgs)
DeleteRegValue((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[2]),
V_BSTR(&pdispparams->rgvarg[1]),
V_BSTR(&pdispparams->rgvarg[0]));
break;
case DISPID_API_DELETEREGKEY:
TRACE(L"DISPID_API_DELETEREGKEY\n");
if (NULL != pdispparams && 1 < pdispparams->cArgs)
DeleteRegKey((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[1]),
V_BSTR(&pdispparams->rgvarg[0]));
break;
case DISPID_API_GET_SYSTEMDIRECTORY:
TRACE(L"DISPID_API_GET_SYSTEMDIRECTORY\n");
if (NULL != pvarResult)
get_SystemDirectory(pvarResult);
break;
case DISPID_API_GET_CSIDLDIRECTORY:
TRACE(L"DISPID_API_GET_CSIDLDIRECTORY\n");
if (NULL != pdispparams && 0 < pdispparams->cArgs && pvarResult != NULL)
get_CSIDLDirectory(V_I4(&pdispparams->rgvarg[0]), pvarResult);
break;
case DISPID_API_LOADFILE:
TRACE(L"DISPID_API_LOADFILE\n");
if (NULL != pdispparams && 0 < pdispparams->cArgs && pvarResult != NULL)
{
LoadFile(V_BSTR(&pdispparams->rgvarg[0]), pvarResult);
}
break;
case DISPID_API_GET_USERDEFAULTLCID:
TRACE(L"DISPID_API_GET_USERDEFAULTLCID\n");
if (pvarResult != NULL)
get_UserDefaultLCID(pvarResult);
break;
case DISPID_API_GET_COMPUTERNAME:
TRACE(L"DISPID_API_GET_COMPUTERNAME\n");
if (NULL != pvarResult)
{
get_ComputerName(pvarResult);
}
break;
case DISPID_API_SET_COMPUTERNAME:
TRACE(L"DISPID_API_SET_COMPUTERNAME\n");
if (pdispparams && &(pdispparams[0].rgvarg[0]))
{
hr = set_ComputerName(pdispparams[0].rgvarg[0].bstrVal);
if (pvarResult)
{
VariantInit(pvarResult);
V_VT(pvarResult) = VT_BOOL;
V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
}
}
hr = S_OK; // don't cause an exception in the scripting engine.
break;
case DISPID_API_FLUSHREGKEY:
TRACE(L"DISPID_API_FLUSHREGKEY\n");
if (pdispparams && &(pdispparams[0].rgvarg[0]))
{
FlushRegKey((HKEY) (DWORD_PTR) V_R8(&pdispparams->rgvarg[0]));
}
break;
case DISPID_API_VALIDATECOMPUTERNAME:
TRACE(L"DISPID_API_VALIDATECOMPUTERNAME\n");
if (pdispparams && (0 < pdispparams->cArgs))
{
hr = ValidateComputername(pdispparams[0].rgvarg[0].bstrVal);
if (pvarResult)
{
VariantInit(pvarResult);
V_VT(pvarResult) = VT_BOOL;
V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
}
}
hr = S_OK; // don't cause an exception in the scripting engine.
break;
case DISPID_API_OEMCOMPUTERNAME:
TRACE(L"DISPID_API_OEMCOMPUTERNAME");
hr = OEMComputername();
if (pvarResult)
{
VariantInit(pvarResult);
V_VT(pvarResult) = VT_BOOL;
V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
}
hr = S_OK; // don't cause an exception in the scripting engine.
break;
case DISPID_API_FORMATMESSAGE:
TRACE(L"DISPID_API_FORMATMESSAGE");
if (pdispparams != NULL)
{
int cArgs = pdispparams->cArgs - 1;
if (cArgs >= 0 && V_VT(&pdispparams->rgvarg[cArgs]) == VT_BSTR)
{
FormatMessage(pvarResult, V_BSTR(&pdispparams->rgvarg[cArgs]), cArgs, &pdispparams->rgvarg[0]);
}
}
break;
case DISPID_API_SET_COMPUTERDESC:
TRACE(L"DISPID_API_SET_COMPUTERDESC\n");
if (pdispparams && &(pdispparams[0].rgvarg[0]))
{
hr = set_ComputerDesc(pdispparams[0].rgvarg[0].bstrVal);
if (pvarResult)
{
VariantInit(pvarResult);
V_VT(pvarResult) = VT_BOOL;
V_BOOL(pvarResult) = Bool2VarBool(SUCCEEDED(hr));
}
}
hr = S_OK; // don't cause an exception in the scripting engine.
break;
case DISPID_API_GET_USERDEFAULTUILANGUAGE:
TRACE(L"DISPID_API_GET_USERDEFAULTUILANGUAGE");
get_UserDefaultUILanguage(pvarResult);
break;
default:
{
hr = DISP_E_MEMBERNOTFOUND;
break;
}
}
return hr;
}