SERVICE::SERVICE (LPSERVER lpServerParent, LPTSTR pszName) { m_lpiServer = lpServerParent->GetIdentifier(); m_lpiCell = m_lpiCell; m_lpiThis = NULL; lstrcpy (m_szName, pszName); m_fStatusOutOfDate = TRUE; memset (&m_ss, 0x00, sizeof(SERVICESTATUS)); }
BOOL FILESET::RefreshStatus (BOOL fNotify, ULONG *pStatus) { BOOL rc = TRUE; DWORD status = 0; if (m_fStatusOutOfDate && (m_wGhost & GHOST_HAS_SERVER_ENTRY)) { m_fStatusOutOfDate = FALSE; if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); LPSERVER lpServer; if ((lpServer = OpenServer (&status)) == NULL) rc = FALSE; else { PVOID hCell; PVOID hVOS; if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL) rc = FALSE; else { WORKERPACKET wp; wp.wpVosVolumeGet.hCell = hCell; wp.wpVosVolumeGet.hServer = hVOS; wp.wpVosVolumeGet.idPartition = NO_PARTITION; wp.wpVosVolumeGet.idVolume = m_idVolume; LPAGGREGATE lpAggregate; if ((lpAggregate = m_lpiAggregate->OpenAggregate()) != NULL) { wp.wpVosVolumeGet.idPartition = lpAggregate->GetID(); lpAggregate->Close(); } if (!Worker_DoTask (wtaskVosVolumeGet, &wp, &status)) rc = FALSE; else { SetStatusFromVOS (&wp.wpVosVolumeGet.Data); if ((lpAggregate = m_lpiAggregate->OpenAggregate()) != NULL) { lpAggregate->InvalidateAllocation(); lpAggregate->Close(); } } lpServer->CloseVosObject(); } lpServer->Close(); } if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status)); } if (pStatus && !rc) *pStatus = status; return TRUE; }
void DispatchNotification_AltThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams) { LPIDENT lpiEvt = pParams->lpi1; switch (evt) { case evtRefreshStatusEnd: if (lpiEvt && (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset())) { Alert_RemoveSecondary (lpiEvt); Alert_Scout_QueueCheckServer (lpiEvt); } if (lpiEvt && lpiEvt->fIsServer()) { LPSERVER_PREF lpsp; if ((lpsp = (LPSERVER_PREF)lpiEvt->GetUserParam()) != NULL) { LPSERVER lpServer; if ((lpServer = lpiEvt->OpenServer()) != NULL) { if (lpsp->fIsMonitored != lpServer->fIsMonitored()) { g.sub = Subsets_SetMonitor (g.sub, lpiEvt, lpServer->fIsMonitored()); UpdateDisplay_ServerWindow (FALSE, lpiEvt); } lpsp->fIsMonitored = lpServer->fIsMonitored(); lpServer->Close(); } } Alert_Scout_ServerStatus (lpiEvt, pParams->status); } break; // When we get a create request, use the object's Get/SetUserParam() // methods to attach an allocated structure to the thing--the structure // contains the preferences for the server/fileset/etc (for instance, // its warning threshholds, any current scout problems, etc). // On delete requests, free that structure. // case evtCreate: if (lpiEvt->fIsServer()) { PVOID pPref = Server_LoadPreferences (lpiEvt); lpiEvt->SetUserParam (pPref); // Should this server be monitored? // if (!Subsets_fMonitorServer (g.sub, lpiEvt)) { LPSERVER lpServer; if ((lpServer = lpiEvt->OpenServer()) != NULL) { lpServer->SetMonitor (FALSE); lpServer->Close(); } } Alert_Scout_SetOutOfDate (lpiEvt); } else if (lpiEvt->fIsService()) { PVOID pPref = Services_LoadPreferences (lpiEvt); lpiEvt->SetUserParam (pPref); } else if (lpiEvt->fIsAggregate()) { PVOID pPref = Aggregates_LoadPreferences (lpiEvt); lpiEvt->SetUserParam (pPref); } else if (lpiEvt->fIsFileset()) { PVOID pPref = Filesets_LoadPreferences (lpiEvt); lpiEvt->SetUserParam (pPref); } if (!lpiEvt->fIsCell()) { Alert_Scout_QueueCheckServer (lpiEvt); } break; // When we get a create request, use the object's Get/SetUserParam() // methods to attach an allocated structure to the thing--the structure // contains the preferences for the server/fileset/etc (for instance, // its warning threshholds, any current scout problems, etc). // On delete requests, free that structure. // case evtDestroy: if (lpiEvt->fIsServer()) { PVOID pPref = lpiEvt->GetUserParam(); lpiEvt->SetUserParam (0); if (pPref) Delete (pPref); } else if (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset()) { Alert_RemoveSecondary (lpiEvt); PVOID pPref = lpiEvt->GetUserParam(); lpiEvt->SetUserParam (0); if (pPref) Delete (pPref); } break; } }
size_t Server_GetAlertCount (LPSERVER lpServer) { return Alert_GetCount (lpServer->GetIdentifier()); }
BOOL Alert_Scout_CheckServer (LPSERVER lpServer) { BOOL rc = TRUE; LPSERVER_PREF lpsp; if ((lpsp = (LPSERVER_PREF)lpServer->GetUserParam()) != NULL) { LPOBJECTALERTS lpoa; if ((lpoa = Alert_GetObjectAlerts (lpServer->GetIdentifier())) != NULL) { PostNotification (evtScoutBegin, lpServer->GetIdentifier()); BOOL fChangedServerAlerts = FALSE; DWORD dwTickNextTestWhenStarted = lpoa->dwTickNextTest; // First look through the server's aggregates and filesets, to // find any which have usages over their warning threshholds. // HENUM heAggregate; for (LPAGGREGATE lpAggregate = lpServer->AggregateFindFirst (&heAggregate); lpAggregate; lpAggregate = lpServer->AggregateFindNext (&heAggregate)) { BOOL fChangedAggregateAlerts = FALSE; LPIDENT lpiAggregate = lpAggregate->GetIdentifier(); LPOBJECTALERTS lpoaAggregate; if ((lpoaAggregate = Alert_GetObjectAlerts (lpAggregate->GetIdentifier())) != NULL) { for (size_t iAlert = 0; iAlert < lpoaAggregate->nAlerts; ) { if ( (lpoaAggregate->aAlerts[ iAlert ].alert == alertFULL) || (lpoaAggregate->aAlerts[ iAlert ].alert == alertOVERALLOC) || (lpoaAggregate->aAlerts[ iAlert ].alert == alertNO_SVRENT) ) { fChangedAggregateAlerts = TRUE; fChangedServerAlerts = TRUE; Alert_Remove (lpAggregate->GetIdentifier(), iAlert); } else ++iAlert; } LPAGGREGATE_PREF lpap; if ((lpap = (LPAGGREGATE_PREF)lpAggregate->GetUserParam()) != NULL) { short wGhost = lpAggregate->GetGhostStatus(); if (lpsp->fWarnAggNoServ && !(wGhost & GHOST_HAS_SERVER_ENTRY)) { ALERTINFO ai; ai.alert = alertNO_SVRENT; Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai); fChangedAggregateAlerts = TRUE; fChangedServerAlerts = TRUE; } if (lpsp->fWarnAggAlloc && lpap->fWarnAggAlloc) { AGGREGATESTATUS as; if (lpAggregate->GetStatus (&as, TRUE)) { if (as.ckStorageAllocated > as.ckStorageTotal) { ALERTINFO ai; ai.alert = alertOVERALLOC; ai.aiOVERALLOC.ckAllocated = as.ckStorageAllocated; ai.aiOVERALLOC.ckCapacity = as.ckStorageTotal; Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai); fChangedAggregateAlerts = TRUE; fChangedServerAlerts = TRUE; } } } short perWarnAggFull = lpap->perWarnAggFull; if (perWarnAggFull == -1) perWarnAggFull = lpsp->perWarnAggFull; if (perWarnAggFull != 0) { AGGREGATESTATUS as; if (lpAggregate->GetStatus (&as, TRUE)) { if (as.ckStorageTotal != 0) { short perNow = (short)( (double)(as.ckStorageTotal - as.ckStorageFree) * 100.0 / (double)(as.ckStorageTotal) ); if (perNow > perWarnAggFull) { ALERTINFO ai; ai.alert = alertFULL; ai.aiFULL.perWarning = perWarnAggFull; ai.aiFULL.ckWarning = (ULONG)( (double)perWarnAggFull * (double)(as.ckStorageTotal) / 100.0 ); Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai); fChangedAggregateAlerts = TRUE; fChangedServerAlerts = TRUE; } } } } } } HENUM heFileset; for (LPFILESET lpFileset = lpAggregate->FilesetFindFirst (&heFileset); lpFileset; lpFileset = lpAggregate->FilesetFindNext (&heFileset)) { BOOL fChangedFilesetAlerts = FALSE; LPIDENT lpiFileset = lpFileset->GetIdentifier(); LPOBJECTALERTS lpoaFileset; if ((lpoaFileset = Alert_GetObjectAlerts (lpFileset->GetIdentifier())) != NULL) { for (size_t iAlert = 0; iAlert < lpoaFileset->nAlerts; ) { if ( (lpoaFileset->aAlerts[ iAlert ].alert == alertFULL) || (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_NO_VNODE) || (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_NO_SERVICE) || (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_OFFLINE) || (lpoaFileset->aAlerts[ iAlert ].alert == alertNO_VLDBENT) || (lpoaFileset->aAlerts[ iAlert ].alert == alertNO_SVRENT) ) { fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; Alert_Remove (lpFileset->GetIdentifier(), iAlert); } else ++iAlert; } } LPFILESET_PREF lpfp; if ((lpfp = (LPFILESET_PREF)lpFileset->GetUserParam()) != NULL) { FILESETSTATUS fs; if (lpFileset->GetStatus (&fs, TRUE)) { if (fs.State & fsNO_VNODE) { ALERTINFO ai; ai.alert = alertSTATE_NO_VNODE; ai.aiSTATE.State = fs.State; Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } else if (fs.State & fsNO_SERVICE) { ALERTINFO ai; ai.alert = alertSTATE_NO_SERVICE; ai.aiSTATE.State = fs.State; Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } else if (fs.State & fsOFFLINE) { ALERTINFO ai; ai.alert = alertSTATE_OFFLINE; ai.aiSTATE.State = fs.State; Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } short perWarnSetFull = lpfp->perWarnSetFull; if (perWarnSetFull == -1) perWarnSetFull = lpsp->perWarnSetFull; if (perWarnSetFull != 0) { if (fs.Type == ftREADWRITE) { if (fs.ckQuota != 0) { short perNow = (short)( (double)(fs.ckUsed) * 100.0 / (double)(fs.ckQuota) ); if (perNow > perWarnSetFull) { ALERTINFO ai; ai.alert = alertFULL; ai.aiFULL.perWarning = perWarnSetFull; ai.aiFULL.ckWarning = (ULONG)( (double)perWarnSetFull * (double)(fs.ckQuota) / 100.0 ); Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } } } } } short wGhost = lpFileset->GetGhostStatus(); if (lpsp->fWarnSetNoVLDB && !(wGhost & GHOST_HAS_VLDB_ENTRY)) { ALERTINFO ai; ai.alert = alertNO_VLDBENT; Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } if (lpsp->fWarnSetNoServ && !(wGhost & GHOST_HAS_SERVER_ENTRY) && !(fs.Type == ftREPLICA)) { ALERTINFO ai; ai.alert = alertNO_SVRENT; Alert_AddPrimary (lpFileset->GetIdentifier(), &ai); fChangedFilesetAlerts = TRUE; fChangedServerAlerts = TRUE; } } lpFileset->Close(); if (fChangedFilesetAlerts) { PostNotification (evtAlertsChanged, lpiFileset); } } lpAggregate->Close(); if (fChangedAggregateAlerts) { PostNotification (evtAlertsChanged, lpiAggregate); } } // Next look through the server's servces to find any // which have stopped. // HENUM heService; for (LPSERVICE lpService = lpServer->ServiceFindFirst (&heService); lpService; lpService = lpServer->ServiceFindNext (&heService)) { BOOL fChangedServiceAlerts = FALSE; LPIDENT lpiService = lpService->GetIdentifier(); LPOBJECTALERTS lpoaService; if ((lpoaService = Alert_GetObjectAlerts (lpService->GetIdentifier())) != NULL) { for (size_t iAlert = 0; iAlert < lpoaService->nAlerts; ) { if (lpoaService->aAlerts[ iAlert ].alert == alertSTOPPED) { fChangedServiceAlerts = TRUE; fChangedServerAlerts = TRUE; Alert_Remove (lpService->GetIdentifier(), iAlert); } else ++iAlert; } LPSERVICE_PREF lpcp; if ((lpcp = (LPSERVICE_PREF)lpService->GetUserParam()) != NULL) { if (lpcp->fWarnSvcStop && lpsp->fWarnSvcStop) { SERVICESTATUS ss; if (lpService->GetStatus (&ss, TRUE)) { if (ss.state != SERVICESTATE_RUNNING) { ALERTINFO ai; ai.alert = alertSTOPPED; memcpy (&ai.aiSTOPPED.stStopped, &ss.timeLastStop, sizeof(SYSTEMTIME)); memcpy (&ai.aiSTOPPED.stLastError, &ss.timeLastFail, sizeof(SYSTEMTIME)); ai.aiSTOPPED.errLastError = ss.dwErrLast; Alert_AddPrimary (lpService->GetIdentifier(), &ai); fChangedServiceAlerts = TRUE; fChangedServerAlerts = TRUE; } } } } } lpService->Close(); if (fChangedServiceAlerts) { PostNotification (evtAlertsChanged, lpiService); } } if (rc && (dwTickNextTestWhenStarted == lpoa->dwTickNextTest)) { Alert_Scout_SetUpToDate (lpoa); } if (fChangedServerAlerts) { PostNotification (evtAlertsChanged, lpServer->GetIdentifier()); } PostNotification (evtScoutEnd, lpServer->GetIdentifier()); } } return rc; }
DWORD WINAPI Alert_ScoutProc (LPVOID lp) { // We'll keep working forever... // for (;;) { AfsClass_Enter(); LPCELL lpCell = (g.lpiCell == NULL) ? NULL : g.lpiCell->OpenCell(); if (lpCell != NULL) { // See if our credentials have expired // CheckForExpiredCredentials(); // See if any new servers have arrived, or old servers disappeared. // lpCell->RefreshServerList(); // Check all the out-of-date servers we can find. // HENUM hEnum; for (LPSERVER lpServer = lpCell->ServerFindFirst (&hEnum); lpServer; lpServer = lpCell->ServerFindNext (&hEnum)) { LPIDENT lpiServer = lpServer->GetIdentifier(); LPOBJECTALERTS lpoa; if ( ((lpoa = Alert_GetObjectAlerts (lpiServer)) != NULL) && (lpoa->dwTickNextTest <= GetTickCount()) ) { // Okay! We've found a server that needs to be tested for // alert conditions. Do that now, and when we're done, set // its next query-time to some distance in the future. // if (lpoa->dwTickNextRefresh == 0) { if (lpoa->cTickRefresh != 0) lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount(); } else if (lpoa->dwTickNextRefresh <= GetTickCount()) { (void)lpServer->Invalidate(); (void)lpServer->RefreshAll(); lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount(); } (void)Alert_Scout_CheckServer (lpServer); } lpServer->Close(); } lpCell->Close(); } AfsClass_Leave(); // Now that we have completed a pass over the servers in this cell, // and now that we're not holding any critical sections on which // other threads would otherwise block, go to sleep for a while. // WaitForSingleObjectEx (heScoutWakeup, 45L * cmsec1SECOND, FALSE); } return 0; }
void Alert_EndUpdate (LPIDENT lpi, LPSERVER lpServer) { // If we just updated some aggregate, fileset or service, then the // associated server's secondary alerts are probably out-of-date. // Update them. // if (lpServer != NULL) { LPOBJECTALERTS lpoaServer = Alert_GetObjectAlerts (lpServer->GetIdentifier()); LPOBJECTALERTS lpoaChild = Alert_GetObjectAlerts (lpi); if (lpoaServer) { for (size_t iAlert = 0; iAlert < lpoaServer->nAlerts; ) { if ( (lpoaServer->aAlerts[ iAlert ].alert == alertSECONDARY) && (lpoaServer->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary == lpi) ) { Alert_RemoveFunc (lpoaServer, iAlert); } else { ++iAlert; } } } if (lpoaServer && lpoaChild) { BOOL fNeedBadCredsWarning = FALSE; BOOL fHaveBadCredsWarning = FALSE; size_t iAlert; for (iAlert = 0; iAlert < lpoaServer->nAlerts; ++iAlert) { if (lpoaServer->aAlerts[ iAlert ].alert == alertSECONDARY) { ALERT alert = Alert_GetAlert (lpoaServer->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary, lpoaServer->aAlerts[ iAlert ].aiSECONDARY.iSecondary); if (alert == alertNO_SVRENT) fNeedBadCredsWarning = TRUE; } } for (iAlert = 0; iAlert < lpoaChild->nAlerts; ++iAlert) { if (lpoaChild->aAlerts[ iAlert ].alert == alertNO_SVRENT) fNeedBadCredsWarning = TRUE; } if (lpoaServer->nAlerts && lpoaServer->aAlerts[ 0 ].alert == alertBADCREDS) { fHaveBadCredsWarning = TRUE; } if (fNeedBadCredsWarning) { fNeedBadCredsWarning = !CheckCredentials (FALSE); } if (fHaveBadCredsWarning && !fNeedBadCredsWarning) { Alert_RemoveFunc (lpoaServer, 0); } else if (fNeedBadCredsWarning && !fHaveBadCredsWarning) { for (iAlert = min( lpoaServer->nAlerts, nAlertsMAX-1 ); iAlert > 0; --iAlert) { memcpy (&lpoaServer->aAlerts[ iAlert ], &lpoaServer->aAlerts[ iAlert-1 ], sizeof(ALERTINFO)); } lpoaServer->aAlerts[0].alert = alertBADCREDS; lpoaServer->nAlerts = min( nAlertsMAX, lpoaServer->nAlerts+1 ); } for (iAlert = 0; iAlert < lpoaChild->nAlerts; ++iAlert) { if (lpoaServer->nAlerts < nAlertsMAX) { lpoaServer->aAlerts[ lpoaServer->nAlerts ].alert = alertSECONDARY; lpoaServer->aAlerts[ lpoaServer->nAlerts ].aiSECONDARY.lpiSecondary = lpi; lpoaServer->aAlerts[ lpoaServer->nAlerts ].aiSECONDARY.iSecondary = iAlert; lpoaServer->nAlerts ++; } } } lpServer->Close(); } }
BOOL SERVICE::RefreshStatus (BOOL fNotify, ULONG *pStatus) { BOOL rc = TRUE; DWORD status = 0; if (m_fStatusOutOfDate) { m_fStatusOutOfDate = FALSE; if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); LPSERVER lpServer; if ((lpServer = OpenServer (&status)) == NULL) rc = FALSE; else { PVOID hCell; PVOID hBOS; if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL) rc = FALSE; else { SERVICESTATUS ss; if (!lstrcmp (m_szName, TEXT("BOS"))) { memset (&ss, 0x00, sizeof(SERVICESTATUS)); AfsClass_UnixTimeToSystemTime (&ss.timeLastStart, 0); AfsClass_UnixTimeToSystemTime (&ss.timeLastStop, 0); AfsClass_UnixTimeToSystemTime (&ss.timeLastFail, 0); ss.nStarts = 1; ss.dwErrLast = 0; ss.dwSigLast = 0; ss.type = SERVICETYPE_SIMPLE; ss.state = SERVICESTATE_RUNNING; } else { WORKERPACKET wp; wp.wpBosProcessInfoGet.hServer = hBOS; wp.wpBosProcessInfoGet.pszService = m_szName; if (!Worker_DoTask (wtaskBosProcessInfoGet, &wp, &status)) rc = FALSE; else { memcpy (&ss, &wp.wpBosProcessInfoGet.ss, sizeof(SERVICESTATUS)); // Get the service's current state // wp.wpBosProcessExecutionStateGet.hServer = hBOS; wp.wpBosProcessExecutionStateGet.pszService = m_szName; wp.wpBosProcessExecutionStateGet.pszAuxStatus = ss.szAuxStatus; if (!Worker_DoTask (wtaskBosProcessExecutionStateGet, &wp, &status)) ss.state = SERVICESTATE_STOPPED; else ss.state = wp.wpBosProcessExecutionStateGet.state; // Get the service's notifier // ss.szNotifier[0] = TEXT('\0'); wp.wpBosProcessNotifierGet.hServer = hBOS; wp.wpBosProcessNotifierGet.pszService = m_szName; wp.wpBosProcessNotifierGet.pszNotifier = ss.szNotifier;; Worker_DoTask (wtaskBosProcessNotifierGet, &wp, &status); // Get the service's parameters // ss.szParams[0] = TEXT('\0'); WORKERPACKET wpBegin; wpBegin.wpBosProcessParameterGetBegin.hServer = hBOS; wpBegin.wpBosProcessParameterGetBegin.pszService = m_szName; if (Worker_DoTask (wtaskBosProcessParameterGetBegin, &wpBegin, &status)) { for (;;) { TCHAR szParam[ 256 ]; WORKERPACKET wpNext; wpNext.wpBosProcessParameterGetNext.hEnum = wpBegin.wpBosProcessParameterGetBegin.hEnum; wpNext.wpBosProcessParameterGetNext.pszParam = szParam; if (!Worker_DoTask (wtaskBosProcessParameterGetNext, &wpNext, &status)) { if (status == ADMITERATORDONE) status = 0; else rc = FALSE; break; } if (ss.szParams[0] != TEXT('\0')) lstrcat (ss.szParams, TEXT(" ")); lstrcat (ss.szParams, szParam); } WORKERPACKET wpDone; wpDone.wpBosProcessParameterGetDone.hEnum = wpBegin.wpBosProcessParameterGetBegin.hEnum; Worker_DoTask (wtaskBosProcessParameterGetDone, &wpDone); } // Strip trailing CR/LF characters // size_t cch = lstrlen (ss.szAuxStatus); while (cch && (ss.szAuxStatus[ cch-1 ] == TEXT('\r') || ss.szAuxStatus[ cch-1 ] == TEXT('\n'))) ss.szAuxStatus[ cch-- ] = TEXT('\0'); cch = lstrlen (ss.szParams); while (cch && (ss.szParams[ cch-1 ] == TEXT('\r') || ss.szParams[ cch-1 ] == TEXT('\n'))) ss.szParams[ cch-- ] = TEXT('\0'); cch = lstrlen (ss.szNotifier); while (cch && (ss.szNotifier[ cch-1 ] == TEXT('\r') || ss.szNotifier[ cch-1 ] == TEXT('\n'))) ss.szNotifier[ cch-- ] = TEXT('\0'); } } if (rc) { memcpy (&m_ss, &ss, sizeof(SERVICESTATUS)); } lpServer->CloseBosObject(); } lpServer->Close(); } if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status)); } if (pStatus && !rc) *pStatus = status; return TRUE; }