//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: Invoke.cpp // // Contents: Handles invocation cases, ENS, Schedule, etc. // // Classes: CSynchronizeInvoke // // Notes: // // History: 05-Nov-97 rogerg Created. // //-------------------------------------------------------------------------- #include "precomp.h" // Review - Need to figure out logon logic. This just prevents ConnectionMade // events from being handled while we are in logon. If IsNetworkAlive becomse async // or someone calls IsNetworkAlive before us we will sync the same items twice. BOOL g_InAutoSync = FALSE; extern HINSTANCE g_hInst; // current instance //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::CSynchronizeInvoke, public // // Synopsis: Constructor // Increments the applications lifetime // // Arguments: // // Returns: // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- CSynchronizeInvoke::CSynchronizeInvoke() { m_cRef = 1; m_pUnkOuter = &m_Unknown; // only support our unknown for know. m_pITypeInfoLogon = NULL; m_pITypeInfoNetwork = NULL; m_Unknown.SetParent(this); #ifdef _SENS m_PrivSensNetwork.SetParent(this); m_PrivSensLogon.SetParent(this); #endif // _SENS AddRefOneStopLifetime(TRUE /*External*/); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::~CSynchronizeInvoke, public // // Synopsis: Destructor // Decrements the applications lifetime // // Arguments: // // Returns: // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- CSynchronizeInvoke::~CSynchronizeInvoke() { if (m_pITypeInfoLogon) { m_pITypeInfoLogon->Release(); m_pITypeInfoLogon = NULL; } if (m_pITypeInfoNetwork) { m_pITypeInfoNetwork->Release(); m_pITypeInfoNetwork = NULL; } ReleaseOneStopLifetime(TRUE /*External*/); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::QueryInterface, public // // Synopsis: Standard QueryInterface // // Arguments: [iid] - Interface ID // [ppvObj] - Object return // // Returns: Appropriate status code // // Modifies: [ppvObj] // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::QueryInterface(REFIID riid, LPVOID FAR *ppv) { return m_pUnkOuter->QueryInterface(riid,ppv); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::AddRef, public // // Synopsis: Add reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::AddRef() { return m_pUnkOuter->AddRef(); } //+--------------------------------------------------------------------------- // // Member: CSychrononizeInvoke::Release, public // // Synopsis: Release reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::Release() { return m_pUnkOuter->Release(); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::UpdateItems, public // // Synopsis: Handles a programmatic UpdateItems call. // // !!Warning - Liveness relies on a dialog being created // before return or we could go away when the // caler releases our interface. // // Arguments: [dwInvokeFlags] - InvokeFlags // [rclsid] - clsid of handler to load // [cbCookie] - Size of cookie data // [lpCookie] - Ptr to cookie data. // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::UpdateItems(DWORD dwInvokeFlags,REFCLSID rclsid, DWORD cbCookie,const BYTE*lpCookie) { HRESULT hr = E_OUTOFMEMORY; CHndlrQueue * pHndlrQueue = NULL; HANDLERINFO *pHandlerID; JOBINFO *pJobInfo = NULL; BOOL fReg; DWORD dwRegistrationFlags; int nCmdShow = (dwInvokeFlags & SYNCMGRINVOKE_MINIMIZED) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL; // when a new UpdateItems come through do the following // 1 - If should display choices see if existing choice dialog or create a new one // and then add the new items to the choice queue // 2 - If shouldn't display choices see if existing progress or create a new one // and then add the items to the progress queue. // behavior - If already an Update All choice dialog just pull it to the Front // If Already an UpdateAll progress bar bring it to the front // If Progress Bar but doesn't already contain an updateAll create the choice dialog. // we don't use stored preferences on invoke so doesn't matter what pass in as the connection pHndlrQueue = new CHndlrQueue(QUEUETYPE_CHOICE,NULL); if (NULL == pHndlrQueue) { hr = E_OUTOFMEMORY; return hr; } // attempt to initialize the queue hr = pHndlrQueue->AddQueueJobInfo( SYNCMGRFLAG_INVOKE | SYNCMGRFLAG_MAYBOTHERUSER, 0,NULL,NULL,FALSE,&pJobInfo); fReg = RegGetHandlerRegistrationInfo(rclsid,&dwRegistrationFlags); Assert(fReg || (0 == dwRegistrationFlags)); if ( (S_OK == hr) && (S_OK == pHndlrQueue->AddHandler(&pHandlerID,pJobInfo,dwRegistrationFlags)) ) { hr = pHndlrQueue->CreateServer(pHandlerID,&rclsid); if (S_OK == hr) { hr = pHndlrQueue->Initialize(pHandlerID,0,SYNCMGRFLAG_INVOKE | SYNCMGRFLAG_MAYBOTHERUSER, cbCookie,lpCookie); } } // can release our reference on the job info if (pJobInfo) { pHndlrQueue->ReleaseJobInfoExt(pJobInfo); pJobInfo = NULL; } if (S_OK == hr) { DWORD cbNumItemsAdded; hr = pHndlrQueue->AddHandlerItemsToQueue(pHandlerID,&cbNumItemsAdded); if (SYNCMGRINVOKE_STARTSYNC & dwInvokeFlags) { // if start invoke need to add the handlers items to the queue before // transferring if ( (S_OK == hr) && (pHndlrQueue->AreAnyItemsSelectedInQueue()) ) { CProgressDlg *pProgressDlg; hr = FindProgressDialog(GUID_NULL,TRUE,nCmdShow,&pProgressDlg); if (S_OK == hr) { hr = pProgressDlg->TransferQueueData(pHndlrQueue); ReleaseProgressDialog(GUID_NULL,pProgressDlg,FALSE); } } pHndlrQueue->FreeAllHandlers(); // done with our queue. pHndlrQueue->Release(); pHndlrQueue = NULL; } else { CChoiceDlg *pChoiceDlg; // Bring up the Choice dialog, Let choice dialog actually addes the hanlder items // if there are any so in the future we can async fill in the choices hr = FindChoiceDialog(rclsid,TRUE,nCmdShow,&pChoiceDlg); if (S_OK == hr) { if (FALSE == pChoiceDlg->SetQueueData(rclsid,pHndlrQueue) ) { pHndlrQueue->FreeAllHandlers(); pHndlrQueue->Release(); pHndlrQueue = NULL; hr = E_UNEXPECTED; } ReleaseChoiceDialog(rclsid,pChoiceDlg); } } } else { // if initialize failed and have a queue release it now. if (pHndlrQueue) { pHndlrQueue->FreeAllHandlers(); pHndlrQueue->Release(); pHndlrQueue = NULL; } } // if we successfully added a jobinfo to the queue release our reference. return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::UpdateAll, public // // Synopsis: Handles a programmatic UpdateAll call. // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::UpdateAll(void) { HRESULT hr = S_OK; TCHAR pConnectName[RAS_MaxEntryName + 1]; TCHAR *pConnectionNameArray; if (!LoadString(g_hInst, IDS_LAN_CONNECTION, pConnectName, ARRAYSIZE(pConnectName))) { hr = HRESULT_FROM_WIN32(GetLastError()); return hr; } pConnectionNameArray = pConnectName; // Review - Do we Need proper connection or do we always just // use the last items selected in a manual sync regardless // of the current connection return PrivUpdateAll(0, SYNCMGRFLAG_MANUAL | SYNCMGRFLAG_MAYBOTHERUSER, 0, NULL, 1, &pConnectionNameArray, NULL, FALSE, NULL, 0, 0, FALSE); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::Logon, public // // Synopsis: Handles a Logon notification // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::Logon() { HRESULT hr = E_UNEXPECTED; RegSetUserDefaults(); // Make Sure the UserDefaults are up to date // if on Win9x just call IsNetworkAlive and rely on ConnectionMade // events coming through. Can't just do this yet on NT 5.0 because // not guaranteed to get connectionMades on each logon. hr = PrivHandleAutoSync(SYNCMGRFLAG_CONNECT | SYNCMGRFLAG_MAYBOTHERUSER); return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::Logoff, public // // Synopsis: Handles a Logoff notification // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::Logoff() { HRESULT hr = E_UNEXPECTED; RegSetUserDefaults(); // Make Sure the UserDefaults are up to date hr = PrivHandleAutoSync(SYNCMGRFLAG_PENDINGDISCONNECT | SYNCMGRFLAG_MAYBOTHERUSER); return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::Schedule, public // // Synopsis: Handles a shceduled notification // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- const TCHAR c_szTrayWindow[] = TEXT("Shell_TrayWnd"); STDMETHODIMP CSynchronizeInvoke::Schedule(WCHAR *pszTaskName) { HRESULT hr = E_UNEXPECTED; TCHAR szConnectionName[RAS_MaxEntryName + 1]; TCHAR *pszConnectionName = szConnectionName; CONNECTIONSETTINGS ConnectionSettings; if (!pszTaskName) { Assert(pszTaskName); return E_INVALIDARG; } // validate this is a valid schedule and if no registry data for // it then delete the .job file. // Get the UserName key from the TaskName itself since on NT schedules // can fire if User provided as Password as a different user thant the // current user. int OffsetToUserName = lstrlen(WSZGUID_IDLESCHEDULE) + 1; // +1 for _ char between guid and user name. WCHAR *pszDomainAndUser = pszTaskName + OffsetToUserName; HKEY hkeySchedSync,hkeyDomainUser,hkeySchedName; LONG lRegResult; hkeySchedSync = hkeyDomainUser = hkeySchedName = NULL; // open up keys ourselves so lRegResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE,SCHEDSYNC_REGKEY,0,KEY_READ, &hkeySchedSync); if (ERROR_SUCCESS == lRegResult) { lRegResult = RegOpenKeyEx (hkeySchedSync,pszDomainAndUser,0,KEY_READ, &hkeyDomainUser); } if (ERROR_SUCCESS == lRegResult) { lRegResult = RegOpenKeyEx (hkeyDomainUser,pszTaskName,0,KEY_READ, &hkeySchedName); } // close up the keys if (hkeySchedName) RegCloseKey(hkeySchedName); if (hkeyDomainUser) RegCloseKey(hkeyDomainUser); if (hkeySchedSync) RegCloseKey(hkeySchedSync); // if any of the keys are bad then nix the TS file and return; if ( ERROR_FILE_NOT_FOUND == lRegResult) { // TODO: Call function to delete this .job file when // it is implemented for now just let it fire each time. return E_UNEXPECTED; } // assert is just so it fires if a new Error code occurs // so we make sure we handle it properly Assert(ERROR_SUCCESS == lRegResult); // check to see if this is really and idle and if so foward on to Idle // method WCHAR *pszSchedCookieIdle = WSZGUID_IDLESCHEDULE; int comparelength = (sizeof(WSZGUID_IDLESCHEDULE)/sizeof(WCHAR)) -1; // don't compare null // set the Idle flag instead if (0 == StrCmpNI(pszSchedCookieIdle, pszTaskName, comparelength)) { return Idle(); } // finally made it past verification if you can get a Connection // you can run the schedule. if (RegGetSchedConnectionName(pszTaskName,pszConnectionName,ARRAYSIZE(szConnectionName))) { BOOL fCanMakeConnection = FALSE; DWORD cbCookie = (lstrlen(pszTaskName) + 1)*(sizeof(WCHAR)/sizeof(BYTE)); // if this is a valid schedule then go ahead and read in the settings // by default don't let the connection be made. StringCchCopy(ConnectionSettings.pszConnectionName, ARRAYSIZE(ConnectionSettings.pszConnectionName), pszConnectionName); if (RegGetSchedSyncSettings(&ConnectionSettings,pszTaskName)) { fCanMakeConnection = ConnectionSettings.dwMakeConnection; } // if this schedule can't make the connectione then // check to see if the conneciton is available and if // it isn't bail here. BOOL fConnectionAvailable = FALSE; if (!fCanMakeConnection) { if (S_OK == ConnectObj_IsConnectionAvailable(pszConnectionName)) { fConnectionAvailable = TRUE; } } // add to the queue and let the main progress determine if // can handle the schedule. if (fCanMakeConnection || fConnectionAvailable) { // on a schedule we pass in the schedule name for the cookie data. hr = PrivUpdateAll(SYNCMGRINVOKE_STARTSYNC | SYNCMGRINVOKE_MINIMIZED,SYNCMGRFLAG_SCHEDULED, cbCookie,(BYTE *) pszTaskName,1,&pszConnectionName,pszTaskName,fCanMakeConnection,NULL,0,0,FALSE); } else { hr = S_FALSE; } } else { AssertSz(0,"Schedule has no Connection"); } return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::Idle, public // // Synopsis: Handles an Idle Notifications // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 20-Feb-98 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::Idle() { HRESULT hr = E_UNEXPECTED; // request the idle Lock, If someone already has it then just return. if (S_OK == (hr = RequestIdleLock())) { hr = RunIdle(); // if an error occured setting things up or nothing to do // then release our idle lock. if (S_OK != hr) { ReleaseIdleLock(); } } return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::RunIdle, public // // Synopsis: Runs an Idle. // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 20-Feb-98 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::RunIdle() { // for not just run the Idle as a Connect return PrivHandleAutoSync(SYNCMGRFLAG_IDLE); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::RasPendingDisconnect, private // // Synopsis: Handles a programmatic Ras Pending Disconnect calls. // // // Arguments: // // Returns: Appropriate error codes // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::RasPendingDisconnect(DWORD cbConnectionName, const BYTE *lpConnectionName) { HRESULT hr = E_OUTOFMEMORY; CONNECTIONOBJ *pConnectionObj; // Thread with class factory is FreeThreaded so can block the return // until update is complete. // find connection object for this item so know its liveness. hr = ConnectObj_FindConnectionObj( (TCHAR*) lpConnectionName,TRUE,&pConnectionObj); if (S_OK == hr) { HANDLE hRasPendingEvent; hr = ConnectObj_GetConnectionObjCompletionEvent(pConnectionObj,&hRasPendingEvent); if (S_OK == hr) { hr = PrivAutoSyncOnConnection(SYNCMGRFLAG_PENDINGDISCONNECT | SYNCMGRFLAG_MAYBOTHERUSER, 1,(TCHAR **) &lpConnectionName,hRasPendingEvent); // if successfully invoked the connection then wait for the event // object to get set, if ( (S_OK == hr) && hRasPendingEvent) { WaitForSingleObject(hRasPendingEvent,INFINITE); // review if can determine a timeout } else { // !!!!on failure call close the Connection to make sure // the object gets cleaned up in case the progress queue didn't get kicked off. // If someone is currently using a connection they will be closed which is // the same as if autosync wasn't selected and the User chose to // close while a sync was in progress. ConnectObj_CloseConnection(pConnectionObj); } // Release our hold on the Connection. ConnectObj_ReleaseConnectionObj(pConnectionObj); if (hRasPendingEvent) { CloseHandle(hRasPendingEvent); } } } return hr; } //+--------------------------------------------------------------------------- // // Member: QueryLoadHandlerOnEvent, private // // Synopsis: Determines if Handle needs to be loaded for the specified // Event and Connection. // // // Arguments: [pszClsid] - clsid of handler // [dwSyncFlags] - SyncFlags to pass onto initialize // [cbNumConnectionNames] - Number of ConnectionNames in array // [ppConnectionNames] - array of connection names. // // Returns: TRUE - handler needs to be loaded // FALSE - handler doesn't need to be loaded. // // Modifies: // // History: 24-Aug-98 rogerg Created. // //---------------------------------------------------------------------------- BOOL QueryLoadHandlerOnEvent(TCHAR *pszClsid,DWORD dwSyncFlags,DWORD dwRegistrationFlags, DWORD cbNumConnectionNames,TCHAR **ppConnectionNames) { BOOL fLoadHandler = TRUE; DWORD dwSyncEvent = dwSyncFlags & SYNCMGRFLAG_EVENTMASK; // see if handler is registered for the event // if it is then we always load it. If its not the User had to have checked an item if ( ( (dwSyncEvent == SYNCMGRFLAG_IDLE) && !(dwRegistrationFlags & SYNCMGRREGISTERFLAG_IDLE) ) || ( (dwSyncEvent == SYNCMGRFLAG_CONNECT) && !(dwRegistrationFlags & SYNCMGRREGISTERFLAG_CONNECT) ) || ( (dwSyncEvent == SYNCMGRFLAG_PENDINGDISCONNECT) && !(dwRegistrationFlags & SYNCMGRREGISTERFLAG_PENDINGDISCONNECT) ) ) { DWORD cbCurConnectionName; fLoadHandler = FALSE; for (cbCurConnectionName = 0 ; cbCurConnectionName < cbNumConnectionNames;cbCurConnectionName++) { fLoadHandler |= RegQueryLoadHandlerOnEvent(pszClsid,dwSyncFlags,ppConnectionNames[cbCurConnectionName]); } } return fLoadHandler; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::PrivUpdateAll, private // // Synopsis: Handles a programmatic UpdateAll call. // // !!Warning - Liveness relies on a dialog being created // before return or we could go away when the // caler releases our interface. // // Arguments: [dwInvokeFlags] - InvokeFlags // [dwSyncFlags] - SyncFlags to pass onto initialize // [pszConnectionName] - array of connection names. // [pszScheduleName] - Name of schedule that was fired if a scheduled event. // // Returns: S_OK - If handled result // S_FALSE - if nothing to do (such as no items selected on Idle). // error codes - if errors occured // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::PrivUpdateAll(DWORD dwInvokeFlags,DWORD dwSyncFlags, DWORD cbCookie,const BYTE *lpCooke, DWORD cbNumConnectionNames,TCHAR **ppConnectionNames, TCHAR *pszScheduleName,BOOL fCanMakeConnection,HANDLE hRasPendingDisconnect, ULONG ulIdleRetryMinutes,ULONG ulDelayIdleShutDownTime,BOOL fRetryEnabled) { HRESULT hr = E_OUTOFMEMORY; CHndlrQueue * pHndlrQueue = NULL; CLSID clsidChoice = GUID_NULL; JOBINFO *pJobInfo = NULL; int nCmdShow = (dwInvokeFlags & SYNCMGRINVOKE_MINIMIZED) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL; DWORD dwSyncEvent = (dwSyncFlags & SYNCMGRFLAG_EVENTMASK); // On an UpdateAll // 1 - see if there is an existing UpdateAll choice, If so bring to foreground // 2 - Bring up update All choice dialog. // behavior - If already an Update All choice dialog just pull it to the Front // If Already an UpdateAll progress bar bring it to the front // If Progress Bar but doesn't already contain an updateAll create the choice dialog. Assert(ppConnectionNames && (cbNumConnectionNames >= 1)); Assert( (NULL == pszScheduleName) || (SYNCMGRFLAG_SCHEDULED == dwSyncEvent) || (SYNCMGRFLAG_IDLE == dwSyncEvent) ); // review, temporary for idle. pHndlrQueue = new CHndlrQueue(QUEUETYPE_CHOICE,NULL); if (NULL == pHndlrQueue) return E_OUTOFMEMORY; hr = pHndlrQueue->AddQueueJobInfo(dwSyncFlags,cbNumConnectionNames, ppConnectionNames,pszScheduleName,fCanMakeConnection ,&pJobInfo); // loop through the reg getting the handlers and trying to // create them. if (S_OK == hr) { TCHAR lpName[256]; DWORD cbName = 256; HKEY hkOneStop; CLSID clsid; HANDLERINFO *pHandlerID; BOOL fItemsInQueue = FALSE; hkOneStop = RegGetHandlerTopLevelKey(KEY_READ); if (hkOneStop) { DWORD dwIndex = 0; while ( ERROR_SUCCESS == RegEnumKey(hkOneStop,dwIndex, lpName,cbName) ) { if (S_OK == CLSIDFromString(lpName,&clsid) ) { BOOL fReg; DWORD dwRegistrationFlags; BOOL fLoadHandler = TRUE; fReg = RegGetHandlerRegistrationInfo(clsid,&dwRegistrationFlags); Assert(fReg || (0 == dwRegistrationFlags)); //For scheduled, see if there are any items on this handler, if ((SYNCMGRINVOKE_STARTSYNC & dwInvokeFlags) && (SYNCMGRFLAG_SCHEDULED == dwSyncEvent)) { fLoadHandler = RegSchedHandlerItemsChecked(lpName, ppConnectionNames[0],pszScheduleName); } else if (SYNCMGRINVOKE_STARTSYNC & dwInvokeFlags) { fLoadHandler = QueryLoadHandlerOnEvent(lpName,dwSyncFlags,dwRegistrationFlags, cbNumConnectionNames,ppConnectionNames); } if (fLoadHandler) { if (S_OK == pHndlrQueue->AddHandler(&pHandlerID,pJobInfo,dwRegistrationFlags)) { pHndlrQueue->CreateServer(pHandlerID,&clsid); } } } dwIndex++; } RegCloseKey(hkOneStop); } // Initialize the items. CLSID pHandlerClsid; while (S_OK == pHndlrQueue->FindFirstHandlerInState(HANDLERSTATE_INITIALIZE,GUID_NULL,&pHandlerID,&pHandlerClsid)) { pHndlrQueue->Initialize(pHandlerID,0,dwSyncFlags, cbCookie,lpCooke); } // can release jobinfo since handlers need to hold their own addref. if (pJobInfo) { pHndlrQueue->ReleaseJobInfoExt(pJobInfo); pJobInfo = NULL; } // if start invoke need to add the handlers items to the queue before // transferring while (S_OK == pHndlrQueue->FindFirstHandlerInState(HANDLERSTATE_ADDHANDLERTEMS,GUID_NULL,&pHandlerID,&pHandlerClsid)) { DWORD cbNumItemsAdded; // CODE REVIEW: // NOTENOTE: // What if one of these additems fails ? hr = pHndlrQueue->AddHandlerItemsToQueue(pHandlerID,&cbNumItemsAdded); // if an item was added, then there are items in the queue if (cbNumItemsAdded) { fItemsInQueue = TRUE; } } // // Move handlers that won't establish connections to end // of handler list. // pHndlrQueue->SortHandlersByConnection(); if (SYNCMGRINVOKE_STARTSYNC & dwInvokeFlags) { CProgressDlg *pProgressDlg; CLSID clsid_Progress = GUID_NULL; // For Idle we want to use the idle progress dialog // currently progress dialog relies on some globals so // need to change that first before checking this in if (SYNCMGRFLAG_IDLE == dwSyncEvent) { clsid_Progress = GUID_PROGRESSDLGIDLE; } // if not items are selected, just free the queue. // Review - it would be better to always call Progress and progress // itself not show until there are items to synchronize if (pHndlrQueue->AreAnyItemsSelectedInQueue()) { hr = FindProgressDialog(clsid_Progress,TRUE,nCmdShow,&pProgressDlg); if (S_OK == hr) { // for an Idle we now request the defaults for retryIdle // and delay shutdown, and change the queue order // based on the last item if (SYNCMGRFLAG_IDLE == dwSyncEvent) { CLSID clsidLastHandler; pProgressDlg->SetIdleParams(ulIdleRetryMinutes, ulDelayIdleShutDownTime, fRetryEnabled); if (S_OK == GetLastIdleHandler(&clsidLastHandler)) { pHndlrQueue->ScrambleIdleHandlers(clsidLastHandler); } } hr = pProgressDlg->TransferQueueData(pHndlrQueue); ReleaseProgressDialog(clsid_Progress,pProgressDlg,FALSE); } } else { hr = S_FALSE; // return S_FALSE IF NOTHING TO DO. } pHndlrQueue->FreeAllHandlers(); // done with our queue. pHndlrQueue->Release(); pHndlrQueue = NULL; } else { BOOL fDontShowIfNoItems = ( (SYNCMGRFLAG_CONNECT == dwSyncEvent) || (SYNCMGRFLAG_PENDINGDISCONNECT == dwSyncEvent ) ); // if the choice has been requested by a logon/logoff event and // there aren't any items in the queue for the User to choose then // if you want to turn on the code to now display anything // turn on this If statement. For now we always show the choice. // CODE REVIEW: // NOTENOTE: // This is ALWAYS executed.. if (1 /* !fDontShowIfNoItems || fItemsInQueue */) { // Bring up the Choice dialog, Let choice dialog actually addes the hanlder items // if there are any so in the future we can async fill in the choices CChoiceDlg *pChoiceDlg; hr = FindChoiceDialog(clsidChoice,TRUE,nCmdShow,&pChoiceDlg); if (S_OK == hr) { if (FALSE == pChoiceDlg->SetQueueData(clsidChoice,pHndlrQueue) ) { hr = E_UNEXPECTED; } else { pHndlrQueue = NULL; // set queue to NULL since Choice dialog owns it now. } ReleaseChoiceDialog(clsidChoice,pChoiceDlg); } } // release our queue if still have it otherwise choice owns it. if (pHndlrQueue) { pHndlrQueue->FreeAllHandlers(); pHndlrQueue->Release(); } } } return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::PrivHandleAutoSync, private // // Synopsis: Handles an AutoSync Update. Figures out what connections // if any are active and invoke an AutoSync on each one. // // Arguments: [dwSyncFlags] - SyncFlags to pass onto initialize // // Returns: S_OK - sync was started // S_FALSE - nothing to do // appropriate error codes. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::PrivHandleAutoSync(DWORD dwSyncFlags) { HRESULT hr = E_UNEXPECTED; DWORD dwFlags = 0; LPNETAPI pNetApi = NULL; DWORD cbNumWanConnections = 0; LPRASCONN pRasConn = NULL; pNetApi = gSingleNetApiObj.GetNetApiObj(); if (NULL == pNetApi) return S_FALSE; g_InAutoSync = TRUE; if (pNetApi->IsNetworkAlive(&dwFlags)) { TCHAR **pConnections; // array of connection names. End with NULL; ULONG ulConnectionCount = 0; if (NETWORK_ALIVE_LAN & dwFlags) { // We curently don't care about these error results. // PrivAutoSyncOnConnection(dwSyncFlags,LANCONNECTIONNAME,NULL); // Review what we want this to do. ulConnectionCount += 1; } // loop through Ras Connections. if ( NETWORK_ALIVE_WAN & dwFlags) { if (S_OK == pNetApi->GetWanConnections(&cbNumWanConnections,&pRasConn) && (pRasConn) ) { ulConnectionCount += cbNumWanConnections; } else { cbNumWanConnections = 0; pRasConn = NULL; } } // allocate array buffer for connections + 1 more for NULL if (ulConnectionCount && (pConnections = (TCHAR **) ALLOC(sizeof(TCHAR *)*(ulConnectionCount + 1)))) { TCHAR **pCurConnection = pConnections; TCHAR *pLanConnection = NULL; // initialize the array. if (NETWORK_ALIVE_LAN & dwFlags) { pLanConnection = (TCHAR *) ALLOC(sizeof(TCHAR )*(MAX_PATH + 1)); if (pLanConnection) { if (LoadString(g_hInst, IDS_LAN_CONNECTION, pLanConnection, MAX_PATH)) { *pCurConnection = pLanConnection; ++pCurConnection; } } } while (cbNumWanConnections) { cbNumWanConnections--; *pCurConnection = pRasConn[cbNumWanConnections].szEntryName; ++pCurConnection; } *pCurConnection = NULL; // set the last connection to NULL; // now autosync these puppies hr = PrivAutoSyncOnConnection(dwSyncFlags,ulConnectionCount,pConnections,NULL); if (pLanConnection) { FREE(pLanConnection); } if (pRasConn) { pNetApi->FreeWanConnections(pRasConn); } if (pConnections) { FREE(pConnections); } } } g_InAutoSync = FALSE; if ( pNetApi ) pNetApi->Release(); return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::PrivAutoSyncOnConnection, private // // Synopsis: Handles an AutoSync Update. Given the SyncFlags and Connection // determines if anything should be done on this connection // and if so invokes it. // // Arguments: [dwSyncFlags] - SyncFlags to pass onto initialize // [ppConnectionNames] - array of connectnames that apply to this request // // Returns: Appropriate error codes // // Modifies: // // History: 08-Dec-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::PrivAutoSyncOnConnection(DWORD dwSyncFlags,DWORD cbNumConnectionNames, TCHAR **ppConnectionNames,HANDLE hRasPendingEvent) { CONNECTIONSETTINGS ConnectSettings; DWORD dwSyncEvent; TCHAR **ppWorkerConnectionNames = NULL; DWORD cbNumWorkerConnections = 0; DWORD cbIndexCheck; DWORD dwPromptMeFirst = 0; ULONG ulIdleRetryMinutes; ULONG ulDelayIdleShutDownTime; BOOL fRetryEnabled = FALSE; HRESULT hr = S_FALSE; // assert there is at least one connection in the request Assert(ppConnectionNames && cbNumConnectionNames >= 1); if (NULL == ppConnectionNames || 0 == cbNumConnectionNames ) return S_FALSE; ppWorkerConnectionNames = (TCHAR **) ALLOC(sizeof(TCHAR**) * cbNumConnectionNames); if (NULL == ppWorkerConnectionNames) { return E_OUTOFMEMORY; } dwSyncEvent = (dwSyncFlags & SYNCMGRFLAG_EVENTMASK); // loop through all the connections and move any of the ones that // are valid into our ppWorkerConnections name array. TCHAR **ppCurWorkerConnectionNamesIndex = ppWorkerConnectionNames; TCHAR **ppConnectionsNameIndex = ppConnectionNames; for (cbIndexCheck = 0; cbIndexCheck < cbNumConnectionNames; cbIndexCheck++) { StringCchCopy(ConnectSettings.pszConnectionName, ARRAYSIZE(ConnectSettings.pszConnectionName), *ppConnectionsNameIndex); // See if should do anything on this connection. if (RegGetSyncSettings(SYNCMGRFLAG_IDLE == dwSyncEvent ? SYNCTYPE_IDLE : SYNCTYPE_AUTOSYNC,&ConnectSettings)) { if ( (((SYNCMGRFLAG_CONNECT == dwSyncEvent) && ConnectSettings.dwLogon)) ||(((SYNCMGRFLAG_PENDINGDISCONNECT == dwSyncEvent) && ConnectSettings.dwLogoff)) ||(((SYNCMGRFLAG_IDLE == dwSyncEvent) && ConnectSettings.dwIdleEnabled)) ) { *ppCurWorkerConnectionNamesIndex = *ppConnectionsNameIndex; ++ppCurWorkerConnectionNamesIndex; ++cbNumWorkerConnections; // update the variables for connection, for autosync if dwPromptMeFirst // is set on any match connection switch (dwSyncEvent) { case SYNCMGRFLAG_IDLE: // minimum retry idle values win. if ( (1 == cbNumWorkerConnections) || (ConnectSettings.ulIdleRetryMinutes < ulIdleRetryMinutes) ) { ulIdleRetryMinutes = ConnectSettings.ulIdleRetryMinutes; } // maximum wait for shutdown wins. if ( (1 == cbNumWorkerConnections) || (ConnectSettings.ulDelayIdleShutDownTime > ulDelayIdleShutDownTime) ) { ulDelayIdleShutDownTime = ConnectSettings.ulDelayIdleShutDownTime; } // if any connection has retry after xxx minutes set to bool then retry if (ConnectSettings.dwRepeatSynchronization) { fRetryEnabled = TRUE; } break; case SYNCMGRFLAG_PENDINGDISCONNECT: case SYNCMGRFLAG_CONNECT: // if any connection is set to prompt then prompt. if (ConnectSettings.dwPromptMeFirst) { dwPromptMeFirst = ConnectSettings.dwPromptMeFirst; } break; } } } ++ppConnectionsNameIndex; } // if we found any connections to actually do work on start the sync off. if (cbNumWorkerConnections > 0) { DWORD dwInvokeFlag = 0; switch (dwSyncEvent) { case SYNCMGRFLAG_IDLE: dwInvokeFlag |= SYNCMGRINVOKE_MINIMIZED | SYNCMGRINVOKE_STARTSYNC; break; case SYNCMGRFLAG_PENDINGDISCONNECT: case SYNCMGRFLAG_CONNECT: if (!dwPromptMeFirst) { dwInvokeFlag |= SYNCMGRINVOKE_STARTSYNC; } break; default: AssertSz(0,"Unknown SyncEvent"); break; } // perform the Update hr = PrivUpdateAll(dwInvokeFlag,dwSyncFlags,0,NULL, cbNumWorkerConnections, ppWorkerConnectionNames,NULL,FALSE,hRasPendingEvent, ulIdleRetryMinutes, ulDelayIdleShutDownTime,fRetryEnabled); } if (ppWorkerConnectionNames) { FREE(ppWorkerConnectionNames); } return hr; } // default Unknown implementation //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::CPrivUnknown::QueryInterface, public // // Synopsis: Standard QueryInterface // // Arguments: [iid] - Interface ID // [ppvObj] - Object return // // Returns: Appropriate status code // // Modifies: [ppvObj] // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::CPrivUnknown::QueryInterface(REFIID riid, LPVOID FAR *ppv) { *ppv = NULL; if (IsEqualIID(riid, IID_IUnknown)) { *ppv = this; } else if (IsEqualIID(riid, IID_IPrivSyncMgrSynchronizeInvoke)) { *ppv = (IPrivSyncMgrSynchronizeInvoke *) m_pSynchInvoke; } #ifdef _SENS else if (IsEqualIID(riid, IID_ISensNetwork)) { *ppv = (ISensNetwork *) &(m_pSynchInvoke->m_PrivSensNetwork); } else if (IsEqualIID(riid, IID_ISensLogon)) { *ppv = (ISensLogon *) &(m_pSynchInvoke->m_PrivSensLogon); } // in final this shouldn't return anything until LCE change, change // depending on which interface we want to test. else if (IsEqualIID(riid, IID_IDispatch)) { *ppv = &(m_pSynchInvoke->m_PrivSensLogon); } #endif // _SENS if (*ppv) { m_pSynchInvoke->m_pUnkOuter->AddRef(); return S_OK; } return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::CPrivUnknown::AddRef, public // // Synopsis: Add reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivUnknown::AddRef() { ULONG cRefs; cRefs = InterlockedIncrement((LONG *)& m_pSynchInvoke->m_cRef); return cRefs; } //+--------------------------------------------------------------------------- // // Member: CSychrononizeInvoke::CPrivUnknown::Release, public // // Synopsis: Release reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivUnknown::Release() { ULONG cRefs; cRefs = InterlockedDecrement( (LONG *) &m_pSynchInvoke->m_cRef); if (0 == cRefs) { delete m_pSynchInvoke; } return cRefs; } #ifdef _SENS // SENS Network connect Interfaces STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::QueryInterface(REFIID riid, LPVOID FAR *ppv) { return m_pSynchInvoke->m_pUnkOuter->QueryInterface(riid,ppv); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::AddRef, public // // Synopsis: Add reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivSensNetwork::AddRef() { return m_pSynchInvoke->m_pUnkOuter->AddRef(); } //+--------------------------------------------------------------------------- // // Member: CSychrononizeInvoke::Release, public // // Synopsis: Release reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivSensNetwork::Release() { return m_pSynchInvoke->m_pUnkOuter->Release(); } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::GetTypeInfoCount( UINT *pCountITypeInfo ) { *pCountITypeInfo = 1; return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::GetTypeInfo( UINT iTypeInfo, LCID lcid, ITypeInfo **ppITypeInfo ) { HRESULT hr; if (iTypeInfo) { return DISP_E_BADINDEX; } if (S_OK == (hr = m_pSynchInvoke->GetNetworkTypeInfo())) { // if got a typelib addref it and hand it out. m_pSynchInvoke->m_pITypeInfoNetwork->AddRef(); *ppITypeInfo = m_pSynchInvoke->m_pITypeInfoNetwork; } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::GetIDsOfNames( REFIID riid, LPOLESTR *arrNames, UINT cNames, LCID lcid, DISPID *arrDispIDs) { HRESULT hr; if (S_OK == (hr = m_pSynchInvoke->GetNetworkTypeInfo())) { hr = m_pSynchInvoke->m_pITypeInfoNetwork->GetIDsOfNames( arrNames, cNames, arrDispIDs ); } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::Invoke( DISPID dispID, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvarResult, EXCEPINFO *pExecpInfo, UINT *puArgErr ) { HRESULT hr; if (S_OK == (hr = m_pSynchInvoke->GetNetworkTypeInfo())) { hr = m_pSynchInvoke->m_pITypeInfoNetwork->Invoke( (IDispatch*) this, dispID, wFlags, pDispParams, pvarResult, pExecpInfo, puArgErr); } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::ConnectionMade( BSTR bstrConnection, ULONG ulType, LPSENS_QOCINFO pQOCInfo ) { HRESULT hr = E_UNEXPECTED; TCHAR pszConnectionName[RAS_MaxEntryName + 1]; TCHAR *pConnectionNameArray; if (g_InAutoSync) // Review logic, for now if in logon just return. { return S_OK; } RegSetUserDefaults(); // Make Sure the UserDefaults are up to date // if Lan connection use our hardcoded value, else use the // connection name given to use. if (ulType & NETWORK_ALIVE_LAN) { LoadString(g_hInst, IDS_LAN_CONNECTION, pszConnectionName,ARRAYSIZE(pszConnectionName)); } else { StringCchCopy(pszConnectionName, ARRAYSIZE(pszConnectionName), bstrConnection); } pConnectionNameArray = pszConnectionName; if (pszConnectionName) { hr = m_pSynchInvoke->PrivAutoSyncOnConnection(SYNCMGRFLAG_CONNECT | SYNCMGRFLAG_MAYBOTHERUSER,1, &pConnectionNameArray, NULL); } return hr; } // // CODE REVIEW: // NOTENOTE: // Can we remove this function ? STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::ConnectionMadeNoQOCInfo( BSTR bstrConnection, ULONG ulType ) { /* AssertSz(0,"ConnectionMadeNoQOCInfo called"); TCHAR *pszConnectionName = bstrConnection; // m_pSynchInvoke->PrivAutoSyncOnConnection(SYNCMGRFLAG_CONNECT,pszConnectionName, // NULL); */ return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::ConnectionLost( BSTR bstrConnection, ULONG ulType ) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::BeforeDisconnect( BSTR bstrConnection, ULONG ulType ) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::DestinationReachable( BSTR bstrDestination, BSTR bstrConnection, ULONG ulType, LPSENS_QOCINFO pQOCInfo ) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensNetwork::DestinationReachableNoQOCInfo( BSTR bstrDestination, BSTR bstrConnection, ULONG ulType ) { return S_OK; } // ISensLogon/Logoff Events STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::QueryInterface(REFIID riid, LPVOID FAR *ppv) { return m_pSynchInvoke->m_pUnkOuter->QueryInterface(riid,ppv); } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::AddRef, public // // Synopsis: Add reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivSensLogon::AddRef() { return m_pSynchInvoke->m_pUnkOuter->AddRef(); } //+--------------------------------------------------------------------------- // // Member: CSychrononizeInvoke::Release, public // // Synopsis: Release reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CSynchronizeInvoke::CPrivSensLogon::Release() { return m_pSynchInvoke->m_pUnkOuter->Release(); } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::GetTypeInfoCount( UINT *pCountITypeInfo ) { *pCountITypeInfo = 1; return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::GetTypeInfo( UINT iTypeInfo, LCID lcid, ITypeInfo **ppITypeInfo ) { HRESULT hr; if (iTypeInfo) { return DISP_E_BADINDEX; } if (S_OK == (hr = m_pSynchInvoke->GetLogonTypeInfo())) { // if got a typelib addref it and hand it out. m_pSynchInvoke->m_pITypeInfoLogon->AddRef(); *ppITypeInfo = m_pSynchInvoke->m_pITypeInfoLogon; } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::GetIDsOfNames( REFIID riid, LPOLESTR *arrNames, UINT cNames, LCID lcid, DISPID *arrDispIDs) { HRESULT hr; if (S_OK == (hr = m_pSynchInvoke->GetLogonTypeInfo())) { hr = m_pSynchInvoke->m_pITypeInfoLogon->GetIDsOfNames( arrNames, cNames, arrDispIDs ); } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::Invoke( DISPID dispID, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvarResult, EXCEPINFO *pExecpInfo, UINT *puArgErr ) { HRESULT hr; if (S_OK == (hr = m_pSynchInvoke->GetLogonTypeInfo())) { hr = m_pSynchInvoke->m_pITypeInfoLogon->Invoke( (IDispatch*) this, dispID, wFlags, pDispParams, pvarResult, pExecpInfo, puArgErr); } return hr; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::Logon(BSTR bstrUserName) { m_pSynchInvoke->Logon(); return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::Logoff(BSTR bstrUserName) { m_pSynchInvoke->Logoff(); return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::Startup(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::StartShell(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::Shutdown(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::DisplayLock(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::DisplayUnlock(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::StartScreenSaver(BSTR bstrUserName) { return S_OK; } STDMETHODIMP CSynchronizeInvoke::CPrivSensLogon::StopScreenSaver(BSTR bstrUserName) { return S_OK; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::GetLogonTypeInfo, private // // Synopsis: Loads the TypeInfo object for the Sens // Logon Information. // // Arguments: // // Returns: S_OK if successfully loaded the TypeInfo. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //+--------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::GetLogonTypeInfo() { HRESULT hr; ITypeLib *pITypeLib; if (m_pITypeInfoLogon) return S_OK; hr = LoadRegTypeLib( LIBID_SensEvents, 1 /* MAJOR_VER */ , 0 /* MINOR_VER */ , 0 /* DEFAULT_LCID */, &pITypeLib ); if (S_OK == hr) { hr = pITypeLib->GetTypeInfoOfGuid( IID_ISensLogon, &m_pITypeInfoLogon ); pITypeLib->Release(); } if (S_OK != hr) { m_pITypeInfoLogon = NULL; // don't rely on call not to leave this alone. } return hr; } //+--------------------------------------------------------------------------- // // Member: CSynchronizeInvoke::GetNetworkTypeInfo, private // // Synopsis: Loads the TypeInfo object for the Sens // Network Information. // // Arguments: // // Returns: S_OK if successfully loaded the TypeInfo. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //+--------------------------------------------------------------------------- STDMETHODIMP CSynchronizeInvoke::GetNetworkTypeInfo() { HRESULT hr; ITypeLib *pITypeLib; if (m_pITypeInfoNetwork) return S_OK; hr = LoadRegTypeLib( LIBID_SensEvents, 1 /* MAJOR_VER */ , 0 /* MINOR_VER */ , 0 /* DEFAULT_LCID */, &pITypeLib ); if (S_OK == hr) { hr = pITypeLib->GetTypeInfoOfGuid( IID_ISensNetwork, &m_pITypeInfoNetwork ); pITypeLib->Release(); } if (S_OK != hr) { m_pITypeInfoNetwork = NULL; // don't rely on call not to leave this alone. } return hr; } #endif // _SENS