转载 引用于 http://blog.csdn.net/chenyujing1234
_tWInMain主要做安装,实例判断,初始化COM环境,开始界面显示.
- int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
- {
- // 获得安装路径
- // 采用MD5方法将软id和硬id合并为mid
- // 从dump.dll中的接口KxEOpenDumpMonitorEx2来注册安装此mid
- KDump::Instance().Install();
- if (S_FALSE == _Module.Init(hInstance))
- return -1;
- KCheckInstance* _pInst = KCheckInstance::Instance();
- if (_pInst == NULL)
- return 0;
- // 检查是不是第一个实例,并处理多实例
- int nRetv = _pInst->CheckFirstInstance(lpstrCmdLine/*, NULL, _T("Kingsoft Antivirus KSG Update Mutex")*/);
- if (!nRetv)
- {
- _pInst->ClearFirstInstance();
- return 0;
- }
- // 启动的时候,自动起托盘
- // WCHAR bufPath[MAX_PATH] = {0};
- // ::GetModuleFileName(NULL, bufPath, MAX_PATH);
- // ::PathRemoveFileSpecW(bufPath);
- // ::PathAppend(bufPath, TEXT("KSafeTray.exe"));
- // ::ShellExecute(NULL, NULL, bufPath, NULL, NULL, SW_HIDE);
- ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- // 加载皮肤、类型、串,加载RICHED20.dll, 查看KSafeSvc服务是否在运行, 创建各自的共享内存
- _Module.Run();
- ::CoUninitialize();
- _Module.Uninit();
- return 0;
- }
在_Module.Run主要做加载皮肤、类型、串,加载RICHED20.dll, 查看KSafeSvc服务是否在运行, 创建各自的共享内存
- // 加载皮肤、类型、串,加载RICHED20.dll, 查看KSafeSvc服务是否在运行, 创建各自的共享内存
- HRESULT KAppModule::Run()
- {
- // ======================Small tip==================
- // 设置资源路径、加载皮肤、类型、串
- _InitUIResource();
- if ( m_hModRichEdit2 == NULL )
- m_hModRichEdit2 = ::LoadLibrary(_T("RICHED20.DLL"));
- /*
- #if _DEBUG
- if (FALSE)
- #else
- if (_CheckIs64BitOp())
- #endif
- {
- //如果是64位操作系统,就退出。
- CBkSafeMsgBox2 dlg;
- dlg.ShowMutlLineMsg(BkString::Get(DefString33), BkString::Get(DefString7), MB_OK | MB_ICONEXCLAMATION);
- return S_OK;
- }*/
- // 由于类KMainDlg里有 KFlowStat m_FlowStatLog;
- // KFlowStat的构造函数中会加载数据库、打开数据库
- KMainDlg dlgMain;
- // ======================Small tip==================
- // 通过OpenSCManager、OpenService、QueryServiceStatus来查看KSafeSvc服务是否在运行
- if (!dlgMain.CheckServericeIsOK())
- {
- netmon_log(L"CheckServiceIsOK Failed!");
- }
- // KUrlMonCfgReader类与KNetFluxCacheReaderod类的Init,创建各自的共享内存
- if (!dlgMain.CheckDriver())
- {
- netmon_log(L"CheckDriver failed.Netmon exit.");
- }
- else
- {
- netmon_log(L"Netmon dlg start ");
- int uRet = dlgMain.DoModal(NULL);// 窗口显示
- }
- return S_OK;
- }
在代码的注释中讲到类KFlowStat的构造函数做了数据库的初始化.
这里先不对数据库展开说,以后会专门讲到金山中的数据库.
- KFlowStat::KFlowStat()
- {
- /*HRESULT hr = BKDbCreateObject(__uuidof(ISQLiteComDatabase3), (void**)&m_spiDB);
- if (!SUCCEEDED(hr))
- return;
- int nCmdLen = MAX_PATH * 2;
- wchar_t szFilePath[MAX_PATH * 2] = {0};
- DWORD dwCode = ::GetModuleFileName(NULL, szFilePath, nCmdLen);
- if (dwCode == 0)a
- return;
- ::PathRemoveFileSpecW(szFilePath);
- ::PathAppend(szFilePath, DEF_SQLITE_FILE);
- hr = m_spiDB->Open(szFilePath);
- if (!SUCCEEDED(hr))
- return;
- */
- HRESULT hr = S_OK;
- // chenyujing1234@163.com 2012-3-29 14:23
- m_piWlDB = NULL;
- // ======================Small tip==================
- // 从注册表中读取LeiDian的APP路径、LeidianLog路径
- hr = CAppPath::Instance().GetLeidianAppPath( m_modpath.m_strPath );
- if ( FAILED( hr ) )
- goto Exit0;
- hr = CAppPath::Instance().GetLeidianLogPath( m_dbpath.m_strPath );
- if ( FAILED( hr ) )
- goto Exit0;
- m_dbpath.Append( DEF_SQLITE_FILE );
- m_modpath.Append( BKMOD_NAME_BKDB );
- /* {
- int nCmdLen = MAX_PATH * 2;
- wchar_t szFilePath[MAX_PATH * 2] = {0};
- DWORD dwCode = ::GetModuleFileName(NULL, szFilePath, nCmdLen);
- ::PathRemoveFileSpecW(szFilePath);
- ::PathAppend(szFilePath, DEF_SQLITE_FILE);
- m_dbpath.m_strPath = szFilePath;
- }
- */
- // ======================Small tip==================
- // 这里会提示“没有找到MSVCR80.dll” m_modpath为c:\program files\ksafe\ksafedb.dll,加载失败
- hr = m_dbmod.LoadLib( m_modpath );
- if ( FAILED( hr ) )
- goto Exit0;
- hr = m_dbmod.BKDbCreateObject(
- __uuidof( Skylark::ISQLiteComDatabase3 ),
- ( void** )&m_piWlDB
- );
- if ( FAILED( hr ) )
- goto Exit0;
- hr = m_piWlDB->Open( m_dbpath );
- if ( FAILED( hr ) )
- {
- ::SetFileAttributes( m_dbpath, 0 );
- ::DeleteFile( m_dbpath );
- hr = m_piWlDB->Open( m_dbpath );
- }
- if ( FAILED( hr ) )
- goto Exit1;
- goto Exit0;
- Exit1:
- if ( m_piWlDB )
- {
- m_piWlDB->Release();
- m_piWlDB = NULL;
- }
- Exit0:
- return ;
- }
既然dlgMain.DoModal(NULL);了,那么接下来就是OnInitDialog了。
它主要做
1、 KOperMemFile创建共享文件,并存入标志,设备提醒信息,日期
2、 KCheckInstance 把容器句柄等信息写到KCheckInstance映射的内存里
3、 KNetFluxCacheReader 根据映射内在中的信息获取系统和当前进程的流量信息
4、 KFlowTray 确保KSafeTray.exe已经运行
5、 本次和上次的日期信息判断是否需要显示出来
6、 创建CBkNetMonitorListBox,并从listbox_template_netmonitor.xml初始化ListBox,把进程流程信息加到列表里
7、并启动定时器(定时器时的处理内容下节讲到)
定时器的类别有:
(1)更新状态信息
(2) 更新网络流量信息(间隔:1000)
(3)更新流量窗口状态(间隔:500)
(4)检查是否退出了(间隔:500)
- BOOL KMainDlg::OnInitDialog( CWindow /*wndFocus*/, LPARAM /*lInitParam*/ )
- {
- if (KOperMemFile::Instance().Init() == S_OK) // 创建共享文件
- {
- // ======================Small tip==================
- // 在映射的MemShareFlowElem内存中存数据 1
- KOperMemFile::Instance().SetWaitMoniterOpen(1);
- // ======================Small tip==================
- // 设置这次与上次提醒的信息:日期
- _InitFlowRemindInfo();
- }
- SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_BEIKESAFE)));
- SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_SMALL)), FALSE);
- m_enumProcessMode = enumProcessModeHasNetFlow;
- // ======================Small tip==================
- // 把容器句柄等信息写到KCheckInstance映射的内存里
- KCheckInstance::Instance()->CfgFirstInstance(NULL, this->m_hWnd, FALSE);
- KNetFluxCacheReader reader;
- if (SUCCEEDED(reader.Init()))
- //根据映射内在中的信息获取系统和当前进程的流量信息
- reader.GetProcessesFluxInfo(m_FluxSys, &m_processInfoList, m_enumProcessMode);
- // KNetFluxCacheReader::Instance().GetSystemNetFlow(m_FluxSys);
- _DisableDelayScan();
- // //加入任务栏右键最大化置灰
- // LONG lSys = GetWindowLong(GWL_STYLE);
- // lSys &= ~(WS_MAXIMIZEBOX);
- // SetWindowLong(GWL_STYLE, lSys);
- KFlowTray prot_shell(TRUE);
- // ======================Small tip==================
- // 确保KSafeTray.exe已经运行
- prot_shell.ShellTray();
- // CListBoxData::GetDataPtr()->SetProviderFunc(NET_MONITOR_219, &KMainDlg::_UpdateNetFlowSummaryWnd);
- // ======================Small tip==================
- // 本次和上次的日期信息判断是否需要显示出来
- _ShowNetMintorRemindDlg(TRUE);
- // ======================Small tip==================
- // 创建CBkNetMonitorListBox,并从listbox_template_netmonitor.xml初始化ListBox
- // 把进程流程信息加到列表里
- _InitNetMonitorListBox();
- // 初始化状态列表,从数据库中获得信息和状态填充列表
- // 为列表中的项显示当前页面
- // 通过KNetFluxStasticCacheReader类获得进程流统计列表,
- _InitStatList();
- // 初始化基本完成,接下来就是开启定时器:
- // 更新状态信息
- // 更新网络流量信息(1000)
- // 更新流量窗口状态(500)
- // 检查是否退出了(500)
- m_uTimer = SetTimer(ID_TIMER_UPDATE_NETFlOW_MON, UPDATE_NETFLOW_MON_INTERVAL, NULL);
- SetTimer(ID_TIMER_REFRESH_FLOATWND_STATUS, 500, NULL);
- //_SetAccessNetCount(0);
- _SetDownAndUpdateSum(0.0, 0.0);
- _SetDownSpeed(0.0);
- _SetUpSpeed(0.0);
- _InitFloatWndSwitch();
- m_hEventExit = ::CreateEvent(
- NULL,
- FALSE,
- FALSE,
- EVENT_NETMON_DLG_EXIT
- );
- m_hEventChangeFlowatWndDisplayStatusText =::CreateEvent(
- NULL,
- FALSE,
- FALSE,
- EVENT_NETMON_DLG_FLOATWND_DISPLAY_STATUS_TEXT
- );
- SetTimer(ID_TIMER_CHECK_EXIT, CHECK_EXIT_INTERVAL);
- _InitNetMonSwitch();
- m_bRptThreadWorking = FALSE;
- m_hEventRptThreadExit = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (m_nCurShowType == enumQueryTypeEveryMonth)
- OnClickShowStatMonths();
- return TRUE;
- }
初始化过程中把进程信息加到列表中去,这里的列表是继续于框架CBkListBox控制,重载得到的列表.
- <p>void KMainDlg::_InitNetMonitorListBox()
- {
- m_pNetMonitorListBox = new CBkNetMonitorListBox;
- .....
- }
- </p>
- BOOL KMainDlg::_InitStatList( void )
- {
- m_pNetStatListBox = new CBkNetMonitorListBox;
- ..........}
=========================================================================================
总结:
1、 用到的互斥机制有种:
(1)采用CLocker
eg: 在类class KMainDlg中有成员CLocker m_locker;
采用关键代码段,相对简单。这里提一下,因为关键代码段采用不让执行代码的方法,当进入嵌套时很容易造成死锁。这在大型框架设备中特别重要。
(2)采用ShareMemLock方式。
//
// 本锁的特性:
// 当有写的要求时,让旧的读取完成;而新的读取请求被挂起,直到本次写完,即写入优先
// 允许多线程读,只能有一个线程在写
- typedef struct _tagShareMemLock
- {
- // m_nLock用于保护m_nReadCnt变量 ,使在多线程时不互斥
- volatile LONG m_nLock;
- volatile LONG m_nReadCnt; // 读的次数 ,当为0表没有人在读,
- // 当为 -10000表写在进行
- volatile LONG m_nWrite; // 写锁
- volatile DWORD m_nDbgLockProcessID;
- volatile DWORD m_nDbgLockThreadID;
- volatile DWORD m_nDbgLockTime;
- void InitLock()
- {
- m_nLock = 0;
- m_nReadCnt = 0;
- m_nWrite = 0;
- }
- BOOL TryLockReadCntLock()
- {
- // LONG InterlockedCompareExchange
- // (LPLONG Destination, LONG Exchange, LONG Comperand);
- // 如果第三个参数与第一个参数指向的值相同
- // 那么用第二个参数取代第一个参数指向的值。函数返回值为原始值
- // ============如果m_nLock == 0,那么m_nLock = 1;且返回0。否则返回非0
- return (::InterlockedCompareExchange(&m_nLock, 1, 0) == 0);
- }
- // 让写锁还原
- BOOL UnlockReadCntLock()
- {
- m_nLock = 0;
- return TRUE;
- }
- BOOL TryLockWriteLock()
- {
- return (::InterlockedCompareExchange(&m_nWrite, 1, 0) == 0);
- }
- // 让写锁还原
- BOOL UnlockWriteLock()
- {
- m_nWrite = 0;
- return TRUE;
- }
- // 请求读的锁,判断现在可否读
- // 改变完读次数时马上把读锁释放
- BOOL TryLockRead()
- {
- // 如果有修改请求,那么优先考虑修改
- if (m_nWrite)
- return FALSE;
- // 如果已经在修改了,那么先等等,锁之外的判断不
- // 准确,但是可以起到加速的作用
- if (m_nReadCnt < 0)
- return FALSE;
- // 开始进行
- if (TryLockReadCntLock()) // 获得锁成功
- {
- if (m_nReadCnt >= 0)
- {
- m_nReadCnt ++; // 读的次数加1
- UnlockReadCntLock();// 改变完m_nReadCnt后马上把读锁打开
- return TRUE;
- }
- else // 如果小于0,即表示有写请求
- {
- UnlockReadCntLock();// 马上把读锁打开
- return FALSE;
- }
- }
- return FALSE;
- }
- // 锁住读
- BOOL LockRead()
- {
- // 如果已经有一个读在进行,那么就等待
- while (!TryLockRead())
- ::Sleep(1);
- return TRUE;
- }
- void UnLockRead()
- {
- while (!TryLockReadCntLock())// 保护m_nReadCtn
- ::Sleep(1);
- m_nReadCnt --;
- UnlockReadCntLock(); // 保护m_nReadCtn
- }
- /// 把读锁锁上.
- BOOL TryLockWrite()
- {
- // 如果有人在读,那么再等等
- // 但是可以起到加速作用
- if (m_nReadCnt > 0)
- return FALSE;
- if (TryLockReadCntLock())
- {
- // 确保没有人读,也没有人写
- if (m_nReadCnt == 0)
- {
- m_nReadCnt = -10000;
- UnlockReadCntLock();
- return TRUE;
- }
- else // 还有读在进行,那么
- {
- UnlockReadCntLock();
- return FALSE;
- }
- }
- return FALSE;
- }
- // 想锁住写,
- // 前提是:上一次的写已经调用了UnLockWrite(即写锁已经解开)
- // 如果成功,那么把写锁与读锁都锁上
- BOOL LockWrite()
- {
- // 保证没有其他人在写
- while (!TryLockWriteLock())
- ::Sleep(1);
- // 与LockRead不一样,这样如果发现在忙时不退出而是等待,这样就有了优先级
- // 保证其他人没有在读,也没有在写
- while (!TryLockWrite())
- ::Sleep(1);
- return TRUE;
- }
- // 写锁解开
- void UnLockWrite()
- {
- while (!TryLockReadCntLock())
- ::Sleep(1);
- m_nReadCnt = 0;
- UnlockReadCntLock();
- UnlockWriteLock();
- }
- }ShareMemLock;
eg: 示例一:在类KStasticFluxProcessList中有成员ShareMemLock m_lock;
- struct KStasticFluxProcessList
- {
- DWORD m_nSize;
- ShareMemLock m_lock;
- ULONGLONG m_nTotalRecv; // 总计接受的流量
- ULONGLONG m_nTotalSend; // 总计发送的流量
- __int64 m_nTimeWatch; // 监控时间
- __int64 m_nTimeTodayStart; // 今天截止时间点
- __int64 m_nTimeTodayLastTime; // 今天截止时间点
- DWORD m_nMaxCnt;
- DWORD m_nCurrentCnt;
- DWORD m_nReserved[100];
- KFluxStasticProcItem m_Items[1];
- };
在上面OnInitDialog( 讲到BOOL KMainDlg::_InitStatList( void ),里它会调用_GetAndShowProcessInfo(); 它就是 通过KNetFluxStasticCacheReader类获得进程流统计列表,
_GetAndShowProcessInfo();里就用到了此锁 m_lock来控制访问.
- // 初始化状态列表,从数据库中获得信息和状态填充列表
- // 为列表中的项显示当前页面
- // 通过KNetFluxStasticCacheReader类获得进程流统计列表,
- BOOL KMainDlg::_InitStatList( void )
- {
- m_pNetStatListBox = new CBkNetMonitorListBox;
- if (NULL == m_pNetStatListBox)
- return FALSE;
- _GetCurLogInfo(enumQueryTypeEveryDay);
- // ======================Small tip==================
- // 初始化状态列表,从数据库中获得信息和状态填充列表
- //listbox
- m_pNetStatListBox->Create( GetViewHWND(), TAB_SHOW_STAT_WINDOW);
- m_pNetStatListBox->Load(IDR_BK_LISTBOX_STATINFO);
- m_pNetStatListBox->SetCanGetFocus(FALSE);
- // ======================Small tip==================
- // 为列表中的项显示当前页面
- _ShowPageForList();
- // m_fluxStatRead.Init();
- // ======================Small tip==================
- // 通过KNetFluxStasticCacheReader类获得进程流统计列表,
- _GetAndShowProcessInfo();
- _ShowRemindInfo();
- SetTimer(ID_TIMER_UPDATE_STAT_INFO, 30000, NULL);
- PostMessage(WM_TIMER, ID_TIMER_UPDATE_STAT_INFO, 0);
- return TRUE;
- }
- void KMainDlg::_GetAndShowProcessInfo( void )
- {
- pFluxStatRead->m_lock.LockRead();
- ....... // 处理数据
- pFluxStatRead->m_lock.UnLockRead();
- }
示例二:在类KProcessFluxList中有成员ShareMemLock m_lock;
- struct KProcessFluxList
- {
- DWORD m_nSize;
- ShareMemLock m_lock;
- KPFWFLUX m_SysFlux;
- DWORD m_nMaxCnt;
- DWORD m_nCurrentCnt;
- DWORD m_nProcessPopCount;
- DWORD m_nReserved[99];
- KProcFluxItem m_Items[1];
- };
在上面OnInitDialog( 讲到BOOL KMainDlg::_InitStatList( void ),里它会调用reader.GetProcessesFluxInfo(m_FluxSys, &m_processInfoList, m_enumProcessMode);
它就是 根据映射内在中的信息获取系统和当前进程的流量信息.
GetProcessesFluxInfo里就用到了_GetProcessesFluxInfo(sysFlux, pProcessesList, nProcessMode);
GetProcessesFluxInfo就是用到了此锁来访问信息。
- // 获取系统和当前进程的流量信息
- BOOL _GetProcessesFluxInfo(KPFWFLUX& sysFlux, std::vector<KProcFluxItem>* pProcessesList, int nProcessMode = enumProcessModeHasAll)
- {
- // 为保证快速读取,并且释放锁,这里先使用内存拷贝的方法
- pList->m_lock.LockRead();
- .......// 处理数据
- // 解锁
- pList->m_lock.UnLockRead();
- }