static int AwayMsgPreShutdown(WPARAM wParam, LPARAM lParam) { if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_CLOSE,0,0); if (hWindowList2) WindowList_BroadcastAsync(hWindowList2,WM_CLOSE,0,0); return 0; }
int StopAccounts(HYAMNPROTOPLUGIN Plugin) { HACCOUNT Finder; //1. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write enter\n"); #endif for (Finder=Plugin->FirstAccount;Finder != NULL;Finder=Finder->Next) { //2. set stop signal StopSignalFcn(Finder); WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Finder,0); if (Plugin->Fcn->StopAccountFcnPtr != NULL) Plugin->Fcn->StopAccountFcnPtr(Finder); } //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); //Now, account is stopped. It can be removed from memory... return 1; }
void CMsgTree::Save() { if (MsgTreePage.GetModified()) { MsgTreePage.PageToMemToDB(); WindowList_BroadcastAsync(hMTWindowList, UM_MSGTREE_UPDATE, 0, 0); } }
void WINAPI SetStatusFcn(HACCOUNT Which, TCHAR *Value) { if (Which != NULL) { mir_cslock lck(csAccountStatusCS); mir_tstrcpy(Which->Status, Value); } WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUS, (WPARAM)Which, 0); }
static int ClcProtoAck(WPARAM, LPARAM lParam) { ACKDATA *ack = (ACKDATA *) lParam; if (ack->type == ACKTYPE_STATUS) { WindowList_BroadcastAsync(hClcWindowList, INTM_INVALIDATE, 0, 0); if (ack->result == ACKRESULT_SUCCESS) { for (int i=0; i < cli.hClcProtoCount; i++) { if (!mir_strcmp(cli.clcProto[i].szProto, ack->szModule)) { cli.clcProto[i].dwStatus = (WORD) ack->lParam; break; } } } } return 0; }
void WINAPI SetStatusFcn(HACCOUNT Which,TCHAR *Value) { if (Which==NULL) return; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs wait\n"); #endif EnterCriticalSection(&AccountStatusCS); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs enter\n"); #endif lstrcpy(Which->Status,Value); WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_CHANGESTATUS,(WPARAM)Which,0); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs done\n"); #endif LeaveCriticalSection(&AccountStatusCS); }
void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) { PYAMN_PROTOPLUGINQUEUE ActualPlugin; HACCOUNT ActualAccount; HANDLE ThreadRunningEV; DWORD Status, tid; // we use event to signal, that running thread has all needed stack parameters copied if (NULL==(ThreadRunningEV=CreateEvent(NULL, FALSE, FALSE, NULL))) return; // if we want to close miranda, we get event and do not run checking anymore if (WAIT_OBJECT_0==WaitForSingleObject(ExitEV, 0)) return; // Get actual status of current user in Miranda Status=CallService(MS_CLIST_GETSTATUSMODE, 0, 0); EnterCriticalSection(&PluginRegCS); for (ActualPlugin=FirstProtoPlugin;ActualPlugin != NULL;ActualPlugin=ActualPlugin->Next) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read wait\n"); #endif if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) //we want to access accounts immiadtelly { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read enter failed\n"); #endif LeaveCriticalSection(&PluginRegCS); return; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read enter\n"); #endif for (ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount != NULL;ActualAccount=ActualAccount->Next) { if (ActualAccount->Plugin==NULL || ActualAccount->Plugin->Fcn==NULL) //account not inited continue; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read wait\n"); #endif if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read wait failed\n"); #endif continue; } #ifdef DEBUG_SYNCHRO switch(Status) { case ID_STATUS_OFFLINE: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status offline\n"); break; case ID_STATUS_ONLINE: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status online\n"); break; case ID_STATUS_AWAY: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status away\n"); break; case ID_STATUS_DND: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status dnd\n"); break; case ID_STATUS_NA: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status na\n"); break; case ID_STATUS_OCCUPIED: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status occupied\n"); break; case ID_STATUS_FREECHAT: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status freechat\n"); break; case ID_STATUS_INVISIBLE: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status invisible\n"); break; case ID_STATUS_ONTHEPHONE: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status onthephone\n"); break; case ID_STATUS_OUTTOLUNCH: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status outtolunch\n"); break; default: DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status unknown\n"); break; } #endif BOOL isAccountCounting = 0; if ( (ActualAccount->Flags & YAMN_ACC_ENA) && (((ActualAccount->StatusFlags & YAMN_ACC_ST0) && (Status<=ID_STATUS_OFFLINE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST1) && (Status==ID_STATUS_ONLINE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST2) && (Status==ID_STATUS_AWAY)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST3) && (Status==ID_STATUS_DND)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST4) && (Status==ID_STATUS_NA)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST5) && (Status==ID_STATUS_OCCUPIED)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST6) && (Status==ID_STATUS_FREECHAT)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST7) && (Status==ID_STATUS_INVISIBLE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST8) && (Status==ID_STATUS_ONTHEPHONE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST9) && (Status==ID_STATUS_OUTTOLUNCH)))) { if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr==NULL) { goto ChangeIsCountingStatusLabel; } if (ActualAccount->TimeLeft) { ActualAccount->TimeLeft--; isAccountCounting = TRUE; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:time left : %i\n", ActualAccount->TimeLeft); #endif WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGETIME, (WPARAM)ActualAccount, (LPARAM)ActualAccount->TimeLeft); if (!ActualAccount->TimeLeft) { struct CheckParam ParamToPlugin={YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_NORMALCHECK, (void *)0, NULL}; HANDLE NewThread; ActualAccount->TimeLeft=ActualAccount->Interval; if (NULL==(NewThread=CreateThread(NULL, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid))) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read done\n"); #endif ReadDoneFcn(ActualAccount->AccountAccessSO); continue; } else { WaitForSingleObject(ThreadRunningEV, INFINITE); CloseHandle(NewThread); } } } ChangeIsCountingStatusLabel: #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read done\n"); #endif if (((ActualAccount->isCounting) != 0) != isAccountCounting) { ActualAccount->isCounting=isAccountCounting; WORD cStatus = db_get_w(ActualAccount->hContact, YAMN_DBMODULE, "Status", 0); switch (cStatus) { case ID_STATUS_ONLINE: case ID_STATUS_OFFLINE: db_set_w(ActualAccount->hContact, YAMN_DBMODULE, "Status", isAccountCounting?ID_STATUS_ONLINE:ID_STATUS_OFFLINE); default: break; } } ReadDoneFcn(ActualAccount->AccountAccessSO); } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read done\n"); #endif SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); } LeaveCriticalSection(&PluginRegCS); CloseHandle(ThreadRunningEV); return; }
/* int FindPluginAccount(WPARAM wParam,LPARAM lParam) { HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; HACCOUNT Finder=(HACCOUNT)lParam; if (Finder=NULL) Finder=Plugin->FirstAccount; // for (;Finder != NULL && Finder->PluginID != Plugin->PluginInfo->PluginID;Finder=(HACCOUNT)Finder->Next); return (int)Finder; } */ INT_PTR DeleteAccountSvc(WPARAM wParam,LPARAM lParam) { //Deleting account works on these steps: //1. set signal that account should stop activity (set event) // setting this event we achieve, that any access to account is failed, // so threads do not start any work with accounts (better saying threads of plugins should not start) //2. wait to get write access to chained list of accounts //3. we can write to chained list, so we change chain not to show to actual account // now, any thread browsing list of accounts does not browse through actual account // actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue)) //Now, we should delete account from memory, BUT!!! // Any thread can still be waked up and start asking account synchronizing object // If account is deleted, asking about access to read account can throw memory exception (reading for // a synchronizing object from memory, that was deleted) //So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore // (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?) // This deleting is achieved in 2 ways: // We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account // 1. Any thread using account first increment UsingThread, so we know that account is used // 2. If thread is about to close, it should decrement UsingThread // 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not // increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using // account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then // new thread is going to read account...). //4. wait until UsingThread Event is signaled //5. delete account from memory HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; HACCOUNT Which=(HACCOUNT)lParam; HACCOUNT Finder; DWORD tid; //1. set stop signal StopSignalFcn(Which); WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Which,0); if (Plugin->Fcn->StopAccountFcnPtr != NULL) Plugin->Fcn->StopAccountFcnPtr(Which); //2. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write enter\n"); #endif //3. remove from queue (chained list) if (Plugin->FirstAccount==NULL) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); return 0; } if (Plugin->FirstAccount==Which) { Finder=Plugin->FirstAccount->Next; Plugin->FirstAccount=Finder; } else { for (Finder=Plugin->FirstAccount;Which != Finder->Next;Finder=Finder->Next); Finder->Next=Finder->Next->Next; } //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); //4. wait while event "UsingThread" is not signaled // And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so // other threads do not start any new work with actual account) We will wait in blocked state? // No, of course not. We will create new thread, that will wait and additionally remove our thread in background. //5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread if ((Plugin->Fcn != NULL) && (Plugin->Fcn->WriteAccountsFcnPtr != NULL)) Plugin->Fcn->WriteAccountsFcnPtr(); CloseHandle(CreateThread(NULL,0,DeleteAccountInBackground,(LPVOID)Which,0,&tid)); //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using //event UsingThreads. return 1; }
int PreShutdownHistoryModule(WPARAM, LPARAM) { if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0); return 0; }
static int OnIconLibIconChanged(WPARAM, LPARAM) { WindowList_BroadcastAsync(hButtonWindowList, MBM_REFRESHICOLIBICON, 0, 0); return 0; }
static int ClcIconsChanged(WPARAM, LPARAM) { WindowList_BroadcastAsync(hClcWindowList, INTM_INVALIDATE, 0, 0); return 0; }
static int ClcContactIconChanged(WPARAM wParam, LPARAM lParam) { WindowList_BroadcastAsync(hClcWindowList, INTM_ICONCHANGED, wParam, lParam); return 0; }
static int ClcContactDeleted(WPARAM wParam, LPARAM lParam) { WindowList_BroadcastAsync(hClcWindowList, INTM_CONTACTDELETED, wParam, lParam); return 0; }
int Buttons_OnSkinModeSettingsChanged(WPARAM, LPARAM) { WindowList_BroadcastAsync(hButtonWindowList, MBM_UPDATETRANSPARENTFLAG, 0, 2); return 0; }
void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam) { WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam); }
int PreshutdownSendRecv(WPARAM wParam, LPARAM lParam) { WindowList_BroadcastAsync(g_dat->hMessageWindowList, WM_CLOSE, 0, 0); return 0; }
static int AwayMsgPreShutdown(WPARAM, LPARAM) { if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_CLOSE,0,0); return 0; }