#include "stdafx.h" #include "theapp.h" #include "netconn.h" #include "netapi.h" #include "prnutil.h" #include "install.h" #include "mydocs.h" #include "comctlwrap.h" #include "icsinst.h" #include "defconn.h" #include "initguid.h" DEFINE_GUID(CLSID_FolderItem, 0xfef10fa2, 0x355e, 0x4e06, 0x93, 0x81, 0x9b, 0x24, 0xd7, 0xf7, 0xcc, 0x88); DEFINE_GUID(CLSID_SharedAccessConnectionManager, 0xBA126AE0,0x2166,0x11D1,0xB1,0xD0,0x00,0x80,0x5F,0xC1,0x27,0x0E); // this doesn't exist in the shell tree #include "resource.h" #include "newapi.h" #include "shgina.h" #include "hnetcfg.h" #include "netconp.h" #include "hnetbcon.h" // ICSLapCtl.h #include "Lm.h" #include "htmlhelp.h" #include "nla.h" #include "netinet.h" #include "netip.h" #include "netras.h" #include "netutil.h" // include files necessary for showing diagrams using ShowHTMLDialog. TinQian #include #include #include #include // Debugging #defines: // Uncomment NO_CHECK_DOMAIN when you want to test the wizard on a domain machine - just don't apply changes ;) // #define NO_CHECK_DOMAIN // Uncomment NO_CONFIG to neuter the wizard for UI-only testing // #define NO_CONFIG // Uncomment FAKE_ICS to simulate the "ICS machine" state // #define FAKE_ICS // Uncomment FAKE_UNPLUGGED to simulate unplugged connections // #define FAKE_UNPLUGGED // Uncomment FAKE_REBOOTREQUIRED to simulate reboot required // #define FAKE_REBOOTREQUIRED // Delay Load ole32.dll function CoSetProxyBlanket since it isn't on W95 Gold // and it's only used by the wizard on NT #define CoSetProxyBlanket CoSetProxyBlanket_NT EXTERN_C STDAPI CoSetProxyBlanket_NT(IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities); // Functions not in any include file yet extern int AdapterIndexFromClass(LPTSTR szClass, BOOL bSkipClass); #define LWS_IGNORERETURN 0x0002 #define MAX_HNW_PAGES 30 #define MAX_WORKGROUPS 20 #define CONN_EXTERNAL 0x00000001 #define CONN_INTERNAL 0x00000002 #define CONN_UNPLUGGED 0x00000004 // Return value to use for sharing configuration conflict #define HNETERRORSTART 0x200 #define E_ANOTHERADAPTERSHARED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, HNETERRORSTART+1) #define E_ICSADDRESSCONFLICT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, HNETERRORSTART+2) class CEnsureSingleInstance { public: CEnsureSingleInstance(LPCTSTR szCaption); ~CEnsureSingleInstance(); BOOL ShouldExit() { return m_fShouldExit;} private: BOOL m_fShouldExit; HANDLE m_hEvent; }; CEnsureSingleInstance::CEnsureSingleInstance(LPCTSTR szCaption) { // Create an event m_hEvent = CreateEvent(NULL, TRUE, FALSE, szCaption); // If any weird errors occur, default to running the instance m_fShouldExit = FALSE; if (NULL != m_hEvent) { // If our event isn't signaled, we're the first instance m_fShouldExit = (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvent, 0)); if (m_fShouldExit) { // app should exit after calling ShouldExit() // Find and show the caption'd window HWND hwndActivate = FindWindow(NULL, szCaption); if (IsWindow(hwndActivate)) { SetForegroundWindow(hwndActivate); } } else { // Signal that event SetEvent(m_hEvent); } } } CEnsureSingleInstance::~CEnsureSingleInstance() { if (NULL != m_hEvent) { CloseHandle(m_hEvent); } } typedef struct _tagHOMENETSETUPINFO { HWND hwnd; DWORD cbSize; DWORD dwFlags; // Data for NT - NetConnections are temporarily represented by their corresponding GUIDs to cross the // thread boundary for asynchronous configuration. BOOL fAsync; GUID guidExternal; GUID* prgguidInternal; DWORD cguidInternal; UINT umsgAsyncNotify; INetConnection* pncExternal; INetConnection** prgncInternal; DWORD cncInternal; // Data for Win9x const NETADAPTER* pNA; // list of adapters. UINT cNA; // count of entries in pNA. RASENTRYNAME* pRas; // list of RAS connectoids. UINT cRas; // count of RAS connectoids. UINT ipaExternal; UINT ipaInternal; // Data for both NT and Win9x TCHAR szComputer[CNLEN + 1]; TCHAR szComputerDescription[256]; TCHAR szWorkgroup[LM20_DNLEN + 1]; // Out-data BOOL fRebootRequired; } HOMENETSETUPINFO, *PHOMENETSETUPINFO; // Function prototypes void HelpCenter(HWND hwnd, LPCWSTR pszTopic); void BoldControl(HWND hwnd, int id); void ShowControls(HWND hwndParent, const int *prgControlIDs, DWORD nControls, int nCmdShow); HRESULT ConfigureHomeNetwork(PHOMENETSETUPINFO pInfo); DWORD WINAPI ConfigureHomeNetworkThread(void* pData); HRESULT ConfigureHomeNetworkSynchronous(PHOMENETSETUPINFO pInfo); HRESULT ConfigureICSBridgeFirewall(PHOMENETSETUPINFO pInfo); HRESULT EnableSimpleSharing(); HRESULT GetConnections(HDPA* phdpa); int FreeConnectionDPACallback(LPVOID pFreeMe, LPVOID pData); HRESULT GetConnectionsFolder(IShellFolder** ppsfConnections); //HRESULT GetConnectionIconIndex(GUID& guidConnection, IShellFolder* psfConnections, int* pIndex, HIMAGELIST imgList); HRESULT GetDriveNameAndIconIndex(LPWSTR pszDrive, LPWSTR pszDisplayName, DWORD cchDisplayName, int* pIndex); void W9xGetNetTypeName(BYTE bNicType, WCHAR* pszBuff, UINT cchBuff); BOOL W9xIsValidAdapter(const NETADAPTER* pNA, DWORD dwFlags); BOOL W9xIsAdapterDialUp(const NETADAPTER* pAdapter); BOOL IsEqualConnection(INetConnection* pnc1, INetConnection* pnc2); void GetTitleFont(LPTSTR pszFaceName, DWORD cch); LONG GetTitlePointSize(void); BOOL FormatMessageString(UINT idTemplate, LPTSTR pszStrOut, DWORD cchSize, ...); int DisplayFormatMessage(HWND hwnd, UINT idCaption, UINT idFormatString, UINT uType, ...); HRESULT SetProxyBlanket(IUnknown * pUnk); HRESULT MakeUniqueShareName(LPCTSTR pszBaseName, LPTSTR pszUniqueName, DWORD cchName); HRESULT WriteSetupInfoToRegistry(PHOMENETSETUPINFO pInfo); HRESULT ReadSetupInfoFromRegistry(PHOMENETSETUPINFO pInfo); HRESULT ShareWellKnownFolders(PHOMENETSETUPINFO pInfo); HRESULT ShareAllPrinters(); HRESULT DeleteSetupInfoFromRegistry(); HRESULT IsUserLocalAdmin(HANDLE TokenHandle, BOOL* pfIsAdmin); BOOL AllPlatformGetComputerName(LPWSTR pszName, DWORD cchName); BOOL AllPlatformSetComputerName(LPCWSTR pszName); void FreeInternalConnections(PHOMENETSETUPINFO pInfo); void FreeInternalGUIDs(PHOMENETSETUPINFO pInfo); void FreeExternalConnection(PHOMENETSETUPINFO pInfo); HRESULT GetConnectionByGUID(HDPA hdpaConnections, const GUID* pguid, INetConnection** ppnc); HRESULT GUIDsToConnections(PHOMENETSETUPINFO pInfo); HRESULT GetConnectionGUID(INetConnection* pnc, GUID* pguid); HRESULT ConnectionsToGUIDs(PHOMENETSETUPINFO pInfo); BOOL IsValidNameSyntax(LPCWSTR pszName, NETSETUP_NAME_TYPE type); void STDMETHODCALLTYPE ConfigurationLogCallback(LPCWSTR pszLogEntry, LPARAM lParam); // Home network wizard class class CHomeNetworkWizard : public IHomeNetworkWizard { friend HRESULT CHomeNetworkWizard_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi); public: // IUnknown STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj); STDMETHOD_(ULONG, AddRef) (); STDMETHOD_(ULONG, Release) (); // IHomeNetworkWizard STDMETHOD(ConfigureSilently)(LPCWSTR pszPublicConnection, DWORD hnetFlags, BOOL* pfRebootRequired); STDMETHOD(ShowWizard)(HWND hwnd, BOOL* pfRebootRequired); protected: CHomeNetworkWizard(); HRESULT Initialize(); HRESULT Uninitialize(); private: // Shared functions void DestroyConnectionList(HWND hwndList); void InitializeConnectionList(HWND hwndList, DWORD dwFlags); void FillConnectionList(HWND hwndList, INetConnection* pncExcludeFromList, DWORD dwFlags); BOOL ShouldShowConnection(INetConnection* pnc, INetConnection* pncExcludeFromList, DWORD dwFlags); BOOL IsConnectionICSPublic(INetConnection* pnc); BOOL IsConnectionUnplugged(INetConnection* pnc); BOOL W9xAddAdapterToList(const NETADAPTER* pNA, const WCHAR* pszDesc, UINT uiAdapterIndex, UINT uiDialupIndex, HWND hwndList, DWORD dwFlags); UINT W9xEnumRasEntries(void); HRESULT GetConnectionByName(LPCWSTR pszName, INetConnection** ppncOut); HRESULT GetInternalConnectionArray(INetConnection* pncExclude, INetConnection*** pprgncArray, DWORD* pcncArray); DWORD GetConnectionCount(INetConnection* pncExclude, DWORD dwFlags); void ReplaceStaticWithLink(HWND hwndStatic, UINT idcLinkControl, UINT idsLinkText); BOOL IsMachineOnDomain(); BOOL IsMachineWrongOS(); BOOL IsICSIPInUse( WCHAR** ppszHost, PDWORD pdwSize ); // Per-Page functions // Welcome static INT_PTR CALLBACK WelcomePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void WelcomeSetTitleFont(HWND hwnd); // No home network hardware static INT_PTR CALLBACK NoHardwareWelcomePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Page with instructions for manual configuration of the network void ManualRefreshConnectionList(); static INT_PTR CALLBACK ManualConfigPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // User has some network hardware unplugged BOOL UnpluggedFillList(HWND hwnd); static INT_PTR CALLBACK UnpluggedPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Found ICS (Internet connection sharing) static INT_PTR CALLBACK FoundIcsPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void FoundIcsSetText(HWND hwnd); BOOL GetICSMachine(LPTSTR pszICSMachineName, DWORD cch); // Connect static INT_PTR CALLBACK ConnectPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void ConnectSetDefault(HWND hwnd); void ConnectNextPage(HWND hwnd); // Show Me Links void ShowMeLink(HWND hwnd, LPCWSTR pszTopic); // Connect other (alternative methods for connection) static INT_PTR CALLBACK ConnectOtherPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Public static INT_PTR CALLBACK PublicPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void PublicSetActive(HWND hwnd); void PublicSetControlState(HWND hwnd); void PublicNextPage(HWND hwnd); void PublicGetControlPositions(HWND hwnd); void PublicResetControlPositions(HWND hwnd); void PublicMoveControls(HWND hwnd, BOOL fItemPreselected); // File sharing static INT_PTR CALLBACK EdgelessPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void EdgelessSetActive(HWND hwnd); // ICS conflict void ICSConflictSetActive(HWND hwnd); static INT_PTR CALLBACK ICSConflictPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // BridgeWarning (do you want to manually configure the bridge? Are you crazy !?) static INT_PTR CALLBACK BridgeWarningPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Private static INT_PTR CALLBACK PrivatePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void PrivateNextPage(HWND hwnd); void PrivateSetControlState(HWND hwnd); // Name (computer and workgroup) static INT_PTR CALLBACK NamePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void NameInitDialog(HWND hwnd); void NameSetControlState(HWND hwnd); HRESULT NameNextPage(HWND hwnd); // Workgroup name void WorkgroupSetControlState(HWND hwnd); HRESULT WorkgroupNextPage(HWND hwnd); static INT_PTR CALLBACK WorkgroupPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Summary static INT_PTR CALLBACK SummaryPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void SummarySetActive(HWND hwnd); // Progress (while the configuration is taking place) static INT_PTR CALLBACK ProgressPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Almost done (after configuration but before the "completed" page) static INT_PTR CALLBACK AlmostDonePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Choose disk drive void FillDriveList(HWND hwndList); void ChooseDiskSetControlState(HWND hwnd); static INT_PTR CALLBACK ChooseDiskPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Insert disk static HRESULT GetSourceFilePath(LPSTR pszSource, DWORD cch); static INT_PTR CALLBACK InsertDiskPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Floppy and XP CD "run the wizard" instructions static INT_PTR CALLBACK InstructionsPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Finish static INT_PTR CALLBACK FinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Error finish static INT_PTR CALLBACK ErrorFinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // No Hardware Finish // An alternate finish if they have a LAN card ONLY, and its used for an INet connection, // so therefore they have no LAN cards connecting to other computers... static INT_PTR CALLBACK NoHardwareFinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Can't Run Wizard Pages // An alternate welcome page when the user isn't an adminm or doesn't have permissions, static INT_PTR CALLBACK CantRunWizardPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static CHomeNetworkWizard* GetThis(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Get Icon Index for network connections based on GUIDs HRESULT GetConnectionIconIndex(GUID& guidConnection, IShellFolder* psfConnections, int* pIndex); // Helpers UINT PopPage() { ASSERT(_iPageStackTop); return _rguiPageStack[--_iPageStackTop]; } void PushPage(UINT uiPageId) { ASSERT(_iPageStackTop < MAX_HNW_PAGES); _rguiPageStack[_iPageStackTop++] = uiPageId; } // Data HDPA _hdpaConnections; HOMENETSETUPINFO _hnetInfo; // even though CNLEN+1 is the limit of a name buffer, friendly names can be longer TCHAR _szICSMachineName[MAX_PATH]; // Machine on the network doing ICS, if applicable UINT _rguiPageStack[MAX_HNW_PAGES]; // Stackopages int _iPageStackTop; // Current top of the stack BOOL _fManualBridgeConfig; // The user wants to manuall configure the bridge BOOL _fICSClient;// This computer will connect through an ICS machine or another sharing device // Shell image lists - never free these HIMAGELIST _himlSmall; HIMAGELIST _himlLarge; LONG _cRef; BOOL _fShowPublicPage; BOOL _fShowSharingPage; BOOL _fNoICSQuestion; BOOL _fNoHomeNetwork; BOOL _fExternalOnly; UINT _iDrive; // Ordinal of removable drive for floppy creation WCHAR _szDrive[256]; // Name of removable drive BOOL _fCancelCopy; BOOL _fFloppyInstructions; // Show the floppy, as opposed to CD, instructions // data structure used by show me links HINSTANCE hinstMSHTML; SHOWHTMLDIALOGEXFN * pfnShowHTMLDialog; IHTMLWindow2 * showMeDlgWnd, * pFrameWindow; // Network Connection folder and folder view call back. Used by Connection List Views. IShellFolder *_psfConnections; IShellFolderViewCB *_pConnViewCB; struct PUBLICCONTROLPOSITIONS { RECT _rcSelectMessage; RECT _rcListLabel; RECT _rcList; RECT _rcHelpIcon; RECT _rcHelpText; } PublicControlPositions; }; int FreeConnectionDPACallback(LPVOID pFreeMe, LPVOID pData) { ((INetConnection*) pFreeMe)->Release(); return 1; } void InitHnetInfo(HOMENETSETUPINFO* pInfo) { ZeroMemory(pInfo, sizeof (HOMENETSETUPINFO)); pInfo->cbSize = sizeof (HOMENETSETUPINFO); pInfo->ipaExternal = -1; pInfo->ipaInternal = -1; } // Creation function HRESULT HomeNetworkWizard_RunFromRegistry(HWND hwnd, BOOL* pfRebootRequired) { HOMENETSETUPINFO setupInfo; InitHnetInfo(&setupInfo); HRESULT hr = ReadSetupInfoFromRegistry(&setupInfo); if (S_OK == hr) { setupInfo.dwFlags = HNET_SHAREPRINTERS | HNET_SHAREFOLDERS; setupInfo.hwnd = hwnd; hr = ConfigureHomeNetwork(&setupInfo); *pfRebootRequired = setupInfo.fRebootRequired; } DeleteSetupInfoFromRegistry(); return hr; } HRESULT HomeNetworkWizard_ShowWizard(HWND hwnd, BOOL* pfRebootRequired) { if (*pfRebootRequired) *pfRebootRequired = FALSE; HRESULT hr = HomeNetworkWizard_RunFromRegistry(hwnd, pfRebootRequired); if (S_FALSE == hr) { IUnknown* punk; hr = CHomeNetworkWizard_CreateInstance(NULL, &punk, NULL); if (SUCCEEDED(hr)) { IHomeNetworkWizard* pwizard; hr = punk->QueryInterface(IID_PPV_ARG(IHomeNetworkWizard, &pwizard)); if (SUCCEEDED(hr)) { hr = pwizard->ShowWizard(hwnd, pfRebootRequired); pwizard->Release(); } punk->Release(); } } return hr; } HRESULT CHomeNetworkWizard_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { *ppunk = NULL; if (punkOuter) return CLASS_E_NOAGGREGATION; CHomeNetworkWizard* pwiz = new CHomeNetworkWizard(); if (!pwiz) return E_OUTOFMEMORY; HRESULT hr = pwiz->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); pwiz->Release(); return hr; } // IUnknown HRESULT CHomeNetworkWizard::QueryInterface(REFIID riid, LPVOID* ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IHomeNetworkWizard)) { AddRef(); *ppvObj = static_cast(this); } else { *ppvObj = NULL; } return *ppvObj ? S_OK : E_NOINTERFACE; } ULONG CHomeNetworkWizard::AddRef() { return (ULONG) InterlockedIncrement(&_cRef); } ULONG CHomeNetworkWizard::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; } HRESULT CHomeNetworkWizard::GetConnectionByName(LPCWSTR pszName, INetConnection** ppncOut) { *ppncOut = NULL; DWORD cItems = DPA_GetPtrCount(_hdpaConnections); DWORD iItem = 0; while ((iItem < cItems) && (NULL == *ppncOut)) { INetConnection* pnc = (INetConnection*) DPA_GetPtr(_hdpaConnections, iItem); NETCON_PROPERTIES* pncprops; HRESULT hr = pnc->GetProperties(&pncprops); if (SUCCEEDED(hr)) { if (0 == StrCmpIW(pszName, pncprops->pszwName)) { *ppncOut = pnc; (*ppncOut)->AddRef(); } NcFreeNetconProperties(pncprops); } iItem ++; } return (*ppncOut) ? S_OK : E_FAIL; } HRESULT CHomeNetworkWizard::GetInternalConnectionArray(INetConnection* pncExclude, INetConnection*** pprgncArray, DWORD* pcncArray) { HRESULT hr = S_OK; *pprgncArray = NULL; DWORD cTotalConnections = DPA_GetPtrCount(_hdpaConnections); DWORD cInternalConnections = GetConnectionCount(pncExclude, CONN_INTERNAL); if (cInternalConnections) { (*pprgncArray) = (INetConnection**) LocalAlloc(LPTR, (cInternalConnections + 1) * sizeof (INetConnection*)); // Note that we allocated an extra entry since this is a null-terminated array if (*pprgncArray) { DWORD nInternalConnection = 0; for (DWORD n = 0; n < cTotalConnections; n++) { INetConnection* pnc = (INetConnection*) DPA_GetPtr(_hdpaConnections, n); if (ShouldShowConnection(pnc, pncExclude, CONN_INTERNAL)) { pnc->AddRef(); (*pprgncArray)[nInternalConnection++] = pnc; } } ASSERT(nInternalConnection == cInternalConnections); } else { hr = E_OUTOFMEMORY; } } if (SUCCEEDED(hr)) { *pcncArray = cInternalConnections; } return hr; } HRESULT CHomeNetworkWizard::ConfigureSilently(LPCWSTR pszPublicConnection, DWORD hnetFlags, BOOL* pfRebootRequired) { // Never set workgroup name hnetFlags &= (~HNET_SETWORKGROUPNAME); if (!g_fRunningOnNT) return E_NOTIMPL; HRESULT hr = Initialize(); if (SUCCEEDED(hr)) { _hnetInfo.dwFlags = hnetFlags; // Calculate what the external and internal adapters will be... if (pszPublicConnection) { hr = GetConnectionByName(pszPublicConnection, &_hnetInfo.pncExternal); } else { _hnetInfo.pncExternal = NULL; } if (SUCCEEDED(hr)) { // Get all LAN connections except the public connection if (_hnetInfo.dwFlags & HNET_BRIDGEPRIVATE) { hr = GetInternalConnectionArray(_hnetInfo.pncExternal, &(_hnetInfo.prgncInternal), &_hnetInfo.cncInternal); } if (SUCCEEDED(hr)) { hr = ConfigureHomeNetwork(&_hnetInfo); *pfRebootRequired = _hnetInfo.fRebootRequired; } } Uninitialize(); } return hr; } CHomeNetworkWizard::CHomeNetworkWizard() : _cRef(1) {} HRESULT CHomeNetworkWizard::Initialize() { _fExternalOnly = FALSE; _fNoICSQuestion = FALSE; _hdpaConnections = NULL; _iPageStackTop = 0; _fManualBridgeConfig = FALSE; _fICSClient = FALSE; _psfConnections = NULL; _pConnViewCB = NULL; InitHnetInfo(&_hnetInfo); *_szICSMachineName = 0; HRESULT hr; if (g_fRunningOnNT) { hr = GetConnections(&_hdpaConnections); } else { _hnetInfo.cNA = EnumCachedNetAdapters(&_hnetInfo.pNA); hr = S_OK; if ( _hnetInfo.cNA > 0 ) { _hnetInfo.ipaInternal = 0; } } // Get the shell image lists - never free these if (!Shell_GetImageLists(&_himlLarge, &_himlSmall)) { hr = E_FAIL; } // variables used by displaying show me links hinstMSHTML = NULL; pfnShowHTMLDialog = NULL; showMeDlgWnd = NULL; pFrameWindow = NULL; return hr; } HRESULT CHomeNetworkWizard::Uninitialize() { if (g_fRunningOnNT) { if (_hdpaConnections) { DPA_DestroyCallback(_hdpaConnections, FreeConnectionDPACallback, NULL); _hdpaConnections = NULL; } // Free public lan information FreeExternalConnection(&_hnetInfo); // Free private lan information FreeInternalConnections(&_hnetInfo); if (_psfConnections != NULL) _psfConnections->Release(); if (_pConnViewCB != NULL) _pConnViewCB->Release(); } else { if (_hnetInfo.pNA) { FlushNetAdapterCache(); _hnetInfo.pNA = NULL; } if (_hnetInfo.pRas) { LocalFree(_hnetInfo.pRas); _hnetInfo.pRas = NULL; } } // release resources used by show me links if (hinstMSHTML) FreeLibrary(hinstMSHTML); if (showMeDlgWnd != NULL) showMeDlgWnd->Release(); if (pFrameWindow != NULL) pFrameWindow->Release(); return S_OK; } // TODO: Move the formatting functions here to a util file or something... BOOL FormatMessageString(UINT idTemplate, LPTSTR pszStrOut, DWORD cchSize, ...) { BOOL fResult = FALSE; va_list vaParamList; TCHAR szFormat[1024]; if (LoadString(g_hinst, idTemplate, szFormat, ARRAYSIZE(szFormat))) { va_start(vaParamList, cchSize); fResult = FormatMessage(FORMAT_MESSAGE_FROM_STRING, szFormat, 0, 0, pszStrOut, cchSize, &vaParamList); va_end(vaParamList); } return fResult; } int DisplayFormatMessage(HWND hwnd, UINT idCaption, UINT idFormatString, UINT uType, ...) { int iResult = IDCANCEL; TCHAR szError[512]; *szError = 0; TCHAR szCaption[256]; TCHAR szFormat[512]; *szFormat = 0; // Load and format the error body if (LoadString(g_hinst, idFormatString, szFormat, ARRAYSIZE(szFormat))) { va_list arguments; va_start(arguments, uType); if (FormatMessage(FORMAT_MESSAGE_FROM_STRING, szFormat, 0, 0, szError, ARRAYSIZE(szError), &arguments)) { // Load the caption if (LoadString(g_hinst, idCaption, szCaption, ARRAYSIZE(szCaption))) { iResult = MessageBox(hwnd, szError, szCaption, uType); } } va_end(arguments); } return iResult; } BOOL CHomeNetworkWizard::GetICSMachine(LPTSTR pszICSMachineName, DWORD cch) { #ifdef FAKE_ICS lstrcpyn(pszICSMachineName, L"COMPNAME", cch); return TRUE; #endif SetCursor(LoadCursor(NULL, IDC_WAIT)); BOOL fICSInstalled = FALSE; HRESULT hr = S_OK; INetConnectionManager* pSharedAccessConnectionManager; hr = CoCreateInstance(CLSID_SharedAccessConnectionManager, NULL, CLSCTX_LOCAL_SERVER, IID_INetConnectionManager, reinterpret_cast(&pSharedAccessConnectionManager)); if(SUCCEEDED(hr)) { IEnumNetConnection* pEnumerator; hr = pSharedAccessConnectionManager->EnumConnections(NCME_DEFAULT, &pEnumerator); if(SUCCEEDED(hr)) { INetConnection* pNetConnection; ULONG ulFetched; hr = pEnumerator->Next(1, &pNetConnection, &ulFetched); // HNW only cares about >= 1 beacon if(SUCCEEDED(hr) && 1 == ulFetched) { fICSInstalled = TRUE; // found the beacon, now recover the machine name if supported INetSharedAccessConnection* pNetSharedAccessConnection; hr = pNetConnection->QueryInterface(IID_INetSharedAccessConnection, reinterpret_cast(&pNetSharedAccessConnection)); if(SUCCEEDED(hr)) { IUPnPService* pOSInfoService; hr = pNetSharedAccessConnection->GetService(SAHOST_SERVICE_OSINFO, &pOSInfoService); if(SUCCEEDED(hr)) { VARIANT Variant; VariantInit(&Variant); BSTR VariableName; VariableName = SysAllocString(L"OSMachineName"); if(NULL != VariableName) { hr = pOSInfoService->QueryStateVariable(VariableName, &Variant); if(SUCCEEDED(hr)) { if(V_VT(&Variant) == VT_BSTR) { lstrcpyn(pszICSMachineName, V_BSTR(&Variant), cch); } else { hr = E_UNEXPECTED; } VariantClear(&Variant); } SysFreeString(VariableName); } else { hr = E_OUTOFMEMORY; } pOSInfoService->Release(); } pNetSharedAccessConnection->Release(); } if(FAILED(hr)) { if (!LoadString(g_hinst, IDS_UNIDENTIFIED_ICS_DEVICE, pszICSMachineName, cch)) *pszICSMachineName = TEXT('\0'); } pNetConnection->Release(); } pEnumerator->Release(); } pSharedAccessConnectionManager->Release(); } return fICSInstalled; } void CHomeNetworkWizard::InitializeConnectionList(HWND hwndList, DWORD dwFlags) { // Set up the columns of the list LVCOLUMN lvc; lvc.mask = LVCF_SUBITEM | LVCF_WIDTH; lvc.iSubItem = 0; lvc.cx = 10; ListView_InsertColumn(hwndList, 0, &lvc); lvc.iSubItem = 1; lvc.cx = 10; ListView_InsertColumn(hwndList, 1, &lvc); DWORD dwStyles = LVS_EX_FULLROWSELECT; if (dwFlags & CONN_INTERNAL) dwStyles |= LVS_EX_CHECKBOXES; // Consider disabling the list or something for CONN_UNPLUGGED ListView_SetExtendedListViewStyleEx(hwndList, dwStyles, dwStyles); ListView_SetImageList(hwndList, _himlSmall, LVSIL_SMALL); _psfConnections = NULL; _pConnViewCB = NULL; if (g_fRunningOnNT) { HRESULT hr = GetConnectionsFolder(&_psfConnections); if (SUCCEEDED(hr)) { IShellView *pConnView = NULL; hr = _psfConnections->CreateViewObject(hwndList, IID_IShellView, reinterpret_cast(&pConnView)); if (SUCCEEDED(hr)) { hr = _psfConnections->QueryInterface(IID_IShellFolderViewCB, reinterpret_cast(&_pConnViewCB)); if (SUCCEEDED(hr)) { HWND hWndParent = GetParent(hwndList); hr = _pConnViewCB->MessageSFVCB(SFVM_HWNDMAIN, NULL, reinterpret_cast(hWndParent)); } } if (pConnView != NULL) pConnView->Release(); } } } BOOL CHomeNetworkWizard::IsConnectionUnplugged(INetConnection* pnc) { BOOL fUnplugged = FALSE; if ( g_fRunningOnNT ) { HRESULT hr; NETCON_PROPERTIES* pncprops; hr = pnc->GetProperties(&pncprops); if (SUCCEEDED(hr)) { ASSERT(pncprops); fUnplugged = (NCS_MEDIA_DISCONNECTED == pncprops->Status); NcFreeNetconProperties(pncprops); } } return fUnplugged; } BOOL CHomeNetworkWizard::ShouldShowConnection(INetConnection* pnc, INetConnection* pncExcludeFromList, DWORD dwFlags) { BOOL fShow = FALSE; if (!IsEqualConnection(pnc, pncExcludeFromList)) { NETCON_PROPERTIES* pprops; HRESULT hr = pnc->GetProperties(&pprops); // Is this the kind of connection we want to show based on whether its external or internal list? if (SUCCEEDED(hr)) { // Note: The bridge is a virtual and not a real connection. If it exists, it will have // NCM_BRIDGE, and so it won't get shown here, which is correct. if (dwFlags & CONN_EXTERNAL) { if ((pprops->MediaType == NCM_LAN) || (pprops->MediaType == NCM_PHONE) || (pprops->MediaType == NCM_TUNNEL) || (pprops->MediaType == NCM_ISDN) || (pprops->MediaType == NCM_PPPOE)) { fShow = TRUE; } } if (dwFlags & CONN_INTERNAL) { if (pprops->MediaType == NCM_LAN) { // Note: In this case pncExcludeFromList is the shared adapter. // If this is a VPN(NCM_TUNNEL) connection then we want to make // sure its pszPrerequisiteEntry is connected. BOOL fAssociated; HRESULT hr; hr = HrConnectionAssociatedWithSharedConnection( pnc, pncExcludeFromList, &fAssociated ); if ( SUCCEEDED(hr) ) { fShow = !fAssociated; } else { fShow = TRUE; } } } if (dwFlags & CONN_UNPLUGGED) { if (IsConnectionUnplugged(pnc)) { fShow = TRUE; } } NcFreeNetconProperties(pprops); } } return fShow; } BOOL CHomeNetworkWizard::IsConnectionICSPublic(INetConnection* pnc) { BOOL fShared = FALSE; NETCON_PROPERTIES* pprops; HRESULT hr = pnc->GetProperties(&pprops); // Is this the kind of connection we want to show based on whether its external or internal list? if (SUCCEEDED(hr)) { // Note: Don't check pprops->MediaType == NCM_SHAREDACCESSHOST. SHAREDACCESSHOST is the connectoid // representing a host's shared connection from the point of view of an ICS client, and not what we're // interested in. if (pprops->dwCharacter & NCCF_SHARED) { fShared = TRUE; } NcFreeNetconProperties(pprops); } return fShared; } void CHomeNetworkWizard::FillConnectionList(HWND hwndList, INetConnection* pncExcludeFromList, DWORD dwFlags) { DestroyConnectionList(hwndList); BOOL fSelected = FALSE; // Has an entry in the list been selected if (g_fRunningOnNT) { HRESULT hr = 0; if (_pConnViewCB != NULL) _pConnViewCB->MessageSFVCB(DVM_REFRESH, TRUE, TRUE); if (SUCCEEDED(hr)) { // Enumerate each net connection DWORD cItems = DPA_GetPtrCount(_hdpaConnections); for (DWORD iItem = 0; iItem < cItems; iItem ++) { INetConnection* pnc = (INetConnection*) DPA_GetPtr(_hdpaConnections, iItem); ASSERT(pnc); // Is this the kind of connection we want to show? if (ShouldShowConnection(pnc, pncExcludeFromList, dwFlags)) { NETCON_PROPERTIES* pncprops; hr = pnc->GetProperties(&pncprops); if (SUCCEEDED(hr)) { LVITEM lvi = {0}; if ((dwFlags & CONN_EXTERNAL) && fSelected) { // If we have a default public adapter, insert other adapters // after it so the default appears at the top of the list. lvi.iItem = 1; } lvi.mask = LVIF_PARAM | LVIF_TEXT; lvi.pszText = pncprops->pszwName; lvi.lParam = (LPARAM) pnc; // We addref this guy when/if we actually add this item // Get the icon index for this connection int iIndex; hr = GetConnectionIconIndex(pncprops->guidId, _psfConnections, &iIndex); if (SUCCEEDED(hr)) { lvi.iImage = iIndex; if (-1 != lvi.iImage) lvi.mask |= LVIF_IMAGE; } // Its ok if the icon stuff failed for now hr = S_OK; int iItem = ListView_InsertItem(hwndList, &lvi); if (-1 != iItem) { pnc->AddRef(); ListView_SetItemText(hwndList, iItem, 1, pncprops->pszwDeviceName); if (dwFlags & CONN_EXTERNAL) { // Select the connection that is already ICS public, if applicable, or // Use network location awareness to guess at a connection type - TODO if (pncprops->dwCharacter & NCCF_SHARED || NLA_INTERNET_YES == GetConnectionInternetType(&pncprops->guidId)) { ListView_SetItemState(hwndList, iItem, LVIS_SELECTED, LVIS_SELECTED); fSelected = TRUE; } } if (dwFlags & CONN_INTERNAL) { ListView_SetItemState(hwndList, iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK); fSelected = TRUE; } } NcFreeNetconProperties(pncprops); } } } } } else { if (_hnetInfo.cNA && _hnetInfo.pNA) { const NETADAPTER* pNA = _hnetInfo.pNA; for (UINT i = 0; i < _hnetInfo.cNA; i++, pNA++) { // Check if the NIC is working. if (W9xIsValidAdapter(pNA, dwFlags)) { fSelected = W9xAddAdapterToList(pNA, pNA->szDisplayName, i, 0, hwndList, dwFlags); } else if (W9xIsAdapterDialUp(pNA)) { _hnetInfo.cRas = W9xEnumRasEntries(); for (UINT j = 0; j < _hnetInfo.cRas; j++) { // W9xAddAdapterToList ALWAYS adds the adapter regardless of the // state of the connection. So we do not have the equivalent of // the Whistler "ShouldShowConnection". Here we need to check // the flags to exclude listing inappropriate adapters. if ( ~CONN_UNPLUGGED & dwFlags ) // Never show RAS Entry's as Unplugged { fSelected = W9xAddAdapterToList( pNA, _hnetInfo.pRas[j].szEntryName, i, j, hwndList, dwFlags ); } } } } } } ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE); ListView_SetColumnWidth(hwndList, 1, LVSCW_AUTOSIZE); } BOOL CHomeNetworkWizard::W9xAddAdapterToList(const NETADAPTER* pNA, const WCHAR* pszDesc, UINT uiAdapterIndex, UINT uiDialupIndex, HWND hwndList, DWORD dwFlags) { BOOL fSelected = FALSE; LVITEM lvi = {0}; lvi.mask = LVIF_PARAM | LVIF_TEXT; WCHAR szNicType[MAX_PATH]; W9xGetNetTypeName(pNA->bNetType, szNicType, ARRAYSIZE(szNicType)); lvi.pszText = szNicType; lvi.lParam = MAKELONG(LOWORD(uiAdapterIndex), LOWORD(uiDialupIndex)); int iItem = ListView_InsertItem(hwndList, &lvi); if (-1 != iItem) { ListView_SetItemText(hwndList, iItem, 1, (LPWSTR)pszDesc); if (dwFlags & CONN_EXTERNAL) { if (NETTYPE_DIALUP == pNA->bNetType || NETTYPE_PPTP == pNA->bNetType || NETTYPE_ISDN == pNA->bNetType ) { ListView_SetItemState(hwndList, iItem, LVIS_SELECTED, LVIS_SELECTED); fSelected = TRUE; } } if (dwFlags & CONN_INTERNAL) { if (NETTYPE_LAN == pNA->bNetType || NETTYPE_IRDA == pNA->bNetType || // ISSUE-2000/05/31-edwardp: Internal? NETTYPE_TV == pNA->bNetType ) // ISSUE-2000/05/31-edwardp: Internal? { ListView_SetItemState(hwndList, iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK); fSelected = TRUE; } } } return fSelected; } UINT CHomeNetworkWizard::W9xEnumRasEntries() { UINT uiRet = 0; if (!_hnetInfo.pRas) { DWORD cDUNs = 0; DWORD cb = 0; RasEnumEntries(NULL, NULL, NULL, &cb, &cDUNs); if (cb > 0) { _hnetInfo.pRas = (RASENTRYNAME*)LocalAlloc(LPTR, cb); if (_hnetInfo.pRas) { _hnetInfo.pRas->dwSize = sizeof(RASENTRYNAME); if (RasEnumEntries(NULL, NULL, _hnetInfo.pRas, &cb, &cDUNs) == 0) { uiRet = cDUNs; } } } } return uiRet; } typedef struct { LPCWSTR idPage; DLGPROC pDlgProc; LPCWSTR pHeading; LPCWSTR pSubHeading; DWORD dwFlags; } WIZPAGE; #define MAKEWIZPAGE(name, dlgproc, dwFlags) \ { MAKEINTRESOURCE(IDD_WIZ_##name##), dlgproc, MAKEINTRESOURCE(IDS_HEADER_##name##), MAKEINTRESOURCE(IDS_SUBHEADER_##name##), dwFlags } INT_PTR MyPropertySheet(LPCPROPSHEETHEADER pHeader); HPROPSHEETPAGE MyCreatePropertySheetPage(LPPROPSHEETPAGE psp); HRESULT DoesUserHaveHNetPermissions(BOOL* pfHasPermission) { HRESULT hr; if (g_fRunningOnNT) { // TODO: We need to check this stuff in once the net team RI's INetConnectionUiUtilities* pNetConnUiUtil; *pfHasPermission = FALSE; hr = CoCreateInstance(CLSID_NetConnectionUiUtilities, NULL, CLSCTX_INPROC, IID_PPV_ARG(INetConnectionUiUtilities, &pNetConnUiUtil)); if (SUCCEEDED(hr)) { if (pNetConnUiUtil->UserHasPermission(NCPERM_ShowSharedAccessUi) && #if 0 // NYI pNetConnUiUtil->UserHasPermission(NCPERM_AllowNetBridge_NLA) && #endif pNetConnUiUtil->UserHasPermission(NCPERM_ICSClientApp) && pNetConnUiUtil->UserHasPermission(NCPERM_PersonalFirewallConfig)) { *pfHasPermission = TRUE; } pNetConnUiUtil->Release(); } else { TraceMsg(TF_WARNING, "Could not cocreate CLSID_NetConnectionUIUtilities"); } } else { // Windows 9x *pfHasPermission = TRUE; hr = S_OK; } return hr; } BOOL CHomeNetworkWizard::IsMachineOnDomain() { BOOL fDomain = FALSE; #ifdef NO_CHECK_DOMAIN return fDomain; #endif NETSETUP_JOIN_STATUS njs; // // Make sure to initialize pszName to NULL. On W9x NetJoinInformation returns NERR_Success // but doesn't allocate pszName. On retail builds the stack garbage in pszName happened to // be the this pointer for CHomeNetworkWizard and NetApiBufferFreeWrap called LocalFree // on it. // LPWSTR pszName = NULL; // init to NULL! See comment above. if (NERR_Success == NetGetJoinInformation(NULL, &pszName, &njs)) { fDomain = (NetSetupDomainName == njs); NetApiBufferFree(pszName); } return fDomain; } BOOL CHomeNetworkWizard::IsMachineWrongOS() { BOOL fWrongOS = TRUE; if (IsOS(OS_WINDOWS)) { if (IsOS(OS_WIN98ORGREATER)) { fWrongOS = FALSE; } } else { if (IsOS(OS_WHISTLERORGREATER)) { fWrongOS = FALSE; } } return fWrongOS; } // The page indices for the possible start pages (three error and one real start page) #define PAGE_NOTADMIN 0 #define PAGE_NOPERMISSIONS 1 #define PAGE_NOHARDWARE 2 #define PAGE_WRONGOS 3 #define PAGE_DOMAIN 4 #define PAGE_WELCOME 5 #define PAGE_CONNECT 9 #define PAGE_FINISH 25 HRESULT CHomeNetworkWizard::ShowWizard(HWND hwnd, BOOL* pfRebootRequired) { HRESULT hr = S_OK; TCHAR szCaption[256]; LoadString(g_hinst, IDS_WIZ_CAPTION, szCaption, ARRAYSIZE(szCaption)); CEnsureSingleInstance ESI(szCaption); if (!ESI.ShouldExit()) { if (g_fRunningOnNT) { LinkWindow_RegisterClass_NT(); } *pfRebootRequired = FALSE; hr = Initialize(); if (SUCCEEDED(hr)) { WIZPAGE c_wpPages[] = { // Error start pages MAKEWIZPAGE(NOTADMIN, CantRunWizardPageProc, PSP_HIDEHEADER), MAKEWIZPAGE(NOPERMISSIONS, CantRunWizardPageProc, PSP_HIDEHEADER), MAKEWIZPAGE(NOHARDWARE, NoHardwareWelcomePageProc, PSP_HIDEHEADER), MAKEWIZPAGE(WRONGOS, CantRunWizardPageProc, PSP_HIDEHEADER), MAKEWIZPAGE(DOMAINWELCOME, CantRunWizardPageProc, PSP_HIDEHEADER), // Real start page MAKEWIZPAGE(WELCOME, WelcomePageProc, PSP_HIDEHEADER), MAKEWIZPAGE(MANUALCONFIG, ManualConfigPageProc, 0), MAKEWIZPAGE(UNPLUGGED, UnpluggedPageProc, 0), MAKEWIZPAGE(FOUNDICS, FoundIcsPageProc, 0), MAKEWIZPAGE(CONNECT, ConnectPageProc, 0), MAKEWIZPAGE(CONNECTOTHER, ConnectOtherPageProc, 0), MAKEWIZPAGE(PUBLIC, PublicPageProc, 0), MAKEWIZPAGE(EDGELESS, EdgelessPageProc, 0), MAKEWIZPAGE(ICSCONFLICT, ICSConflictPageProc, 0), MAKEWIZPAGE(BRIDGEWARNING, BridgeWarningPageProc, 0), MAKEWIZPAGE(PRIVATE, PrivatePageProc, 0), MAKEWIZPAGE(NAME, NamePageProc, 0), MAKEWIZPAGE(WORKGROUP, WorkgroupPageProc, 0), MAKEWIZPAGE(SUMMARY, SummaryPageProc, 0), MAKEWIZPAGE(PROGRESS, ProgressPageProc, 0), MAKEWIZPAGE(ALMOSTDONE, AlmostDonePageProc, 0), MAKEWIZPAGE(CHOOSEDISK, ChooseDiskPageProc, 0), MAKEWIZPAGE(INSERTDISK, InsertDiskPageProc, 0), MAKEWIZPAGE(FLOPPYINST, InstructionsPageProc, 0), MAKEWIZPAGE(CDINST, InstructionsPageProc, 0), MAKEWIZPAGE(FINISH, FinishPageProc, PSP_HIDEHEADER), MAKEWIZPAGE(CONFIGERROR, ErrorFinishPageProc, PSP_HIDEHEADER), MAKEWIZPAGE(NOHARDWAREFINISH, NoHardwareFinishPageProc, PSP_HIDEHEADER), }; // Sanity check to make sure we haven't added new error pages without updating the // welcome page number ASSERT(c_wpPages[PAGE_WELCOME].idPage == MAKEINTRESOURCE(IDD_WIZ_WELCOME)); ASSERT(c_wpPages[PAGE_CONNECT].idPage == MAKEINTRESOURCE(IDD_WIZ_CONNECT)); ASSERT(c_wpPages[PAGE_FINISH].idPage == MAKEINTRESOURCE(IDD_WIZ_FINISH)); if (!g_fRunningOnNT) { c_wpPages[PAGE_WELCOME].idPage = MAKEINTRESOURCE(IDD_WIZ_WIN9X_WELCOME); c_wpPages[PAGE_FINISH].idPage = MAKEINTRESOURCE(IDD_WIZ_WIN9X_FINISH); CICSInst* pICS = new CICSInst; if (pICS) { if (!pICS->IsInstalled()) { c_wpPages[PAGE_CONNECT].idPage = MAKEINTRESOURCE(IDD_WIZ_WIN9X_CONNECT); _fNoICSQuestion = TRUE; } delete pICS; } } HPROPSHEETPAGE rghpage[MAX_HNW_PAGES]; int cPages; for (cPages = 0; cPages < ARRAYSIZE(c_wpPages); cPages ++) { PROPSHEETPAGE psp = { 0 }; psp.dwSize = SIZEOF(PROPSHEETPAGE); psp.hInstance = g_hinst; psp.lParam = (LPARAM)this; psp.dwFlags = PSP_USETITLE | PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | c_wpPages[cPages].dwFlags; psp.pszTemplate = c_wpPages[cPages].idPage; psp.pfnDlgProc = c_wpPages[cPages].pDlgProc; psp.pszTitle = MAKEINTRESOURCE(IDS_WIZ_CAPTION); psp.pszHeaderTitle = c_wpPages[cPages].pHeading; psp.pszHeaderSubTitle = c_wpPages[cPages].pSubHeading; rghpage[cPages] = MyCreatePropertySheetPage(&psp); } ASSERT(cPages < MAX_HNW_PAGES); PROPSHEETHEADER psh = { 0 }; psh.dwSize = SIZEOF(PROPSHEETHEADER); psh.hwndParent = hwnd; psh.hInstance = g_hinst; psh.dwFlags = PSH_USEICONID | PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK | PSH_STRETCHWATERMARK | PSH_HEADER; psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); psh.nPages = cPages; psh.phpage = rghpage; psh.pszIcon = MAKEINTRESOURCE(IDI_APPICON); // Check for administrator and policy (permissions) BOOL fUserIsAdmin = FALSE; BOOL fUserHasPermissions = FALSE; IsUserLocalAdmin(NULL, &fUserIsAdmin); DoesUserHaveHNetPermissions(&fUserHasPermissions); if (!fUserIsAdmin) { // Not admin error page psh.nStartPage = PAGE_NOTADMIN; } else if (!fUserHasPermissions) { // No permissions error page psh.nStartPage = PAGE_NOPERMISSIONS; } else if (GetConnectionCount(NULL, CONN_INTERNAL) < 1) { if ( g_fRunningOnNT && ( GetConnectionCount(NULL, CONN_EXTERNAL) > 0 ) ) { TraceMsg(TF_WARNING, "External Adapters Only"); psh.nStartPage = PAGE_WELCOME; _fExternalOnly = TRUE; } else { // No hardware error page psh.nStartPage = PAGE_NOHARDWARE; } } else if (IsMachineWrongOS()) { psh.nStartPage = PAGE_WRONGOS; } else if (IsMachineOnDomain()) { psh.nStartPage = PAGE_DOMAIN; } else { // Run the real wizard psh.nStartPage = PAGE_WELCOME; } INT_PTR iReturn = MyPropertySheet(&psh); *pfRebootRequired = ((iReturn == ID_PSRESTARTWINDOWS) || (iReturn == ID_PSREBOOTSYSTEM)); Uninitialize(); } } return hr; } void GetTitleFont(LPTSTR pszFaceName, DWORD cch) { if (!LoadString(g_hinst, IDS_TITLE_FONT, pszFaceName, cch)) { lstrcpyn(pszFaceName, TEXT("Verdana"), cch); } } LONG GetTitlePointSize() { LONG lPointSize = 0; TCHAR szPointSize[20]; if (LoadString(g_hinst, IDS_TITLE_POINTSIZE, szPointSize, ARRAYSIZE(szPointSize))) { lPointSize = StrToInt(szPointSize); } if (!lPointSize) { lPointSize = 12; } return lPointSize; } void CHomeNetworkWizard::WelcomeSetTitleFont(HWND hwnd) { HWND hwndTitle = GetDlgItem(hwnd, IDC_TITLE); // Get the existing font HFONT hfontOld = (HFONT) SendMessage(hwndTitle, WM_GETFONT, 0, 0); LOGFONT lf = {0}; if (GetObject(hfontOld, sizeof(lf), &lf)) { GetTitleFont(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName)); HDC hDC = GetDC(hwndTitle); if (hDC) { lf.lfHeight = -MulDiv(GetTitlePointSize(), GetDeviceCaps(hDC, LOGPIXELSY), 72); lf.lfWeight = FW_BOLD; HFONT hfontNew = CreateFontIndirect(&lf); if (hfontNew) { SendMessage(hwndTitle, WM_SETFONT, (WPARAM) hfontNew, FALSE); // Don't do this, its shared. // DeleteObject(hfontOld); } ReleaseDC(hwndTitle, hDC); } } LONG lStyle = GetWindowLong(GetParent(hwnd), GWL_STYLE); SetWindowLong(GetParent(hwnd), GWL_STYLE, lStyle & ~WS_SYSMENU); } INT_PTR CHomeNetworkWizard::WelcomePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->WelcomeSetTitleFont(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_NEXT); return TRUE; case PSN_WIZNEXT: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_MANUALCONFIG); if (!g_fRunningOnNT) pthis->PushPage(IDD_WIZ_WIN9X_WELCOME); else pthis->PushPage(IDD_WIZ_WELCOME); return TRUE; } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::NoHardwareWelcomePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->WelcomeSetTitleFont(hwnd); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_HARDWAREREQ); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, 0); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_requirements.htm"); } return TRUE; } } } return FALSE; } return FALSE; } void CHomeNetworkWizard::ReplaceStaticWithLink(HWND hwndStatic, UINT idcLinkControl, UINT idsLinkText) { if (g_fRunningOnNT) { RECT rcStatic; HWND hwndParent = GetParent(hwndStatic); if (GetWindowRect(hwndStatic, &rcStatic) && MapWindowPoints(NULL, hwndParent, (LPPOINT) &rcStatic, 2)) { WCHAR szLinkText[256]; if (LoadString(g_hinst, idsLinkText, szLinkText, ARRAYSIZE(szLinkText))) { HWND hwndLink = CreateWindowEx(0, TEXT("SysLink"), szLinkText, WS_CHILD | WS_TABSTOP | LWS_IGNORERETURN, rcStatic.left, rcStatic.top, (rcStatic.right - rcStatic.left), (rcStatic.bottom - rcStatic.top), hwndParent, NULL, g_hinst, NULL); if (hwndLink) { SetWindowLongPtr(hwndLink, GWLP_ID, (LONG_PTR) idcLinkControl); ShowWindow(hwndLink, SW_SHOW); ShowWindow(hwndStatic, SW_HIDE); } } } } } void CHomeNetworkWizard::ManualRefreshConnectionList() { if (g_fRunningOnNT) { // Refresh connection DPA in case the user plugged in more connections HDPA hdpaConnections2; if (SUCCEEDED(GetConnections(&hdpaConnections2))) { // Replace the real list with our new one DPA_DestroyCallback(_hdpaConnections, FreeConnectionDPACallback, NULL); _hdpaConnections = hdpaConnections2; // Ensure we remove our other holds to the INetConnections // Free public lan information FreeExternalConnection(&_hnetInfo); // Free private lan information FreeInternalConnections(&_hnetInfo); } } } INT_PTR CHomeNetworkWizard::ManualConfigPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_INSTALLATION); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); return TRUE; case PSN_WIZNEXT: // pthis->ManualRefreshConnectionList(); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_UNPLUGGED); pthis->PushPage(IDD_WIZ_MANUALCONFIG); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { if (IsOS(OS_PERSONAL)) { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_checklistP.htm"); } else { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_checklistW.htm"); } } return TRUE; } } } return FALSE; } return FALSE; } // Returns TRUE if there are some unplugged connections, FALSE o/w BOOL CHomeNetworkWizard::UnpluggedFillList(HWND hwnd) { BOOL fSomeUnpluggedConnections = FALSE; HWND hwndList = GetDlgItem(hwnd, IDC_CONNLIST); FillConnectionList(hwndList, NULL, CONN_UNPLUGGED); // and if there actually are unplugged connections... if (0 != ListView_GetItemCount(hwndList)) { // Show this page fSomeUnpluggedConnections = TRUE; } return fSomeUnpluggedConnections; } INT_PTR CHomeNetworkWizard::UnpluggedPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->InitializeConnectionList(GetDlgItem(hwnd, IDC_CONNLIST), CONN_UNPLUGGED); SendDlgItemMessage(hwnd, IDC_IGNORE, BM_SETCHECK, BST_UNCHECKED, 0); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { // If we don't need to show this page if (!pthis->UnpluggedFillList(hwnd)) { // Don't push ourselves on the stack // But navigate to the next page... SetWindowLongPtr( hwnd, DWLP_MSGRESULT, (pthis->_fExternalOnly) ? IDD_WIZ_CONNECTOTHER : IDD_WIZ_FOUNDICS ); } } return TRUE; case PSN_WIZNEXT: { BOOL fStillUnplugged = pthis->UnpluggedFillList(hwnd); int idNext; if (!fStillUnplugged) { // User fixed the problem. Go forward and don't store this // error page on the pagestack idNext = (pthis->_fExternalOnly) ? IDD_WIZ_CONNECTOTHER : IDD_WIZ_FOUNDICS; } else if (BST_CHECKED == SendDlgItemMessage(hwnd, IDC_IGNORE, BM_GETCHECK, 0, 0)) { // User wants to go on, but store this page on the pagestack // so they can "back" up to it. pthis->PushPage(IDD_WIZ_UNPLUGGED); idNext = (pthis->_fExternalOnly) ? IDD_WIZ_CONNECTOTHER : IDD_WIZ_FOUNDICS; } else { // User still has disconnected net hardware they don't want to ignore. Tell them and keep them on this page. DisplayFormatMessage(hwnd, IDS_WIZ_CAPTION, IDS_STILLUNPLUGGED, MB_ICONERROR | MB_OK); idNext = -1; } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, idNext); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; } } return FALSE; case WM_DESTROY: pthis->DestroyConnectionList(GetDlgItem(hwnd, IDC_CONNLIST)); return TRUE; } return FALSE; } void CHomeNetworkWizard::PublicSetControlState(HWND hwnd) { BOOL fSelection = ListView_GetSelectedCount(GetDlgItem(hwnd, IDC_CONNLIST)); PropSheet_SetWizButtons(GetParent(hwnd), fSelection ? PSWIZB_BACK | PSWIZB_NEXT : PSWIZB_BACK); } void FreeExternalConnection(PHOMENETSETUPINFO pInfo) { if (pInfo->pncExternal) { pInfo->pncExternal->Release(); pInfo->pncExternal = NULL; } } void CHomeNetworkWizard::PublicNextPage(HWND hwnd) { FreeExternalConnection(&_hnetInfo); // Get the selected external adapter HWND hwndList = GetDlgItem(hwnd, IDC_CONNLIST); int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); // We can assert here since Next should be disabled if there is no selection! ASSERT(-1 != iItem); LVITEM lvi = {0}; lvi.iItem = iItem; lvi.mask = LVIF_PARAM; if (ListView_GetItem(hwndList, &lvi)) { if (g_fRunningOnNT) { _hnetInfo.pncExternal = (INetConnection*) (lvi.lParam); _hnetInfo.pncExternal->AddRef(); } else { _hnetInfo.ipaExternal = lvi.lParam; } } // Do the real wizard navigation UINT idPage = IDD_WIZ_NAME; if (g_fRunningOnNT) { idPage = _fShowSharingPage ? IDD_WIZ_EDGELESS : IDD_WIZ_ICSCONFLICT; } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, idPage); } void CHomeNetworkWizard::FoundIcsSetText(HWND hwnd) { if (GetICSMachine(_szICSMachineName, ARRAYSIZE(_szICSMachineName))) { TCHAR szMsg[256]; if (FormatMessageString(IDS_ICSMSG, szMsg, ARRAYSIZE(szMsg), _szICSMachineName)) { SetWindowText(GetDlgItem(hwnd, IDC_ICSMSG), szMsg); } } else { // No ICS beacon - ask the user how they connect SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) _fNoICSQuestion ? IDD_WIZ_WIN9X_CONNECT : IDD_WIZ_CONNECT); } } INT_PTR CHomeNetworkWizard::FoundIcsPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: SendMessage(GetDlgItem(hwnd, IDC_SHARECONNECT), BM_SETCHECK, BST_CHECKED, 0); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); pthis->FoundIcsSetText(hwnd); return TRUE; case PSN_WIZNEXT: { UINT idNext; if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_SHARECONNECT), BM_GETCHECK, 0, 0)) { // This machine should be an ICS Client and won't have a public connection pthis->_hnetInfo.dwFlags = HNET_SHAREPRINTERS | HNET_SHAREFOLDERS | HNET_ICSCLIENT; pthis->_fShowPublicPage = FALSE; pthis->_fShowSharingPage = FALSE; pthis->_fICSClient = TRUE; idNext = g_fRunningOnNT ? IDD_WIZ_ICSCONFLICT : IDD_WIZ_NAME; } else { idNext = pthis->_fNoICSQuestion ? IDD_WIZ_WIN9X_CONNECT : IDD_WIZ_CONNECT; } pthis->PushPage(IDD_WIZ_FOUNDICS); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, idNext); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; } } return FALSE; } return FALSE; } void CHomeNetworkWizard::ConnectSetDefault(HWND hwnd) { UINT idSelect = IDC_ICSHOST; if ((!g_fRunningOnNT) || (GetConnectionCount(NULL, CONN_INTERNAL | CONN_EXTERNAL) == 1)) { idSelect = IDC_ICSCLIENT; } SendDlgItemMessage(hwnd, idSelect, BM_SETCHECK, BST_CHECKED, 0); } void CHomeNetworkWizard::ConnectNextPage(HWND hwnd) { _fICSClient = FALSE; _fNoHomeNetwork = FALSE; if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_ICSHOST), BM_GETCHECK, 0, 0)) { // This machine will need a firewalled, public connection, and should be ICS Host. _hnetInfo.dwFlags = HNET_SHARECONNECTION | HNET_FIREWALLCONNECTION | HNET_SHAREPRINTERS | HNET_SHAREFOLDERS; _fShowPublicPage = TRUE; _fShowSharingPage = FALSE; } else if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_ICSCLIENT), BM_GETCHECK, 0, 0)) { // This machine should be an ICS Client and won't have a public connection _hnetInfo.dwFlags = HNET_SHAREPRINTERS | HNET_SHAREFOLDERS | HNET_ICSCLIENT; _fShowPublicPage = FALSE; _fShowSharingPage = FALSE; _fICSClient = TRUE; } else if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_ALLCOMPUTERSDIRECT), BM_GETCHECK, 0, 0)) { // This machine will need a public connection, and we should ask before sharing files _hnetInfo.dwFlags = HNET_FIREWALLCONNECTION | HNET_SHAREPRINTERS | HNET_SHAREFOLDERS; _fShowPublicPage = TRUE; _fShowSharingPage = TRUE; } else if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_NOHOMENETWORK), BM_GETCHECK, 0, 0)) { // This machine needs a firewalled, public connection and not much else _hnetInfo.dwFlags = HNET_FIREWALLCONNECTION | HNET_SHAREPRINTERS | HNET_SHAREFOLDERS; _fShowPublicPage = TRUE; _fShowSharingPage = FALSE; _fNoHomeNetwork = TRUE; } else if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_NOINTERNET), BM_GETCHECK, 0, 0)) { // No internet box _hnetInfo.dwFlags = HNET_SHAREPRINTERS | HNET_SHAREFOLDERS; _fShowPublicPage = FALSE; _fShowSharingPage = FALSE; } UINT idNext; if (g_fRunningOnNT) { if (BST_CHECKED == SendMessage(GetDlgItem(hwnd, IDC_OTHER), BM_GETCHECK, 0, 0)) { idNext = IDD_WIZ_CONNECTOTHER; } else { idNext = _fShowPublicPage ? IDD_WIZ_PUBLIC : IDD_WIZ_ICSCONFLICT; } } else { // For now - TODO: Ed and I need to figure out what we need to do downlevel (9x + 2k) idNext = IDD_WIZ_NAME; } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, idNext); } INT_PTR CHomeNetworkWizard::ConnectPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_HNCONFIG); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_SHOWMESTATIC1), IDC_SHOWMELINK1, IDS_SHOWME); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_SHOWMESTATIC2), IDC_SHOWMELINK2, IDS_SHOWME); pthis->ConnectSetDefault(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); return TRUE; case PSN_WIZNEXT: { pthis->PushPage(pthis->_fNoICSQuestion ? IDD_WIZ_WIN9X_CONNECT : IDD_WIZ_CONNECT); pthis->ConnectNextPage(hwnd); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { if (IsOS(OS_PERSONAL)) { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_howto_connectP.htm"); } else { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_howto_connectW.htm"); } } return TRUE; case IDC_SHOWMELINK1: { pthis->ShowMeLink(hwnd, L"ntart.chm::/hn_showme1.htm"); } return TRUE; case IDC_SHOWMELINK2: { pthis->ShowMeLink(hwnd, L"ntart.chm::/hn_showme2.htm"); } return TRUE; } } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::ConnectOtherPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: if ( pthis->_fExternalOnly ) { TraceMsg(TF_WARNING, "External Adapters Only"); } SendDlgItemMessage(hwnd, IDC_ALLCOMPUTERSDIRECT, BM_SETCHECK, (WPARAM) BST_CHECKED, 0); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_HNCONFIG); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_SHOWMESTATIC3), IDC_SHOWMELINK3, IDS_SHOWME); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_SHOWMESTATIC4), IDC_SHOWMELINK4, IDS_SHOWME); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_SHOWMESTATIC5), IDC_SHOWMELINK5, IDS_SHOWME); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); return TRUE; case PSN_WIZNEXT: { pthis->PushPage(IDD_WIZ_CONNECTOTHER); pthis->ConnectNextPage(hwnd); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"netcfg.chm%3A%3A/share_conn_overvw.htm"); } return TRUE; case IDC_SHOWMELINK3: { pthis->ShowMeLink(hwnd, L"ntart.chm::/hn_showme3.htm"); } return TRUE; case IDC_SHOWMELINK4: { pthis->ShowMeLink(hwnd, L"ntart.chm::/hn_showme4.htm"); } return TRUE; case IDC_SHOWMELINK5: { pthis->ShowMeLink(hwnd, L"ntart.chm::/hn_showme5.htm"); } return TRUE; } } } return FALSE; } return FALSE; } void CHomeNetworkWizard::DestroyConnectionList(HWND hwndList) { if (g_fRunningOnNT) { int nItems = ListView_GetItemCount(hwndList); for (int iItem = 0; iItem < nItems; iItem ++) { // Get our stashed INetConnection for each item in the list and free it LVITEM lvi = {0}; lvi.mask = LVIF_PARAM; lvi.iItem = iItem; if (ListView_GetItem(hwndList, &lvi)) { ((INetConnection*) lvi.lParam)->Release(); } } } ListView_DeleteAllItems(hwndList); } inline void _SetDlgItemRect(HWND hwnd, UINT id, RECT* pRect) { SetWindowPos(GetDlgItem(hwnd, id), NULL, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top, SWP_NOZORDER | SWP_SHOWWINDOW); } void _OffsetDlgItem(HWND hwnd, UINT id, int xOffset, int yOffset, BOOL fAdjustWidth, BOOL fAdjustHeight) { RECT rc; HWND hwndControl = GetDlgItem(hwnd, id); GetWindowRect(hwndControl, &rc); MapWindowPoints(NULL, hwnd, (LPPOINT) &rc, 2); OffsetRect(&rc, xOffset, yOffset); if (fAdjustWidth) { rc.right -= xOffset; } if (fAdjustHeight) { rc.bottom -= yOffset; } _SetDlgItemRect(hwnd, id, &rc); } void CHomeNetworkWizard::PublicMoveControls(HWND hwnd, BOOL fItemPreselected) { // We need to move controls around on this page depending on whether or not an item is preselected or not // Reset the dialog so that all controls are in their default positions PublicResetControlPositions(hwnd); if (fItemPreselected) { // We are transitioning from the "default" position to one where an item is preselected. // The only work we do here is to hide the help icon and move over the help text a bit to the left int xOffset = (PublicControlPositions._rcHelpIcon.left) - (PublicControlPositions._rcHelpText.left); UINT idHelp = IsWindowVisible(GetDlgItem(hwnd, IDC_HELPSTATIC)) ? IDC_HELPSTATIC : IDC_HELPLINK; _OffsetDlgItem(hwnd, idHelp, xOffset, 0, TRUE, FALSE); ShowWindow(GetDlgItem(hwnd, IDC_HELPICON), SW_HIDE); } else { // We are transitioning from the "default" position to the one where we don't have a preselection // We need to hide the "we've automatically selected..." message and move up the list label, // and expand the connection list. int yOffset = (PublicControlPositions._rcSelectMessage.top) - (PublicControlPositions._rcListLabel.top); _OffsetDlgItem(hwnd, IDC_LISTLABEL, 0, yOffset, FALSE, FALSE); _OffsetDlgItem(hwnd, IDC_CONNLIST, 0, yOffset, FALSE, TRUE); ShowWindow(GetDlgItem(hwnd, IDC_SELECTMSG), SW_HIDE); } } void CHomeNetworkWizard::PublicSetActive(HWND hwnd) { HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); FreeExternalConnection(&_hnetInfo); HWND hwndList = GetDlgItem(hwnd, IDC_CONNLIST); FillConnectionList(hwndList, NULL, CONN_EXTERNAL); // Auto-select if there is only one connection listed if (ListView_GetItemCount(hwndList) == 1 #ifdef DEBUG && !(GetKeyState(VK_CONTROL) < 0) // don't do this if CTRL is down for debugging #endif ) { ListView_SetItemState(hwndList, 0, LVIS_SELECTED, LVIS_SELECTED); // PublicNextPage will set DWLP_MSGRESULT and tell the wizard to skip this page // and go on to the next. PublicNextPage(hwnd); } else { // If there is a selected item int iSelectedItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); if (-1 != iSelectedItem) { // Read the item name and set the alternate "Windows recommends this connection." text WCHAR szItem[256], szMsg[256]; ListView_GetItemText(hwndList, iSelectedItem, 0, szItem, ARRAYSIZE(szItem)); FormatMessageString(IDS_RECOMMENDEDCONN, szMsg, ARRAYSIZE(szMsg), szItem); SetDlgItemText(hwnd, IDC_SELECTMSG, szMsg); BoldControl(hwnd, IDC_SELECTMSG); } PublicMoveControls(hwnd, (-1 != iSelectedItem)); PublicSetControlState(hwnd); } if(NULL != hOldCursor) { SetCursor(hOldCursor); } } void CHomeNetworkWizard::PublicGetControlPositions(HWND hwnd) { // Remember the default positions of the controls that will move as we reorganize this dialog GetWindowRect(GetDlgItem(hwnd, IDC_SELECTMSG), &PublicControlPositions._rcSelectMessage); GetWindowRect(GetDlgItem(hwnd, IDC_LISTLABEL), &PublicControlPositions._rcListLabel); GetWindowRect(GetDlgItem(hwnd, IDC_CONNLIST), &PublicControlPositions._rcList); GetWindowRect(GetDlgItem(hwnd, IDC_HELPICON), &PublicControlPositions._rcHelpIcon); GetWindowRect(GetDlgItem(hwnd, IDC_HELPSTATIC), &PublicControlPositions._rcHelpText); // We actually need them in client coords // Map 2 points (1 rect) at a time since Mirrored points get screwed up with more MapWindowPoints(NULL, hwnd, (LPPOINT) &PublicControlPositions._rcSelectMessage, 2); MapWindowPoints(NULL, hwnd, (LPPOINT) &PublicControlPositions._rcListLabel, 2); MapWindowPoints(NULL, hwnd, (LPPOINT) &PublicControlPositions._rcList, 2); MapWindowPoints(NULL, hwnd, (LPPOINT) &PublicControlPositions._rcHelpIcon, 2); MapWindowPoints(NULL, hwnd, (LPPOINT) &PublicControlPositions._rcHelpText, 2); } void CHomeNetworkWizard::PublicResetControlPositions(HWND hwnd) { // Set the controls back to their default positions _SetDlgItemRect(hwnd, IDC_SELECTMSG, &PublicControlPositions._rcSelectMessage); _SetDlgItemRect(hwnd, IDC_LISTLABEL, &PublicControlPositions._rcListLabel); _SetDlgItemRect(hwnd, IDC_CONNLIST, &PublicControlPositions._rcList); _SetDlgItemRect(hwnd, IDC_HELPICON, &PublicControlPositions._rcHelpIcon); UINT idHelp = IsWindowVisible(GetDlgItem(hwnd, IDC_HELPSTATIC)) ? IDC_HELPSTATIC : IDC_HELPLINK; _SetDlgItemRect(hwnd, idHelp, &PublicControlPositions._rcHelpText); } INT_PTR CHomeNetworkWizard::PublicPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->InitializeConnectionList(GetDlgItem(hwnd, IDC_CONNLIST), CONN_EXTERNAL); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_SELECTPUBLIC); pthis->PublicGetControlPositions(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { pthis->PublicSetActive(hwnd); return TRUE; } case PSN_WIZNEXT: pthis->PushPage(IDD_WIZ_PUBLIC); pthis->PublicNextPage(hwnd); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case LVN_ITEMCHANGED: pthis->PublicSetControlState(hwnd); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_determine_internet_connection.htm"); } return TRUE; } } } return FALSE; case WM_DESTROY: pthis->DestroyConnectionList(GetDlgItem(hwnd, IDC_CONNLIST)); return TRUE; } return FALSE; } void CHomeNetworkWizard::EdgelessSetActive(HWND hwnd) { PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT); // _hnetInfo.dwFlags &= (~(HNET_SHAREFOLDERS | HNET_SHAREPRINTERS)); if (!ShouldShowConnection(_hnetInfo.pncExternal, NULL, CONN_INTERNAL)) { // External connection is a modem or such - no file sharing necessary (user already said they didn't have a home network) SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_ICSCONFLICT); } } INT_PTR CHomeNetworkWizard::EdgelessPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_RECOMMENDED); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: pthis->EdgelessSetActive(hwnd); return TRUE; case PSN_WIZNEXT: pthis->_hnetInfo.dwFlags |= (HNET_SHAREFOLDERS | HNET_SHAREPRINTERS); pthis->PushPage(IDD_WIZ_EDGELESS); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) IDD_WIZ_BRIDGEWARNING); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { if (IsOS(OS_PERSONAL)) { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_nohost_computerP.htm"); } else { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_nohost_computerW.htm"); } } return TRUE; } } } return FALSE; } return FALSE; } BOOL CHomeNetworkWizard::IsICSIPInUse( WCHAR** ppszHost, PDWORD pdwSize ) { HRESULT hr; INetConnection** ppArray = NULL; DWORD dwItems = 0; BOOL bExists = FALSE; if ( ppszHost ) *ppszHost = NULL; if ( pdwSize ) *pdwSize = 0; hr = GetInternalConnectionArray( _hnetInfo.pncExternal, &ppArray, &dwItems ); if ( SUCCEEDED(hr) ) { hr = E_FAIL; for( DWORD i=0; iRelease(); } // for( DWORD i=0; iReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_ICSCONFLICT); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; WCHAR* pszConflictingHost = NULL; DWORD dwSize = 0; switch (pnmh->code) { case PSN_SETACTIVE: pthis->ICSConflictSetActive(hwnd); return TRUE; case PSN_WIZNEXT: if (pthis->IsICSIPInUse(&pszConflictingHost, &dwSize)) { DisplayFormatMessage(hwnd, IDS_WIZ_CAPTION, IDS_STILLICSCONFLICT, MB_ICONERROR | MB_OK); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, -1); } else { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) IDD_WIZ_BRIDGEWARNING); } if ( pszConflictingHost ) delete [] pszConflictingHost; return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_change_ics_host.htm"); } return TRUE; } } } return FALSE; } return FALSE; } DWORD CHomeNetworkWizard::GetConnectionCount(INetConnection* pncExclude, DWORD dwFlags) { DWORD dwCount = 0; if (g_fRunningOnNT) { DWORD cItems = DPA_GetPtrCount(_hdpaConnections); for (DWORD iItem = 0; iItem < cItems; iItem ++) { INetConnection* pnc = (INetConnection*) DPA_GetPtr(_hdpaConnections, iItem); if (ShouldShowConnection(pnc, pncExclude, dwFlags)) { dwCount++; } } } else { const NETADAPTER* pNA = _hnetInfo.pNA; for (UINT i = 0; i < _hnetInfo.cNA; i++, pNA++) { // Check if the NIC is working. if (W9xIsValidAdapter(pNA, dwFlags)) { dwCount++; } } } return dwCount; } INT_PTR CHomeNetworkWizard::BridgeWarningPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: SendDlgItemMessage(hwnd, IDC_AUTOBRIDGE, BM_SETCHECK, (WPARAM) BST_CHECKED, 0); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_BRIDGE); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { if (pthis->_fNoHomeNetwork) { FreeInternalConnections(&pthis->_hnetInfo); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_NAME); } else { DWORD nInternal = pthis->GetConnectionCount(pthis->_hnetInfo.pncExternal, CONN_INTERNAL); if (1 < nInternal) { // We show this page if there are two or more internal connections (which is this case) PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); } else if ((pthis->_hnetInfo.dwFlags & HNET_SHARECONNECTION) && (0 == nInternal)) { // We are sharing the public connection, and there are no other connections left // over for home networking. Show error page pthis->_fManualBridgeConfig = FALSE; SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_NOHARDWAREFINISH); } else { // There are either zero or one internal connections. If zero, then we aren't sharing the connection // Skip the bridge warning page and go to the private page pthis->_fManualBridgeConfig = FALSE; SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_PRIVATE); } } return TRUE; } case PSN_WIZNEXT: { pthis->_fManualBridgeConfig = (BST_CHECKED == SendDlgItemMessage(hwnd, IDC_MANUALBRIDGE, BM_GETCHECK, 0, 0)); pthis->PushPage(IDD_WIZ_BRIDGEWARNING); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_PRIVATE); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"netcfg.chm%3A%3A/hnw_understanding_bridge.htm"); } return TRUE; } } } return FALSE; } return FALSE; } void FreeInternalConnections(PHOMENETSETUPINFO pInfo) { // Delete any existing private connection information if (pInfo->prgncInternal) { for (DWORD i = 0; i < pInfo->cncInternal; i++) { INetConnection* pnc = pInfo->prgncInternal[i]; pnc->Release(); } LocalFree(pInfo->prgncInternal); pInfo->prgncInternal = NULL; } pInfo->cncInternal = 0; } void FreeInternalGUIDs(PHOMENETSETUPINFO pInfo) { if (pInfo->prgguidInternal) { LocalFree(pInfo->prgguidInternal); pInfo->prgguidInternal = NULL; } pInfo->cguidInternal = 0; } DWORD _ListView_GetCheckedCount(HWND hwndList) { int nItems = ListView_GetItemCount(hwndList); DWORD nCheckedItems = 0; if (-1 != nItems) { for(int iItem = 0; iItem < nItems; iItem ++) { if (ListView_GetCheckState(hwndList, iItem)) { nCheckedItems ++; } } } return nCheckedItems; } void CHomeNetworkWizard::PrivateSetControlState(HWND hwnd) { BOOL fEnableNext = TRUE; // If the user is sharing a connection, they must specify at least one private connection if (_hnetInfo.dwFlags & HNET_SHARECONNECTION) { fEnableNext = (0 != _ListView_GetCheckedCount(GetDlgItem(hwnd, IDC_CONNLIST))); } PropSheet_SetWizButtons(GetParent(hwnd), fEnableNext ? PSWIZB_BACK | PSWIZB_NEXT : PSWIZB_BACK); } void CHomeNetworkWizard::PrivateNextPage(HWND hwnd) { FreeInternalConnections(&_hnetInfo); // Figure out the number of connections we'll need HWND hwndList = GetDlgItem(hwnd, IDC_CONNLIST); int nItems = ListView_GetItemCount(hwndList); DWORD nCheckedItems = _ListView_GetCheckedCount(hwndList); if (nCheckedItems) { _hnetInfo.prgncInternal = (INetConnection**) LocalAlloc(LPTR, (nCheckedItems + 1) * sizeof (INetConnection*)); // Alloc one extra INetConnection* and Null-terminate this array so we can pass it to HNet config api if (_hnetInfo.prgncInternal) { _hnetInfo.cncInternal = 0; // Get the INetConnection for each checked item for (int iItem = 0; iItem < nItems; iItem ++) { if (ListView_GetCheckState(hwndList, iItem)) { LVITEM lvi = {0}; lvi.iItem = iItem; lvi.mask = LVIF_PARAM; ListView_GetItem(hwndList, &lvi); if (g_fRunningOnNT) { _hnetInfo.prgncInternal[_hnetInfo.cncInternal] = (INetConnection*) lvi.lParam; _hnetInfo.prgncInternal[_hnetInfo.cncInternal]->AddRef(); } else { // TODO W9x } _hnetInfo.cncInternal ++; } } // Assert since if we messed something up there might not be enough space allocated in the buffer! ASSERT(nCheckedItems == _hnetInfo.cncInternal); } } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_NAME); } INT_PTR CHomeNetworkWizard::PrivatePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->InitializeConnectionList(GetDlgItem(hwnd, IDC_CONNLIST), CONN_INTERNAL); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_BRIDGE); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { FreeInternalConnections(&(pthis->_hnetInfo)); HWND hwndList = GetDlgItem(hwnd, IDC_CONNLIST); pthis->FillConnectionList(hwndList, pthis->_hnetInfo.pncExternal, CONN_INTERNAL); // If the user hasn't select manual bridge and/or there is less than 2 items, // then _fManualBridgeConfig will be FALSE and we'll autobridge if (!pthis->_fManualBridgeConfig) { // PrivateNextPage will set DWLP_MSGRESULT and tell the wizard to skip this page // and go on to the next. pthis->PrivateNextPage(hwnd); } pthis->PrivateSetControlState(hwnd); return TRUE; } case PSN_WIZNEXT: pthis->PrivateNextPage(hwnd); pthis->PushPage(IDD_WIZ_PRIVATE); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"netcfg.chm%3A%3A/hnw_understanding_bridge.htm"); } return TRUE; } case LVN_ITEMCHANGED: pthis->PrivateSetControlState(hwnd); return TRUE; } } return FALSE; case WM_DESTROY: pthis->DestroyConnectionList(GetDlgItem(hwnd, IDC_CONNLIST)); return FALSE; } return FALSE; } void CHomeNetworkWizard::NameSetControlState(HWND hwnd) { BOOL fEnableNext = (0 != GetWindowTextLength(GetDlgItem(hwnd, IDC_COMPUTERNAME))); PropSheet_SetWizButtons(GetParent(hwnd), fEnableNext ? PSWIZB_BACK | PSWIZB_NEXT : PSWIZB_BACK); } HRESULT CHomeNetworkWizard::NameNextPage(HWND hwnd) { HRESULT hr = E_FAIL; GetDlgItemText(hwnd, IDC_COMPUTERDESC, _hnetInfo.szComputerDescription, ARRAYSIZE(_hnetInfo.szComputerDescription)); GetDlgItemText(hwnd, IDC_COMPUTERNAME, _hnetInfo.szComputer, ARRAYSIZE(_hnetInfo.szComputer)); // There are two errors that we show for computer name: INVALID and DUPLICATE // TODO: We only detect duplicate for NT so far!!! UINT idError = IDS_COMPNAME_INVALID; // Test to see if the name is more than 15 OEM bytes int iBytes = WideCharToMultiByte(CP_OEMCP, 0, _hnetInfo.szComputer, -1, NULL, 0, NULL, NULL) - 1; if (iBytes <= LM20_DNLEN) { if (IsValidNameSyntax(_hnetInfo.szComputer, NetSetupMachine)) { if (g_fRunningOnNT) { SetCursor(LoadCursor(NULL, IDC_WAIT)); NET_API_STATUS nas = NetValidateName(NULL, _hnetInfo.szComputer, NULL, NULL, NetSetupMachine); if (ERROR_DUP_NAME == nas) { ASSERT(E_FAIL == hr); idError = IDS_COMPNAME_DUPLICATE; } else if (NERR_InvalidComputer == nas) { ASSERT(E_FAIL == hr); idError = IDS_COMPNAME_INVALID; } else { // if there is any other failure we just go ahead. If the Client For MS Networks is not installed we // can't validate the name, but it should be fine to use what we have hr = S_OK; _hnetInfo.dwFlags |= HNET_SETCOMPUTERNAME; } } else { // TODO: Win9x!!! hr = S_OK; _hnetInfo.dwFlags |= HNET_SETCOMPUTERNAME; } } } else { ASSERT(E_FAIL == hr); idError = IDS_COMPNAME_TOOMANYBYTES; } // If the computer name didn't validate, don't change pages and show an error. if(FAILED(hr)) { SetFocus(GetDlgItem(hwnd, IDC_COMPUTERNAME)); PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK); DisplayFormatMessage(hwnd, IDS_WIZ_CAPTION, idError, MB_ICONERROR | MB_OK, _hnetInfo.szComputer); } return hr; } void CHomeNetworkWizard::NameInitDialog(HWND hwnd) { // Limit the edit fields SendDlgItemMessage(hwnd, IDC_COMPUTERDESC, EM_SETLIMITTEXT, ARRAYSIZE(_hnetInfo.szComputerDescription) - 1, NULL); SendDlgItemMessage(hwnd, IDC_COMPUTERNAME, EM_SETLIMITTEXT, ARRAYSIZE(_hnetInfo.szComputer) - 1, NULL); // Set the current name as the default WCHAR szComputerName[ARRAYSIZE(_hnetInfo.szComputer)]; *szComputerName = 0; WCHAR szDescription[ARRAYSIZE(_hnetInfo.szComputerDescription)]; *szDescription = 0; if (g_fRunningOnNT) { SERVER_INFO_101_NT* psv101 = NULL; if (NERR_Success == NetServerGetInfo_NT(NULL, 101, (LPBYTE*) &psv101)) { if (psv101->sv101_comment && psv101->sv101_comment[0]) { StrCpyN(szDescription, psv101->sv101_comment, ARRAYSIZE(szDescription)); } ASSERT(psv101->sv101_name); StrCpyN(szComputerName, psv101->sv101_name, ARRAYSIZE(szComputerName)); NetApiBufferFree(psv101); } } else { AllPlatformGetComputerName(szComputerName, ARRAYSIZE(szComputerName)); CRegistry reg; if (reg.OpenKey(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\VxD\\VNETSUP", KEY_READ)) { reg.QueryStringValue(L"Comment", szDescription, ARRAYSIZE(szDescription)); } } SetDlgItemText(hwnd, IDC_COMPUTERNAME, szComputerName); SetDlgItemText(hwnd, IDC_COMPUTERDESC, szDescription); WCHAR szNameMessage[256]; if (FormatMessageString(IDS_CURRENTNAME, szNameMessage, ARRAYSIZE(szNameMessage), szComputerName)) { SetDlgItemText(hwnd, IDC_CURRENTNAME, szNameMessage); } } INT_PTR CHomeNetworkWizard::NamePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->NameInitDialog(hwnd); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_COMPNAME); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { // Show the ISP Warning if this computer connects directly to the Internet int nShowISPWarning = (NULL != pthis->_hnetInfo.pncExternal) ? SW_SHOW : SW_HIDE; ShowWindow(GetDlgItem(hwnd, IDC_ISPWARN1), nShowISPWarning); ShowWindow(GetDlgItem(hwnd, IDC_ISPWARN2), nShowISPWarning); pthis->NameSetControlState(hwnd); } return TRUE; case PSN_WIZNEXT: if (SUCCEEDED(pthis->NameNextPage(hwnd))) { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) IDD_WIZ_WORKGROUP); pthis->PushPage(IDD_WIZ_NAME); } else { // else not changing pages; don't push SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) -1); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: { HelpCenter(hwnd, L"network.chm%3A%3A/hnw_comp_name_description.htm"); } return TRUE; } } } return FALSE; case WM_COMMAND: { switch (HIWORD(wParam)) { case EN_CHANGE: if (LOWORD(wParam) == IDC_COMPUTERNAME) { pthis->NameSetControlState(hwnd); } return FALSE; } } return FALSE; } return FALSE; } void CHomeNetworkWizard::WorkgroupSetControlState(HWND hwnd) { BOOL fNext = (0 != SendDlgItemMessage(hwnd, IDC_WORKGROUP, WM_GETTEXTLENGTH, 0, 0)); PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | (fNext ? PSWIZB_NEXT : 0)); } HRESULT CHomeNetworkWizard::WorkgroupNextPage(HWND hwnd) { HRESULT hr = E_FAIL; UINT idError = IDS_WORKGROUP_INVALID; if (GetDlgItemText(hwnd, IDC_WORKGROUP, _hnetInfo.szWorkgroup, ARRAYSIZE(_hnetInfo.szWorkgroup))) { // Test to see if the name is more than 15 OEM bytes int iBytes = WideCharToMultiByte(CP_OEMCP, 0, _hnetInfo.szWorkgroup, -1, NULL, 0, NULL, NULL) - 1; if (iBytes <= LM20_DNLEN) { // Remove any preceding blanks size_t szLen = wcslen( _hnetInfo.szWorkgroup ) + 1; LPWSTR szTemp = new WCHAR[ szLen ]; if ( szTemp ) { WCHAR* pch; for ( pch = _hnetInfo.szWorkgroup; *pch && (L' ' == *pch); ) pch++; wcsncpy( szTemp, pch, szLen ); wcsncpy( _hnetInfo.szWorkgroup, szTemp, szLen ); delete [] szTemp; } // Use the computer name check for workgroups too if (IsValidNameSyntax(_hnetInfo.szWorkgroup, NetSetupWorkgroup)) { if (g_fRunningOnNT) { SetCursor(LoadCursor(NULL, IDC_WAIT)); NET_API_STATUS nas = NetValidateName(NULL, _hnetInfo.szWorkgroup, NULL, NULL, NetSetupWorkgroup); if (NERR_InvalidWorkgroupName != nas) // we only put up a invalid name dialog if the name was invalid. { hr = S_OK; _hnetInfo.dwFlags |= HNET_SETWORKGROUPNAME; } } else { // TODO: Win9x!!! hr = S_OK; _hnetInfo.dwFlags |= HNET_SETWORKGROUPNAME; } } } else { ASSERT(E_FAIL == hr); idError = IDS_WORKGROUP_TOOMANYBYTES; } // If the computer name didn't validate, don't change pages and show an error. if(FAILED(hr)) { SetFocus(GetDlgItem(hwnd, IDC_WORKGROUP)); PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK); DisplayFormatMessage(hwnd, IDS_WIZ_CAPTION, idError, MB_ICONERROR | MB_OK, _hnetInfo.szWorkgroup); } } return hr; } INT_PTR CHomeNetworkWizard::WorkgroupPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { WCHAR szWorkgroup[LM20_DNLEN + 1]; *szWorkgroup = 0; LoadString(g_hinst, IDS_DEFAULT_WORKGROUP1, szWorkgroup, ARRAYSIZE(szWorkgroup)); SetDlgItemText(hwnd, IDC_WORKGROUP, szWorkgroup); SendDlgItemMessage(hwnd, IDC_WORKGROUP, EM_LIMITTEXT, ARRAYSIZE(pthis->_hnetInfo.szWorkgroup) - 1, 0); } return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { pthis->WorkgroupSetControlState(hwnd); pthis->_hnetInfo.dwFlags &= (~HNET_SETWORKGROUPNAME); } return TRUE; case PSN_WIZNEXT: { if (SUCCEEDED(pthis->WorkgroupNextPage(hwnd))) { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) IDD_WIZ_SUMMARY); pthis->PushPage(IDD_WIZ_WORKGROUP); } else { // else not changing pages; don't push SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) -1); } } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; } } return FALSE; case WM_COMMAND: { switch (HIWORD(wParam)) { case EN_CHANGE: if (LOWORD(wParam) == IDC_WORKGROUP) { pthis->WorkgroupSetControlState(hwnd); } return FALSE; } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::SummaryPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_QUERYINITIALFOCUS: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) GetDlgItem(hwnd, IDC_TITLE)); return TRUE; case PSN_SETACTIVE: pthis->SummarySetActive(hwnd); PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZNEXT: pthis->PushPage(IDD_WIZ_SUMMARY); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_PROGRESS); return TRUE; } } return FALSE; } return FALSE; } #define WM_CONFIGDONE (WM_USER + 0x100) INT_PTR CHomeNetworkWizard::ProgressPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { PropSheet_CancelToClose(GetParent(hwnd)); PropSheet_SetWizButtons(pnmh->hwndFrom, 0); pthis->_hnetInfo.fAsync = TRUE; pthis->_hnetInfo.hwnd = hwnd; pthis->_hnetInfo.umsgAsyncNotify = WM_CONFIGDONE; ConfigureHomeNetwork(&(pthis->_hnetInfo)); HWND hwndAnimate = GetDlgItem(hwnd, IDC_PROGRESS); Animate_Open(hwndAnimate, g_fRunningOnNT ? IDA_CONFIG : IDA_LOWCOLORCONFIG); Animate_Play(hwndAnimate, 0, -1, -1); } return TRUE; } } return FALSE; case WM_CONFIGDONE: { Animate_Stop(GetDlgItem(hwnd, IDC_PROGRESS)); // The config thread has finished. We assert that the thread has freed/nulled out // all of his INetConnection*'s since otherwise the UI thread will try to use/free them! ASSERT(NULL == pthis->_hnetInfo.pncExternal); ASSERT(NULL == pthis->_hnetInfo.prgncInternal); if (pthis->_hnetInfo.fRebootRequired) { PropSheet_RebootSystem(GetParent(hwnd)); } // The HRESULT from the configuration is stored in wParam HRESULT hr = (HRESULT) wParam; UINT idFinishPage; if (SUCCEEDED(hr)) { idFinishPage = IDD_WIZ_ALMOSTDONE; } else { idFinishPage = IDD_WIZ_CONFIGERROR; } PropSheet_SetCurSelByID(GetParent(hwnd), idFinishPage); } return TRUE; } return FALSE; } INT_PTR CHomeNetworkWizard::AlmostDonePageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { SendDlgItemMessage(hwnd, IDC_CREATEDISK, BM_SETCHECK, BST_CHECKED, 0); return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { if (g_fRunningOnNT) { PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_NEXT); } else { // Skip this page on 9x SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_WIN9X_FINISH); } } return TRUE; case PSN_WIZNEXT: { // This page only shows on NT ASSERT(g_fRunningOnNT); pthis->_fFloppyInstructions = TRUE; pthis->PushPage(IDD_WIZ_ALMOSTDONE); UINT idNext = IDD_WIZ_FINISH; if (BST_CHECKED == SendDlgItemMessage(hwnd, IDC_CREATEDISK, BM_GETCHECK, 0, 0)) { idNext = IDD_WIZ_CHOOSEDISK; } else if (BST_CHECKED == SendDlgItemMessage(hwnd, IDC_HAVEDISK, BM_GETCHECK, 0, 0)) { idNext = IDD_WIZ_FLOPPYINST; } else if (BST_CHECKED == SendDlgItemMessage(hwnd, IDC_HAVECD, BM_GETCHECK, 0, 0)) { idNext = IDD_WIZ_CDINST; pthis->_fFloppyInstructions = FALSE; } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG_PTR) idNext); } return TRUE; } } return FALSE; } return FALSE; } void CHomeNetworkWizard::FillDriveList(HWND hwndList) { ListView_SetImageList(hwndList, _himlLarge, LVSIL_NORMAL); ListView_DeleteAllItems(hwndList); WCHAR szDrive[] = L"A:\\"; for (UINT i = 0; i < 26; i++) { szDrive[0] = L'A' + i; if (DRIVE_REMOVABLE == GetDriveType(szDrive)) { LVITEM lvi = {0}; lvi.mask = LVIF_PARAM | LVIF_TEXT; lvi.lParam = i; int iIndex; WCHAR szDriveDisplay[256]; HRESULT hr = GetDriveNameAndIconIndex(szDrive, szDriveDisplay, ARRAYSIZE(szDriveDisplay), &iIndex); if (SUCCEEDED(hr)) { lvi.iImage = iIndex; if (-1 != lvi.iImage) lvi.mask |= LVIF_IMAGE; lvi.pszText = szDriveDisplay; int iItem = ListView_InsertItem(hwndList, &lvi); } } } ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE); ListView_SetColumnWidth(hwndList, 1, LVSCW_AUTOSIZE); } void CHomeNetworkWizard::ChooseDiskSetControlState(HWND hwnd) { BOOL fSelection = ListView_GetSelectedCount(GetDlgItem(hwnd, IDC_DEVICELIST)); PropSheet_SetWizButtons(GetParent(hwnd), fSelection ? PSWIZB_BACK | PSWIZB_NEXT : PSWIZB_BACK); } INT_PTR CHomeNetworkWizard::ChooseDiskPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: ASSERT(g_fRunningOnNT); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_QUERYINITIALFOCUS: SetFocus(GetDlgItem(hwnd, IDC_DEVICELIST)); return TRUE; case PSN_SETACTIVE: { HWND hwndList = GetDlgItem(hwnd, IDC_DEVICELIST); pthis->FillDriveList(hwndList); pthis->ChooseDiskSetControlState(hwnd); int cDrives = ListView_GetItemCount(hwndList); if (0 >= cDrives) { // There are no removable drives or an error occurred DisplayFormatMessage(hwnd, IDS_WIZ_CAPTION, IDS_NOREMOVABLEDRIVES, MB_ICONINFORMATION | MB_OK); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); } else if (1 == cDrives) { // One drive - autoselect it and go to the next page LVITEM lvi = {0}; lvi.mask = LVIF_PARAM; ListView_GetItem(hwndList, &lvi); pthis->_iDrive = lvi.lParam; ListView_GetItemText(hwndList, lvi.iItem, 0, pthis->_szDrive, ARRAYSIZE(pthis->_szDrive)); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_INSERTDISK); } } return TRUE; case PSN_WIZNEXT: { HWND hwndList = GetDlgItem(hwnd, IDC_DEVICELIST); pthis->_iDrive = 0; LVITEM lvi = {0}; lvi.mask = LVIF_PARAM; lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); if (-1 != lvi.iItem && ListView_GetItem(hwndList, &lvi)) { pthis->_iDrive = lvi.lParam; ListView_GetItemText(hwndList, lvi.iItem, 0, pthis->_szDrive, ARRAYSIZE(pthis->_szDrive)); pthis->PushPage(IDD_WIZ_CHOOSEDISK); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_INSERTDISK); } } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case LVN_ITEMCHANGED: pthis->ChooseDiskSetControlState(hwnd); return TRUE; } } return FALSE; } return FALSE; } #define SOURCE_FILE "%windir%\\system32\\netsetup.exe" HRESULT CHomeNetworkWizard::GetSourceFilePath(LPSTR pszSource, DWORD cch) { HRESULT hr = E_FAIL; if (ExpandEnvironmentStringsA(SOURCE_FILE, pszSource, cch)) { DWORD c = lstrlenA(pszSource); if (c + 2 <= cch) { // Add double NULL since we'll be passing this to SHFileOperation pszSource[c + 1] = '\0'; hr = S_OK; } } return hr; } INT_PTR CHomeNetworkWizard::InsertDiskPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: ASSERT(g_fRunningOnNT); return TRUE; case WM_COMMAND: if (IDC_FORMAT == LOWORD(wParam)) { SHFormatDrive(hwnd, pthis->_iDrive, 0, 0); return TRUE; } return FALSE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { SetDlgItemText(hwnd, IDC_DISK, pthis->_szDrive); PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZNEXT: { CHAR szSource[MAX_PATH]; if (SUCCEEDED(GetSourceFilePath(szSource, ARRAYSIZE(szSource)))) { // Double-null since we'll be passing this to SHFileOperation CHAR szDest[] = "a:\\netsetup.exe\0"; szDest[0] = 'A' + pthis->_iDrive; SHFILEOPSTRUCTA shfo = {0}; shfo.wFunc = FO_COPY; shfo.pFrom = szSource; shfo.pTo = szDest; shfo.fFlags = FOF_SIMPLEPROGRESS | FOF_NOCONFIRMATION; CHAR szTitle[256]; LoadStringA(g_hinst, IDS_COPYING, szTitle, ARRAYSIZE(szTitle)); shfo.lpszProgressTitle = szTitle; int i = SHFileOperationA(&shfo); if (i || shfo.fAnyOperationsAborted) { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, -1); } else { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_FLOPPYINST); } } } return TRUE; } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::InstructionsPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: ASSERT(g_fRunningOnNT); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_NEXT); // If we aren't going to need to reboot if (!pthis->_hnetInfo.fRebootRequired) { // Then we don't want to tell the user to reboot in the text UINT idNoReboot = IDS_CD_NOREBOOT; if (pthis->_fFloppyInstructions) { // We're on the floppy instructions page idNoReboot = IDS_FLOPPY_NOREBOOT; } WCHAR szLine[256]; LoadString(g_hinst, idNoReboot, szLine, ARRAYSIZE(szLine)); SetDlgItemText(hwnd, IDC_INSTRUCTIONS, szLine); } } return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZNEXT: pthis->PushPage(pthis->_fFloppyInstructions ? IDD_WIZ_FLOPPYINST : IDD_WIZ_CDINST); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, IDD_WIZ_FINISH); return TRUE; } } return FALSE; } return FALSE; } void _AddLineToBuffer(LPCWSTR pszLine, LPWSTR pszBuffer, DWORD cchBuffer, DWORD* piChar) { lstrcpyn(pszBuffer + (*piChar), pszLine, cchBuffer - (*piChar)); *piChar += lstrlen(pszLine); lstrcpyn(pszBuffer + (*piChar), L"\r\n", cchBuffer - (*piChar)); *piChar += 2; } void CHomeNetworkWizard::SummarySetActive(HWND hwnd) { WCHAR szText[2048]; WCHAR szLine[256]; DWORD iChar = 0; // Fill the list with some information based on what things we're going to do to // configure their home network. if (_hnetInfo.pncExternal) { // "Internet connection settings:" LoadString(g_hinst, IDS_SUMMARY_INETSETTINGS, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); NETCON_PROPERTIES* pncprops; HRESULT hr = _hnetInfo.pncExternal->GetProperties(&pncprops); if (SUCCEEDED(hr)) { // Internet connection:\t%1 if (FormatMessageString(IDS_SUMMARY_INETCON, szLine, ARRAYSIZE(szLine), pncprops->pszwName)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } // Internet connection sharing:\tenabled if (_hnetInfo.dwFlags & HNET_SHARECONNECTION) { LoadString(g_hinst, IDS_SUMMARY_ICSENABLED, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } // Personal firewall:\tenabled if (_hnetInfo.dwFlags & HNET_FIREWALLCONNECTION) { LoadString(g_hinst, IDS_SUMMARY_FIREWALLENABLED, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } NcFreeNetconProperties(pncprops); } LoadString(g_hinst, IDS_SUMMARY_UNDERLINE, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } else { if (_fICSClient) { // "Internet connection settings:" LoadString(g_hinst, IDS_SUMMARY_INETSETTINGS, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); if (*_szICSMachineName) { // Connecting via ICS through:\t%1 if (FormatMessageString(IDS_sUMMARY_CONNECTTHROUGH, szLine, ARRAYSIZE(szLine), _szICSMachineName)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } } else { // Connecting through another device or computer. LoadString(g_hinst, IDS_SUMMARY_CONNECTTHROUGH2, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } LoadString(g_hinst, IDS_SUMMARY_UNDERLINE, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } else { // Not connecting to the Internet - display nothing } } // Home network settings: LoadString(g_hinst, IDS_SUMMARY_HNETSETTINGS, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); if (_hnetInfo.dwFlags & HNET_SETCOMPUTERNAME) { // Computer description:\t%1 if (FormatMessageString(IDS_SUMMARY_COMPDESC, szLine, ARRAYSIZE(szLine), _hnetInfo.szComputerDescription)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } // Computer name:\t%1 if (FormatMessageString(IDS_SUMMARY_COMPNAME, szLine, ARRAYSIZE(szLine), _hnetInfo.szComputer)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } } if (_hnetInfo.dwFlags & HNET_SETWORKGROUPNAME) { // Workgroup name:\t%1 if (FormatMessageString(IDS_SUMMARY_WORKGROUP, szLine, ARRAYSIZE(szLine), _hnetInfo.szWorkgroup)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } } // The Shared Documents folder and any printers connected to this computer have been shared. _AddLineToBuffer(L"", szText, ARRAYSIZE(szText), &iChar); LoadString(g_hinst, IDS_SUMMARY_SHARING, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); LoadString(g_hinst, IDS_SUMMARY_UNDERLINE, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); if ((_hnetInfo.prgncInternal) && (_hnetInfo.cncInternal)) { if (_hnetInfo.cncInternal > 1) { // Bridged connections:\r\n LoadString(g_hinst, IDS_SUMMARY_BRIDGESETTINGS, szLine, ARRAYSIZE(szLine)); _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); // Now list the connections... for (DWORD i = 0; i < _hnetInfo.cncInternal; i++) { NETCON_PROPERTIES* pncprops; HRESULT hr = _hnetInfo.prgncInternal[i]->GetProperties(&pncprops); if (SUCCEEDED(hr)) { _AddLineToBuffer(pncprops->pszwName, szText, ARRAYSIZE(szText), &iChar); NcFreeNetconProperties(pncprops); } } } else // Single internal connection case { // Home network connection:\t%1 NETCON_PROPERTIES* pncprops; HRESULT hr = _hnetInfo.prgncInternal[0]->GetProperties(&pncprops); if (SUCCEEDED(hr)) { if (FormatMessageString(IDS_SUMMARY_HOMENETCON, szLine, ARRAYSIZE(szLine), pncprops->pszwName)) { _AddLineToBuffer(szLine, szText, ARRAYSIZE(szText), &iChar); } NcFreeNetconProperties(pncprops); } } } ASSERT(iChar < ARRAYSIZE(szText)); UINT iTabDistance = 150; SendDlgItemMessage(hwnd, IDC_CHANGELIST, EM_SETTABSTOPS, (WPARAM) 1, (LPARAM) &iTabDistance); SetDlgItemText(hwnd, IDC_CHANGELIST, szText); } INT_PTR CHomeNetworkWizard::FinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { pthis->WelcomeSetTitleFont(hwnd); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC), IDC_HELPLINK, IDS_HELP_SHARING); pthis->ReplaceStaticWithLink(GetDlgItem(hwnd, IDC_HELPSTATIC2), IDC_HELPLINK2, IDS_HELP_SHAREDDOCS); return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_CancelToClose(GetParent(hwnd)); PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK | PSWIZB_FINISH); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZFINISH: return TRUE; case NM_CLICK: case NM_RETURN: switch ((int) wParam) { case IDC_HELPLINK: // help on sharing { if (IsOS(OS_PERSONAL)) { HelpCenter(hwnd, L"filefold.chm%3A%3A/sharing_files_overviewP.htm"); } else { HelpCenter(hwnd, L"filefold.chm%3A%3A/sharing_files_overviewW.htm"); } } return TRUE; case IDC_HELPLINK2: // help on Shared Documents { HelpCenter(hwnd, L"filefold.chm%3A%3A/windows_shared_documents.htm"); } return TRUE; } } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::ErrorFinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->WelcomeSetTitleFont(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_FINISH); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZFINISH: return TRUE; } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::NoHardwareFinishPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: { pthis->WelcomeSetTitleFont(hwnd); return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, PSWIZB_BACK); return TRUE; case PSN_WIZBACK: SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pthis->PopPage()); return TRUE; case PSN_WIZFINISH: return TRUE; } } return FALSE; } return FALSE; } INT_PTR CHomeNetworkWizard::CantRunWizardPageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = GetThis(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_INITDIALOG: pthis->WelcomeSetTitleFont(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(pnmh->hwndFrom, 0); return TRUE; } } return FALSE; } return FALSE; } HRESULT GetConnections(HDPA* phdpa) { HRESULT hr = S_OK; *phdpa = DPA_Create(5); if (*phdpa) { // Initialize the net connection enumeration INetConnectionManager* pmgr; hr = CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_PPV_ARG(INetConnectionManager, &pmgr)); if (SUCCEEDED(hr)) { hr = SetProxyBlanket(pmgr); if (SUCCEEDED(hr)) { IEnumNetConnection* penum; hr = pmgr->EnumConnections(NCME_DEFAULT, &penum); if (SUCCEEDED(hr)) { hr = SetProxyBlanket(penum); if (SUCCEEDED(hr)) { // Fill in our DPA will the connections hr = penum->Reset(); while (S_OK == hr) { INetConnection* pnc; ULONG ulISuck; hr = penum->Next(1, &pnc, &ulISuck); if (S_OK == hr) { hr = SetProxyBlanket(pnc); if (SUCCEEDED(hr)) { if (-1 != DPA_AppendPtr(*phdpa, pnc)) { pnc->AddRef(); } else { hr = E_OUTOFMEMORY; } } pnc->Release(); } } } penum->Release(); } } pmgr->Release(); } if (FAILED(hr)) { DPA_DestroyCallback(*phdpa, FreeConnectionDPACallback, NULL); *phdpa = NULL; } } else { hr = E_OUTOFMEMORY; } return hr; } CHomeNetworkWizard* CHomeNetworkWizard::GetThis(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CHomeNetworkWizard* pthis = NULL; if (uMsg == WM_INITDIALOG) { PROPSHEETPAGE* psp = (PROPSHEETPAGE*) lParam; pthis = (CHomeNetworkWizard*) psp->lParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) pthis); } else { pthis = (CHomeNetworkWizard*) GetWindowLongPtr(hwnd, GWLP_USERDATA); } return pthis; } // Utility functions HRESULT GetConnectionsFolder(IShellFolder** ppsfConnections) { LPITEMIDLIST pidlFolder; HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONNECTIONS, &pidlFolder); if (SUCCEEDED(hr)) { IShellFolder* pshDesktop; hr = SHGetDesktopFolder(&pshDesktop); if (SUCCEEDED(hr)) { hr = pshDesktop->BindToObject(pidlFolder, NULL, IID_PPV_ARG(IShellFolder, ppsfConnections)); #if 0 /* We need to do an IEnumIDList::Reset to set up internal data structures so that ::ParseDisplayName works later. Remove this once DaveA's stuff gets in the desktop build. TODO */ if (SUCCEEDED(hr)) { IEnumIDList* penum; hr = (*ppsfConnections)->EnumObjects(NULL, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &penum); if (SUCCEEDED(hr)) { penum->Reset(); penum->Release(); } } #endif pshDesktop->Release(); } ILFree(pidlFolder); } return hr; } void W9xGetNetTypeName(BYTE bNicType, WCHAR* pszBuff, UINT cchBuff) { COMPILETIME_ASSERT(IDS_NETTYPE_START == IDS_NETTYPE_LAN); COMPILETIME_ASSERT(IDS_NETTYPE_LAN - IDS_NETTYPE_START == NETTYPE_LAN); COMPILETIME_ASSERT(IDS_NETTYPE_DIALUP - IDS_NETTYPE_START == NETTYPE_DIALUP); COMPILETIME_ASSERT(IDS_NETTYPE_IRDA - IDS_NETTYPE_START == NETTYPE_IRDA); COMPILETIME_ASSERT(IDS_NETTYPE_PPTP - IDS_NETTYPE_START == NETTYPE_PPTP); COMPILETIME_ASSERT(IDS_NETTYPE_TV - IDS_NETTYPE_START == NETTYPE_TV); COMPILETIME_ASSERT(IDS_NETTYPE_ISDN - IDS_NETTYPE_START == NETTYPE_ISDN); COMPILETIME_ASSERT(IDS_NETTYPE_LAN - IDS_NETTYPE_START == NETTYPE_LAN); if (bNicType >= NETTYPE_LAN && bNicType <= NETTYPE_ISDN) { LoadString(g_hinst, IDS_NETTYPE_START + bNicType, pszBuff, cchBuff); } else { LoadString(g_hinst, IDS_NETTYPE_UNKNOWN, pszBuff, cchBuff); } return; } BOOL W9xIsValidAdapter(const NETADAPTER* pNA, DWORD dwFlags) { BOOL fRet = FALSE; if (dwFlags & CONN_EXTERNAL) { fRet = (pNA->bError == NICERR_NONE && pNA->bNetType == NETTYPE_LAN && pNA->bNetSubType != SUBTYPE_ICS && pNA->bNetSubType != SUBTYPE_AOL && pNA->bNicType != NIC_1394 ); } else if (dwFlags & CONN_INTERNAL) { fRet = (pNA->bError == NICERR_NONE && pNA->bNetType == NETTYPE_LAN && pNA->bNetSubType != SUBTYPE_ICS && pNA->bNetSubType != SUBTYPE_AOL ); } /* else if ( dwFlags & CONN_UNPLUGGED ) { if ( IsOS(OS_MILLENNIUM) ) { fRet = IsAdapterDisconnected( (void*)pNA ); } } */ return fRet; } BOOL W9xIsAdapterDialUp(const NETADAPTER* pAdapter) { return (pAdapter->bNetType == NETTYPE_DIALUP && pAdapter->bNetSubType == SUBTYPE_NONE); } HRESULT CHomeNetworkWizard::GetConnectionIconIndex(GUID& guidConnection, IShellFolder* psfConnections, int* pIndex) { *pIndex = -1; OLECHAR szGUID[40]; HRESULT hr = E_FAIL; if (StringFromGUID2(guidConnection, szGUID, ARRAYSIZE(szGUID))) { LPITEMIDLIST pidlConn = NULL; ULONG cchEaten = 0; hr = psfConnections->ParseDisplayName(NULL, NULL, szGUID, &cchEaten, &pidlConn, NULL); if (SUCCEEDED(hr)) { IExtractIconW *pExtractIconW; LPCITEMIDLIST pcidl = pidlConn; hr = psfConnections->GetUIObjectOf(NULL, 1, &pcidl, IID_IExtractIconW, 0, (LPVOID *)(&pExtractIconW)); if (SUCCEEDED(hr)) { WCHAR szIconLocation[MAX_PATH]; INT iIndex; UINT wFlags; hr = pExtractIconW->GetIconLocation(GIL_FORSHELL, szIconLocation, MAX_PATH, &iIndex, &wFlags); if (SUCCEEDED(hr)) { HICON hIconLarge; HICON hIconSmall; hr = pExtractIconW->Extract(szIconLocation, iIndex, &hIconLarge, &hIconSmall, 0x00100010); if (SUCCEEDED(hr)) { *pIndex = ImageList_AddIcon(_himlSmall, hIconSmall); } DestroyIcon(hIconLarge); DestroyIcon(hIconSmall); } } if(pExtractIconW != NULL) pExtractIconW->Release(); ILFree(pidlConn); } } return hr; } HRESULT GetDriveNameAndIconIndex(LPWSTR pszDrive, LPWSTR pszDisplayName, DWORD cchDisplayName, int* pIndex) { SHFILEINFO fi = {0}; if (SHGetFileInfoW_NT(pszDrive, 0, &fi, sizeof (fi), SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX)) { *pIndex = fi.iIcon; lstrcpyn(pszDisplayName, fi.szDisplayName, cchDisplayName); return S_OK; } return E_FAIL; } BOOL IsEqualConnection(INetConnection* pnc1, INetConnection* pnc2) { BOOL fEqual = FALSE; if ((pnc1) && (pnc2)) { NETCON_PROPERTIES *pprops1, *pprops2; if (SUCCEEDED(pnc1->GetProperties(&pprops1))) { if (SUCCEEDED(pnc2->GetProperties(&pprops2))) { fEqual = (pprops1->guidId == pprops2->guidId); NcFreeNetconProperties(pprops2); } NcFreeNetconProperties(pprops1); } } return fEqual; } HRESULT ShareAllPrinters() { PRINTER_ENUM* pPrinters; int nPrinters = MyEnumLocalPrinters(&pPrinters); if (nPrinters) { int iPrinterNumber = 1; for (int iPrinter = 0; iPrinter < nPrinters; iPrinter ++) { TCHAR szShare[NNLEN + 1]; do { FormatMessageString(IDS_PRINTER, szShare, ARRAYSIZE(szShare), iPrinterNumber); if (1 == iPrinterNumber) { szShare[lstrlen(szShare) - 1] = 0; // Remove the "1" from the end since this is the first printer // ie: "Printer1" --> "Printer" } if (!g_fRunningOnNT) { CharUpper(szShare); } iPrinterNumber ++; } while (IsShareNameInUse(szShare)); if (SharePrinter(pPrinters[iPrinter].pszPrinterName, szShare, NULL)) { g_logFile.Write("Shared Printer: "); } else { g_logFile.Write("Failed to share Printer: "); } g_logFile.Write(pPrinters[iPrinter].pszPrinterName); g_logFile.Write("\r\n"); } free(pPrinters); } return S_OK; } BOOL AllPlatformGetComputerName(LPWSTR pszName, DWORD cchName) { if (g_fRunningOnNT) { return GetComputerNameExW_NT(ComputerNamePhysicalNetBIOS, pszName, &cchName); } else { return GetComputerName(pszName, &cchName); } } BOOL _IsTCPIPAvailable(void) { BOOL fTCPIPAvailable = FALSE; HKEY hk; DWORD dwSize; // we check to see if the TCP/IP stack is installed and which object it is // bound to, this is a string, we don't check the value only that the // length is non-zero. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\Tcpip\\Linkage"), 0x0, KEY_QUERY_VALUE, &hk) ) { if ( ERROR_SUCCESS == RegQueryValueEx(hk, TEXT("Export"), 0x0, NULL, NULL, &dwSize) ) { if ( dwSize > 2 ) { fTCPIPAvailable = TRUE; } } RegCloseKey(hk); } return (fTCPIPAvailable); } BOOL AllPlatformSetComputerName(LPCWSTR pszComputerName) { // NetBIOS computer name is set even on NT for completeness BOOL fSuccess; if (g_fRunningOnNT) { if (_IsTCPIPAvailable()) { fSuccess = SetComputerNameExW_NT(ComputerNamePhysicalDnsHostname, pszComputerName); } else { fSuccess = SetComputerNameExW_NT(ComputerNamePhysicalNetBIOS, pszComputerName); } } else { // Windows 9x fSuccess = SetComputerName(pszComputerName); } return fSuccess; } BOOL SetComputerNameIfNecessary(LPCWSTR pszComputerName, BOOL* pfRebootRequired) { g_logFile.Write("Attempting to set computer name\r\n"); WCHAR szOldComputerName[LM20_CNLEN + 1]; AllPlatformGetComputerName(szOldComputerName, ARRAYSIZE(szOldComputerName)); if (0 != StrCmpIW(szOldComputerName, pszComputerName)) { if (AllPlatformSetComputerName(pszComputerName)) { g_logFile.Write("Computer name set successfully: "); g_logFile.Write(pszComputerName); g_logFile.Write("\r\n"); *pfRebootRequired = TRUE; } else { g_logFile.Write("Computer name set failed.\r\n"); return FALSE; } } else { g_logFile.Write("Old computer name is the same as new computer name - not setting.\r\n"); } return TRUE; } BOOL SetComputerDescription(LPCWSTR pszComputerDescription) { BOOL fRet; if (g_fRunningOnNT) { g_logFile.Write("Setting server description (comment): "); g_logFile.Write(pszComputerDescription); g_logFile.Write("\r\n"); // Set comment (for now, NT only) win9x - TODO SERVER_INFO_1005_NT sv1005; sv1005.sv1005_comment = const_cast(pszComputerDescription); fRet = (NERR_Success == NetServerSetInfo_NT(NULL, 1005, (LPBYTE) &sv1005, NULL)); } else { CRegistry reg; fRet = reg.OpenKey(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\VxD\\VNETSUP"); if (fRet) { fRet = reg.SetStringValue(L"Comment", pszComputerDescription); } } return fRet; } HRESULT ShareWellKnownFolders(PHOMENETSETUPINFO pInfo) { if (!NetConn_IsSharedDocumentsShared()) { NetConn_CreateSharedDocuments(NULL, g_hinst, NULL, 0); if (NetConn_IsSharedDocumentsShared()) { g_logFile.Write("'Shared Documents' shared.\r\n"); } else { g_logFile.Write("Failed to share 'Shared Documents'\r\n"); return E_FAIL; } } return S_OK; } HRESULT SetProxyBlanket(IUnknown * pUnk) { HRESULT hr; hr = CoSetProxyBlanket ( pUnk, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE); if(SUCCEEDED(hr)) { IUnknown * pUnkSet = NULL; hr = pUnk->QueryInterface(IID_PPV_ARG(IUnknown, &pUnkSet)); if(SUCCEEDED(hr)) { hr = CoSetProxyBlanket ( pUnkSet, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE); pUnkSet->Release(); } } return hr; } HRESULT WriteSetupInfoToRegistry(PHOMENETSETUPINFO pInfo) { HKEY hkey; if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szAppRegKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL)) { // Write information telling the home network wizard to run silently on next boot, and what to share DWORD dwRun = 1; RegSetValueEx(hkey, TEXT("RunWizardFromRegistry"), NULL, REG_DWORD, (CONST BYTE*) &dwRun, sizeof (dwRun)); RegCloseKey(hkey); } // Add a runonce entry for this wizard TCHAR szProcess[MAX_PATH]; if (0 != GetModuleFileName(NULL, szProcess, ARRAYSIZE(szProcess))) { TCHAR szModule[MAX_PATH]; if (0 != GetModuleFileName(g_hinst, szModule, ARRAYSIZE(szModule))) { const TCHAR szRunDllFormat[] = TEXT("%s %s,HomeNetWizardRunDll"); TCHAR szRunDllLine[MAX_PATH]; if (0 < wnsprintf(szRunDllLine, ARRAYSIZE(szRunDllLine), szRunDllFormat, szProcess, szModule)) { if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL)) { RegSetValueEx(hkey, TEXT("Network Setup Wizard"), 0, REG_SZ, (LPBYTE) szRunDllLine, ARRAYSIZE(szRunDllLine)); RegCloseKey(hkey); } } } } return S_OK; } HRESULT DeleteSetupInfoFromRegistry() { RegDeleteKeyAndSubKeys(HKEY_LOCAL_MACHINE, c_szAppRegKey); return S_OK; } HRESULT ReadSetupInfoFromRegistry(PHOMENETSETUPINFO pInfo) { BOOL fRunFromRegistry = FALSE; HKEY hkey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szAppRegKey, 0, KEY_READ, &hkey)) { DWORD dwType; DWORD cbData = sizeof (fRunFromRegistry); if (ERROR_SUCCESS != RegQueryValueEx(hkey, TEXT("RunWizardFromRegistry"), NULL, &dwType, (LPBYTE) &fRunFromRegistry, &cbData)) { fRunFromRegistry = FALSE; } RegCloseKey(hkey); } // S_FALSE indicates we're not running silently from infromation in the registry. return fRunFromRegistry ? S_OK : S_FALSE; } HRESULT MakeUniqueShareName(LPCTSTR pszBaseName, LPTSTR pszUniqueName, DWORD cchName) { if (!IsShareNameInUse(pszBaseName)) { lstrcpyn(pszUniqueName, pszBaseName, cchName); return S_OK; } else { int i = 2; while (TRUE) { if (0 > wnsprintf(pszUniqueName, cchName, TEXT("%s%d"), pszBaseName, i)) { return E_FAIL; } if (!IsShareNameInUse(pszUniqueName)) { return S_OK; } } } } // Pass NULL as TokenHandle to see if thread token is admin HRESULT IsUserLocalAdmin(HANDLE TokenHandle, BOOL* pfIsAdmin) { if (g_fRunningOnNT) { // First we must check if the current user is a local administrator; if this is // the case, our dialog doesn't even display PSID psidAdminGroup = NULL; SID_IDENTIFIER_AUTHORITY security_nt_authority = SECURITY_NT_AUTHORITY; BOOL fSuccess = ::AllocateAndInitializeSid_NT(&security_nt_authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdminGroup); if (fSuccess) { // See if the user for this process is a local admin fSuccess = CheckTokenMembership_NT(TokenHandle, psidAdminGroup, pfIsAdmin); FreeSid_NT(psidAdminGroup); } return fSuccess ? S_OK:E_FAIL; } else { // Win9x - every user is an admin *pfIsAdmin = TRUE; return S_OK; } } HRESULT GetConnectionByGUID(HDPA hdpaConnections, const GUID* pguid, INetConnection** ppnc) { *ppnc = NULL; DWORD nItems = DPA_GetPtrCount(hdpaConnections); HRESULT hr = E_FAIL; if (nItems) { DWORD iItem = 0; while (iItem < nItems) { INetConnection* pnc = (INetConnection*) DPA_GetPtr(hdpaConnections, iItem); if (pnc) { GUID guidMatch; hr = GetConnectionGUID(pnc, &guidMatch); if (SUCCEEDED(hr)) { if (*pguid == guidMatch) { *ppnc = pnc; (*ppnc)->AddRef(); break; } } // Don't pnc->Release() - its coming from the DPA } iItem ++; } if (iItem == nItems) { // We searched and didn't find hr = E_FAIL; } } return hr; } HRESULT GUIDsToConnections(PHOMENETSETUPINFO pInfo) { ASSERT(NULL == pInfo->prgncInternal); ASSERT(NULL == pInfo->pncExternal); HDPA hdpaConnections; HRESULT hr = GetConnections(&hdpaConnections); if (SUCCEEDED(hr)) { // Get internal connections by GUID (allocate an extra one for null-terminated array, as elsewhere) pInfo->prgncInternal = (INetConnection**) LocalAlloc(LPTR, (pInfo->cguidInternal + 1) * sizeof (INetConnection*)); if (pInfo->prgncInternal) { DWORD iConnection = 0; while ((iConnection < pInfo->cguidInternal) && SUCCEEDED(hr)) { hr = GetConnectionByGUID(hdpaConnections, pInfo->prgguidInternal + iConnection, pInfo->prgncInternal + iConnection); iConnection++; } pInfo->cncInternal = iConnection; } else { hr = E_OUTOFMEMORY; } if (SUCCEEDED(hr) && (GUID_NULL != pInfo->guidExternal)) { // Get external connection hr = GetConnectionByGUID(hdpaConnections, &(pInfo->guidExternal), &(pInfo->pncExternal)); } DPA_DestroyCallback(hdpaConnections, FreeConnectionDPACallback, NULL); hdpaConnections = NULL; } if (FAILED(hr)) { FreeExternalConnection(pInfo); FreeInternalConnections(pInfo); } pInfo->guidExternal = GUID_NULL; FreeInternalGUIDs(pInfo); return hr; } HRESULT GetConnectionGUID(INetConnection* pnc, GUID* pguid) { NETCON_PROPERTIES* pncprops; HRESULT hr = pnc->GetProperties(&pncprops); if (SUCCEEDED(hr)) { *pguid = pncprops->guidId; NcFreeNetconProperties(pncprops); } return hr; } HRESULT ConnectionsToGUIDs(PHOMENETSETUPINFO pInfo) { HRESULT hr = S_OK; ASSERT(NULL == pInfo->prgguidInternal); ASSERT(GUID_NULL == pInfo->guidExternal); // Allocate the private connection guid array if (pInfo->cncInternal) { pInfo->prgguidInternal = (GUID*) LocalAlloc(LPTR, pInfo->cncInternal * sizeof (GUID)); if (pInfo->prgguidInternal) { // Get each connection's GUID and fill in the array DWORD i = 0; while ((i < pInfo->cncInternal) && (SUCCEEDED(hr))) { hr = GetConnectionGUID(pInfo->prgncInternal[i], &(pInfo->prgguidInternal[i])); i++; } pInfo->cguidInternal = i; } else { hr = E_OUTOFMEMORY; } } if (SUCCEEDED(hr)) { if (pInfo->pncExternal) { hr = GetConnectionGUID(pInfo->pncExternal, &(pInfo->guidExternal)); } } if (FAILED(hr) && pInfo->prgguidInternal) { FreeInternalGUIDs(pInfo); pInfo->guidExternal = GUID_NULL; } FreeExternalConnection(pInfo); FreeInternalConnections(pInfo); return hr; } HRESULT ConfigureHomeNetwork(PHOMENETSETUPINFO pInfo) { HRESULT hr = E_FAIL; if (pInfo->fAsync) { if (g_fRunningOnNT) { // Bundle up NT specific data for cross-thread hr = ConnectionsToGUIDs(pInfo); } else { // TODO: Anything necessary on win9x hr = S_OK; } if (SUCCEEDED(hr)) { if (SHCreateThread(ConfigureHomeNetworkThread, pInfo, CTF_COINIT, NULL)) { hr = S_FALSE; } else { hr = E_FAIL; } } } else { hr = ConfigureHomeNetworkSynchronous(pInfo); } return hr; } DWORD WINAPI ConfigureHomeNetworkThread(void* pvData) { PHOMENETSETUPINFO pInfo = (PHOMENETSETUPINFO) pvData; // Before creating this thread, the caller MUST have freed his INetConnection*'s or // else the thread might touch/free them, which it must not do. Assert this. ASSERT(NULL == pInfo->pncExternal); ASSERT(NULL == pInfo->prgncInternal); HRESULT hr; if (g_fRunningOnNT) { // Unbundle data after crossing the thread boundary hr = GUIDsToConnections(pInfo); } else { // TODO: Anything necessary for Win9x hr = S_OK; } if (SUCCEEDED(hr)) { hr = ConfigureHomeNetworkSynchronous(pInfo); FreeExternalConnection(pInfo); FreeInternalConnections(pInfo); if ((pInfo->hwnd) && (pInfo->umsgAsyncNotify)) { // The HRESULT from the configuration is passed in WPARAM PostMessage(pInfo->hwnd, pInfo->umsgAsyncNotify, (WPARAM) hr, 0); } } return 0; } HRESULT ConfigureHomeNetworkSynchronous(PHOMENETSETUPINFO pInfo) { g_logFile.Initialize("%systemroot%\\nsw.log"); HRESULT hr = S_OK; #ifdef NO_CONFIG g_logFile.Write("UI Test only - no configuration\r\n"); g_logFile.Uninitialize(); Sleep(2000); #ifdef FAKE_REBOOTREQUIRED pInfo->fRebootRequired = TRUE; #endif return S_OK; #endif BOOL fInstallSharing = TRUE; BOOL fSharingAlreadyInstalled = IsSharingInstalled(TRUE); BOOL fInstalledWorkgroup = FALSE; // We don't need to install sharing unless we're sharing something if (!(pInfo->dwFlags & (HNET_SHAREFOLDERS | HNET_SHAREPRINTERS))) { g_logFile.Write("No file or printer sharing requested\r\n"); fInstallSharing = FALSE; } // Worker function for the whole wizard // Computer name if ((pInfo->dwFlags & HNET_SETCOMPUTERNAME) && (*(pInfo->szComputer))) { SetComputerNameIfNecessary(pInfo->szComputer, &(pInfo->fRebootRequired)); SetComputerDescription(pInfo->szComputerDescription); } // Workgroup name if ((pInfo->dwFlags & HNET_SETWORKGROUPNAME) && (*(pInfo->szWorkgroup))) { Install_SetWorkgroupName(pInfo->szWorkgroup, &(pInfo->fRebootRequired)); fInstalledWorkgroup = TRUE; } // Install TCP/IP hr = InstallTCPIP(pInfo->hwnd, NULL, NULL); if (NETCONN_NEED_RESTART == hr) { pInfo->fRebootRequired = TRUE; hr = S_OK; } if (FAILED(hr)) { g_logFile.Write("Failed to install TCP/IP\r\n"); } // Install Client for Microsoft Networks // TODO: figure out what to do if NetWare client is installed!?!? hr = InstallMSClient(pInfo->hwnd, NULL, NULL); if (NETCONN_NEED_RESTART == hr) { pInfo->fRebootRequired = TRUE; hr = S_OK; } if (FAILED(hr)) { g_logFile.Write("Failed to install Client for Microsoft Networks.\r\n"); } // Install sharing if (fInstallSharing) { hr = InstallSharing(pInfo->hwnd, NULL, NULL); if (NETCONN_NEED_RESTART == hr) { pInfo->fRebootRequired = TRUE; hr = S_OK; } if (FAILED(hr)) { g_logFile.Write("Failed to install File and Printer Sharing.\r\n"); } } // TODO: What to do about share level vs. user level access control on windows 9x??? // TODO: What to do about autodialing? Are we assuming this will already be done for us? 9x and NT? I think so! if ( g_fRunningOnNT ) { // We only set autodial here if we are configuring an ICS Client // In the case that we explicitly set a public adapter then ConfigureICSBridgeFirewall // will set autodial if required. if ( pInfo->dwFlags & HNET_ICSCLIENT ) { hr = HrSetAutodial( AUTODIAL_MODE_NO_NETWORK_PRESENT ); } } else { if ( pInfo->ipaExternal != -1 ) { if (W9xIsAdapterDialUp(&pInfo->pNA[LOWORD(pInfo->ipaExternal)])) // Dialup adapter for connecting to internet { g_logFile.Write("Setting default dial-up connection to autodial.\r\n"); SetDefaultDialupConnection((pInfo->pRas[HIWORD(pInfo->ipaExternal)]).szEntryName); EnableAutodial(TRUE); } else { g_logFile.Write("Disabling autodial since default connection isn't dial-up.\r\n"); SetDefaultDialupConnection(NULL); EnableAutodial(FALSE); } } } // Configure ICS, the Bridge and the personal firewall if (g_fRunningOnNT) { hr = ConfigureICSBridgeFirewall(pInfo); } else { // ICS client or no internet connection. if ((pInfo->dwFlags & HNET_ICSCLIENT) || (pInfo->pNA && pInfo->ipaExternal == -1)) { CICSInst* pICS = new CICSInst; if (pICS) { if (pICS->IsInstalled()) { pICS->m_option = ICS_UNINSTALL; g_logFile.Write("Uninstalling ICS Client.\r\n"); pICS->DoInstallOption(&(pInfo->fRebootRequired), pInfo->ipaInternal); } delete pICS; } if ( (pInfo->dwFlags & HNET_ICSCLIENT) && (pInfo->pNA && pInfo->ipaInternal != -1)) { UINT ipa; for ( ipa=0; ipacNA; ipa++ ) { const NETADAPTER* pNA = &pInfo->pNA[ ipa ]; if ( W9xIsValidAdapter( pNA, CONN_INTERNAL ) && !W9xIsValidAdapter( pNA, CONN_UNPLUGGED ) ) { HrEnableDhcp( (void*)pNA, HNW_ED_RELEASE|HNW_ED_RENEW ); } } } g_logFile.Write("Disabling autodial.\r\n"); SetDefaultDialupConnection(NULL); EnableAutodial(FALSE); } } // NOTE: we might want to split HNET_SHAREFOLDERS out into two // bits: HNET_CREATESHAREDFOLDERS and HNET_SHARESHAREDFOLDERS // if (pInfo->dwFlags & (HNET_SHAREPRINTERS | HNET_SHAREFOLDERS)) { // Due to domain/corporate security concerns, share things // iff we're setting up a workgroup, or we're already on one // BOOL fOnWorkgroup = fInstalledWorkgroup; if (!fOnWorkgroup) { if (g_fRunningOnNT) { LPTSTR pszDomain; NETSETUP_JOIN_STATUS njs; if (NERR_Success == NetGetJoinInformation(NULL, &pszDomain, &njs)) { NetApiBufferFree(pszDomain); fOnWorkgroup = (NetSetupWorkgroupName == njs); } } else { fOnWorkgroup = TRUE; // there may be some registry key we can check for this } } if (fOnWorkgroup) { EnableSimpleSharing(); if (fSharingAlreadyInstalled) { if (pInfo->dwFlags & HNET_SHAREPRINTERS) { ShareAllPrinters(); } if (pInfo->dwFlags & HNET_SHAREFOLDERS) { ShareWellKnownFolders(pInfo); } } else { // Write the sharing info to the registry - do required work on reboot g_logFile.Write("Sharing isn't installed. Will share folders and printers on reboot.\r\n"); pInfo->fRebootRequired = TRUE; WriteSetupInfoToRegistry(pInfo); } } } if (pInfo->fRebootRequired) { g_logFile.Write("Reboot is required for changes to take effect.\r\n"); } g_logFile.Uninitialize(); // Kick off the netcrawler INetCrawler *pnc; if (SUCCEEDED(CoCreateInstance(CLSID_NetCrawler, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(INetCrawler, &pnc)))) { pnc->Update(0x0); pnc->Release(); } #ifdef FAKE_REBOOTREQUIRED pInfo->fRebootRequired = TRUE; #endif return hr; } void STDMETHODCALLTYPE ConfigurationLogCallback(LPCWSTR pszLogEntry, LPARAM lParam) { g_logFile.Write(pszLogEntry); } typedef BOOL (APIENTRY* PFNNETSETUPICSUPGRADE)(BOOL); HRESULT ConfigureICSBridgeFirewall(PHOMENETSETUPINFO pInfo) { HRESULT hr = E_FAIL; // Call HNetSetShareAndBridgeSettings directly BOOLEAN fSharePublicConnection = (pInfo->pncExternal && (pInfo->dwFlags & HNET_SHARECONNECTION)) ? TRUE : FALSE; BOOLEAN fFirewallPublicConnection = (pInfo->pncExternal && (pInfo->dwFlags & HNET_FIREWALLCONNECTION)) ? TRUE : FALSE; if (fSharePublicConnection) { g_logFile.Write("Will attempt to share public connection.\r\n"); } if (fFirewallPublicConnection) { g_logFile.Write("Will attempt to firewall public connection.\r\n"); } HMODULE hHNetCfg = LoadLibrary(L"hnetcfg.dll"); if (hHNetCfg) { INetConnection* pncPrivate = NULL; LPFNHNETSETSHAREANDBRIDGESETTINGS pfnHNetSetShareAndBridgeSettings = reinterpret_cast (GetProcAddress(hHNetCfg, "HNetSetShareAndBridgeSettings")); if (pfnHNetSetShareAndBridgeSettings) { hr = (*pfnHNetSetShareAndBridgeSettings)( pInfo->pncExternal, pInfo->prgncInternal, fSharePublicConnection, fFirewallPublicConnection, ConfigurationLogCallback, 0, &pncPrivate ); if (SUCCEEDED(hr)) { if ( ( HNET_ICSCLIENT & pInfo->dwFlags ) && ( NULL == pInfo->prgncInternal[1] ) ) { HrEnableDhcp( pInfo->prgncInternal[0], HNW_ED_RELEASE|HNW_ED_RENEW ); } // If we are sharing an external adapter then set WinInet settings to allow // for an existing connection created from ICS client traffic. if ( pInfo->pncExternal ) { hr = HrSetAutodial( AUTODIAL_MODE_NO_NETWORK_PRESENT ); } if ( pncPrivate ) { pncPrivate->Release(); } } else { g_logFile.Write("Adapter Configuration for Home Networking failed.\r\n"); } } else { TraceMsg(TF_WARNING, "HNetCfg.DLL could not find HNetSetShareAndBridgeSettings"); } FreeLibrary(hHNetCfg); } else { TraceMsg(TF_WARNING, "HNetCfg.DLL could not be loaded"); } return hr; } BOOL MachineHasNetShares() { SHARE_INFO* prgShares; int cShares = EnumLocalShares(&prgShares); // See if there are any file or print shares, which are the ones we care about BOOL fHasShares = FALSE; for (int i = 0; i < cShares; i++) { if ((STYPE_DISKTREE == prgShares[i].bShareType) || (STYPE_PRINTQ == prgShares[i].bShareType)) { fHasShares = TRUE; break; } } NetApiBufferFree(prgShares); return fHasShares; } // Checks if guest access mode is enabled. If guest access mode is OFF but // in the indeterminate state (ForceGuest is not set), and the m/c has no net shares, // then we set ForceGuest to 1 and return TRUE. // // This indeterminate state occurs only on win2k->XP upgrade. BOOL EnsureGuestAccessMode( VOID ) { BOOL fIsGuestAccessMode = FALSE; if (IsOS(OS_PERSONAL)) { // Guest mode is always on for Personal fIsGuestAccessMode = TRUE; } else if (IsOS(OS_PROFESSIONAL) && !IsOS(OS_DOMAINMEMBER)) { LONG ec; HKEY hkey; // Professional, not in a domain. Check the ForceGuest value. ec = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkey ); if (ec == NO_ERROR) { DWORD dwValue; DWORD dwValueSize = sizeof(dwValue); ec = RegQueryValueEx(hkey, TEXT("ForceGuest"), NULL, NULL, (LPBYTE)&dwValue, &dwValueSize); if (ec == NO_ERROR) { if (1 == dwValue) { // ForceGuest is already on fIsGuestAccessMode = TRUE; } } else { // Value doesn't exist if (!MachineHasNetShares()) { // Machine has no shares dwValue = 1; ec = RegSetValueEx(hkey, TEXT("ForceGuest"), 0, REG_DWORD, (BYTE*) &dwValue, sizeof (dwValue)); if (ec == NO_ERROR) { // Write succeeded - guest access mode is enabled fIsGuestAccessMode = TRUE; } } } RegCloseKey(hkey); } } return fIsGuestAccessMode; } // It is assumed the machine is not joined to a domain when this is called! HRESULT EnableSimpleSharing() { HRESULT hr = S_FALSE; if (EnsureGuestAccessMode()) { ILocalMachine *pLM; hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILocalMachine, &pLM)); if (SUCCEEDED(hr)) { TraceMsg(TF_ALWAYS, "Enabling Guest Account"); hr = pLM->EnableGuest(ILM_GUEST_NETWORK_LOGON); pLM->Release(); SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0); } } return hr; } #define INVALID_COMPUTERNAME_CHARS L" {|}~[\\]^':;<=>?@!\"#$%^`()+/*&" #define INVALID_WORKGROUP_CHARS L"{|}~[\\]^':;<=>?!\"#$%^`()+/*&" #define INVALID_TRAILING_CHAR L' ' BOOL IsValidNameSyntax(LPCWSTR pszName, NETSETUP_NAME_TYPE type) { // Only support workgroup and machine - need to add new charsets if // required ASSERT(type == NetSetupWorkgroup || type == NetSetupMachine); LPCWSTR pszInvalid = (type == NetSetupWorkgroup) ? INVALID_WORKGROUP_CHARS : INVALID_COMPUTERNAME_CHARS; BOOL fValid = TRUE; WCHAR* pch = (LPWSTR) pszName; if ( *pch && ( NetSetupWorkgroup == type ) ) { // remove trailing blanks WCHAR* pchLast = pch + wcslen(pch) - 1; while ( (INVALID_TRAILING_CHAR == *pchLast) && (pchLast >= pch) ) { *pchLast = NULL; pchLast--; } } fValid = ( *pch ) ? TRUE : FALSE; while (*pch && fValid) { fValid = (NULL == StrChrW(pszInvalid, *pch)); pch ++; } return fValid; } void BoldControl(HWND hwnd, int id) { HWND hwndTitle = GetDlgItem(hwnd, id); // Get the existing font HFONT hfontOld = (HFONT) SendMessage(hwndTitle, WM_GETFONT, 0, 0); LOGFONT lf = {0}; if (GetObject(hfontOld, sizeof(lf), &lf)) { lf.lfWeight = FW_BOLD; HFONT hfontNew = CreateFontIndirect(&lf); if (hfontNew) { SendMessage(hwndTitle, WM_SETFONT, (WPARAM) hfontNew, FALSE); // Don't do this, its shared. // DeleteObject(hfontOld); } } } void ShowControls(HWND hwndParent, const int *prgControlIDs, DWORD nControls, int nCmdShow) { for (DWORD i = 0; i < nControls; i++) ShowWindow(GetDlgItem(hwndParent, prgControlIDs[i]), nCmdShow); } void HelpCenter(HWND hwnd, LPCWSTR pszTopic) { // use ShellExecuteExA for w98 compat. CHAR szURL[1024]; wsprintfA(szURL, "hcp://services/layout/contentonly?topic=ms-its%%3A%%25help_location%%25\\%S", pszTopic); SHELLEXECUTEINFOA shexinfo = {0}; shexinfo.cbSize = sizeof (shexinfo); shexinfo.fMask = SEE_MASK_FLAG_NO_UI; shexinfo.nShow = SW_SHOWNORMAL; shexinfo.lpFile = szURL; shexinfo.lpVerb = "open"; // since help center doesn't properly call AllowSetForegroundWindow when it defers to an existing process we just give it to the next taker. HMODULE hUser32 = GetModuleHandleA("user32.dll"); if(NULL != hUser32) { BOOL (WINAPI *pAllowSetForegroundWindow)(DWORD); pAllowSetForegroundWindow = reinterpret_cast(GetProcAddress(hUser32, "AllowSetForegroundWindow")); if(NULL != pAllowSetForegroundWindow) { pAllowSetForegroundWindow(-1); } } ShellExecuteExA(&shexinfo); } void CHomeNetworkWizard::ShowMeLink(HWND hwnd, LPCWSTR pszTopic) { if (pfnShowHTMLDialog == NULL) { hinstMSHTML = LoadLibrary(TEXT("MSHTML.DLL")); if (hinstMSHTML) { pfnShowHTMLDialog = (SHOWHTMLDIALOGEXFN*)GetProcAddress(hinstMSHTML, "ShowHTMLDialogEx"); } // can not find ShowHTMLDialog API. Do nothing. if (pfnShowHTMLDialog == NULL) return; } WCHAR szURL[1024]; HRESULT hr; VARIANT_BOOL isClosed = VARIANT_FALSE; // check to see if the dialog window is closed. If so, release it so that a new one // will be created. if (showMeDlgWnd != NULL) { if (SUCCEEDED(showMeDlgWnd->get_closed(&isClosed))) { if (isClosed == VARIANT_TRUE) { showMeDlgWnd->Release(); showMeDlgWnd = NULL; if (pFrameWindow != NULL) { pFrameWindow->Release(); pFrameWindow = NULL; } } } else { return; } } const char *helpLoc = getenv("help_location"); LPWSTR lpszWinDir; // pointer to system information string WCHAR tchBuffer[MAX_PATH]; // buffer for concatenated string // if unset use the default location. lpszWinDir = tchBuffer; GetWindowsDirectory(lpszWinDir, MAX_PATH); if (showMeDlgWnd == NULL) { BSTR bstrFrameURL; // need to create a new dialog window. if (helpLoc != NULL) wnsprintfW(szURL, 1024, L"ms-its:%S\\ntart.chm::/hn_ShowMeFrame.htm", helpLoc); else wnsprintfW(szURL, 1024, L"ms-its:%s\\help\\ntart.chm::/hn_ShowMeFrame.htm", lpszWinDir); bstrFrameURL = SysAllocString((const LPCWSTR)szURL); if (bstrFrameURL == NULL) return; IMoniker * pURLMoniker = NULL; CreateURLMoniker(NULL, bstrFrameURL, &pURLMoniker); if (pURLMoniker != NULL) { VARIANT varReturn; VariantInit(&varReturn); DWORD dwFlags = HTMLDLG_MODELESS | HTMLDLG_VERIFY; hr = (*pfnShowHTMLDialog)( NULL, pURLMoniker, dwFlags, NULL, L"scroll:no;help:no;status:no;dialogHeight:394px;dialogWidth:591px;", &varReturn); if (SUCCEEDED(hr)) { hr = V_UNKNOWN(&varReturn)->QueryInterface(__uuidof(IHTMLWindow2), (void**)&showMeDlgWnd); } pURLMoniker->Release(); VariantClear(&varReturn); } SysFreeString(bstrFrameURL); } // we don't have a dialog window to work with so quit silently. if (showMeDlgWnd == NULL) { return; } // we need get the frame window where the actual html page will be displayed. if (pFrameWindow == NULL) { VARIANT index; VARIANT frameOut; long frameLen = 0; VariantInit(&index); VariantInit(&frameOut); IHTMLFramesCollection2* pFramesCol = NULL; // we may not be able to get the frames the first time around. So try some more. int i = 5; while (i-- > 0) { if(!SUCCEEDED(showMeDlgWnd->get_frames(&pFramesCol))) { // can not get frames. so quit. break; } else if (!SUCCEEDED(pFramesCol->get_length(&frameLen))) { // can not determine how many frames it has. so quit. break; } else { if (frameLen > 0) { V_VT(&index) = VT_I4; V_I4(&index) = 0; if (SUCCEEDED(pFramesCol->item(&index, &frameOut))) { if (V_VT(&frameOut) == VT_DISPATCH && V_DISPATCH(&frameOut) != NULL) { hr = V_DISPATCH(&frameOut)->QueryInterface(__uuidof(IHTMLWindow2), (void**)&pFrameWindow); } } // found at least one frame. jump out of the loop. break; } } if (pFramesCol != NULL) pFramesCol->Release(); Sleep(1000); } if (pFramesCol != NULL) pFramesCol->Release(); VariantClear(&index); VariantClear(&frameOut); } if (pFrameWindow == NULL) return; // now to load in the actual html page BSTR bstrURL; if (helpLoc != NULL) wnsprintf(szURL, 1024, L"ms-its:%S\\%s", helpLoc, pszTopic); else wnsprintf(szURL, 1024, L"ms-its:%s\\help\\%s", lpszWinDir, pszTopic); bstrURL = SysAllocString((const LPCWSTR)szURL); if (bstrURL == NULL) return; hr = pFrameWindow->navigate(bstrURL); hr = showMeDlgWnd->focus(); SysFreeString(bstrURL); }