📄 channelmenu.cpp
字号:
/*
* Openmysee
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "stdafx.h"
#include ".\channelmenu.h"
#include "httprequest.h"
#include "xml.h"
#include "MultiLanguageMgr.h"
#include "configfile.h"
#include "..\layer1\external\md5.h"
static CChannelMenu* pChannelMenu = NULL;
extern TCHAR g_sAppPath[MAX_PATH];
CChannelMenu::CChannelMenu(void) : h_channelmenu(NULL), h_MenuThread(NULL),
channeldataOK(0), ParseDataOK(FALSE), useChannel(FALSE), channelthreadStop(FALSE), updatechannel(0),channelrunning(FALSE),
xmlurl(_T("http://www.Openmysee.com/program.php")),
pointcookieurl(_T("http://www.Openmysee.com/")),
pointurl(_T("http://www.Openmysee.com/member/userstat.php"))
{
pHttpSession = new HttpRequest;
pHttpSession->Create();
pTrayIconMenu = new CTrayIconMenu;
}
CChannelMenu::~CChannelMenu(void)
{
DestroyMenu(h_channelmenu);
channelthreadStop = TRUE;
pHttpSession->SetStopRequest();
if(h_MenuThread != NULL)
{
WaitForSingleObject(h_MenuThread,INFINITE);
CloseHandle(h_MenuThread);
}
delete pHttpSession;
delete pTrayIconMenu;
}
CChannelMenu* CChannelMenu::CreateInstance(BOOL useChannel)
{
if(pChannelMenu == NULL)
{
pChannelMenu = new CChannelMenu;
pChannelMenu->useChannel = useChannel;
if(useChannel)
{
mystring filestr(g_sAppPath);
filestr.append(_T("\\config.ini"));
ConfigFile config(filestr);
mystring tmp = config.Value(_T("localserver"), _T("channellist"));
if(!(config.fileNotFound || config.stringNotFound))
pChannelMenu->xmlurl = tmp;
tmp = config.Value(_T("localserver"), _T("userdata"));
if(!(config.fileNotFound || config.stringNotFound))
pChannelMenu->pointcookieurl = tmp;
tmp = config.Value(_T("localserver"), _T("postpointurl"));
if(!(config.fileNotFound || config.stringNotFound))
pChannelMenu->pointurl = tmp;
unsigned int threadID;
pChannelMenu->h_MenuThread = (HANDLE) _beginthreadex(NULL, 0, &_GetMenuThreadProc, pChannelMenu, 0, &threadID);
}
}
return pChannelMenu;
}
CChannelMenu* CChannelMenu::GetInstance()
{
return pChannelMenu;
}
void CChannelMenu::ReleaseInstance()
{
delete pChannelMenu;
}
extern volatile HWND g_hMainWnd;
unsigned int CALLBACK CChannelMenu::_GetMenuThreadProc(void* lpParameter)
{
CChannelMenu* pClass = (CChannelMenu*) lpParameter;
//发生随机数
srand(GetTickCount());
int idleinterval = 0;
int nextworkingtime = 0;
int getxmlerrcount = 0;
while(!pClass->channelthreadStop)
{
if(idleinterval >= nextworkingtime ) //当定时器被触发时,开始获取XML的行动
{
InterlockedExchange(&pClass->channeldataOK, 0);
if(!pClass->GetChannelXML())
{
if(getxmlerrcount < 3) //根据已经发生的错误次数制定逐步加长的重试间隔
{
nextworkingtime += 1; //隔1s重试一次
getxmlerrcount++;
}
else if(getxmlerrcount < 6)
{
nextworkingtime += 10; //隔10s重试一次
getxmlerrcount++;
}
else //放弃重试,等待下一次定时唤醒
{
InterlockedExchange(&pClass->channeldataOK, -1);
nextworkingtime += 1200;
getxmlerrcount = 0;
}
}
else
{
nextworkingtime += 1200; //隔20min重试一次
getxmlerrcount = 0;
InterlockedExchange(&pClass->channeldataOK, 1);
}
}
else if(pClass->updatechannel == 1)
{
nextworkingtime = idleinterval;
InterlockedExchange(&pClass->updatechannel, 0);
}
if(idleinterval%300 == 0)
{
pClass->PostAddPoint();
}
Sleep(1000);
idleinterval++;
}
// PostMessage(g_hMainWnd, WM_COMMAND, WM_APP + 1, 0);
return 0;
}
void CChannelMenu::UpdateChannelNow()
{
InterlockedExchange(&channeldataOK, 0);
InterlockedExchange(&updatechannel, 1);
}
BOOL CChannelMenu::PostAddPoint()
{
if(channelrunning == FALSE)
return FALSE;
mystring deststr(pointurl);
mystring formatstr;
deststr.append(_T("?u=")); //userstat?
TCHAR datastr[36];
DWORD len = 36;
if(!HttpRequest::GetCookieEx(pointcookieurl.c_str(), "MYSE_UID", datastr, &len))
return FALSE;
deststr.append(datastr); //userstat?<userid>
formatstr.append(datastr);
formatstr.append(_T("06My&SEe#211")/*约定的密钥*/);
int _rand = rand();
_stprintf(datastr, _T("&r=%d&h="), _rand);
deststr.append(datastr); //userstat?<userid>&<random num>&
_stprintf(datastr, _T("%d"), _rand);
formatstr.append(datastr);
char* srcstr = new char[formatstr.size() + 20];
wsprintfA(srcstr, "%s", formatstr.c_str());
MD5 md5((unsigned char*) srcstr, strlen(srcstr));
char* result = md5.hex_digest();
delete[] srcstr;
wsprintf(datastr, "%hs", result);
delete[] result;
deststr.append(datastr); //userstat?<userid>&<random num>&<md5>
return pHttpSession->OpenRequest(deststr.c_str());
}
BOOL CChannelMenu::GetChannelXML()
{
LANGID langid = pTrayIconMenu->GetCurLanguage();
mystring appendxmlurl(xmlurl);
if(appendxmlurl.find(_T(".php")) != mystring::npos) //对于非PHP的URL,应该不应用参数
{
switch(langid)
{
case MAINLAND_LANG_ID: //简体中文
appendxmlurl.append(_T("?lang=zh"));
break;
case TAIWAN_LANG_ID:
case HONGKONG_LANG_ID: //繁体中文
appendxmlurl.append(_T("?lang=big5"));
break;
case DEFAULT_LANG_ID: //英文
default:
appendxmlurl.append(_T("?lang=en"));
}
}
if(!pHttpSession->OpenRequest(appendxmlurl.c_str()))
return FALSE;
// MessageBox(NULL, "get xml!", "", MB_OK);
BYTE* tempstr = new BYTE[pHttpSession->getBufLen() + 30];
memset(tempstr, 0, pHttpSession->getBufLen() + 30);
pHttpSession->TransBuf(tempstr);
m_critsec_XMLFile.Lock();
strXMLFile = (LPCSTR) tempstr;
m_critsec_XMLFile.Unlock();
delete[] tempstr;
return TRUE;
}
#ifdef _UNICODE
static const std::wstring groupname[] =
{
_T("GROUP"),
_T("SUBGROUP"),
_T("Channel"),
};
#else
static const std::string groupname[] =
{
_T("GROUP"),
_T("SUBGROUP"),
_T("Channel"),
};
#endif
#define ChannelPos 2
BOOL CChannelMenu::ParseChannelXML(HMENU hmenu)
{
CXML* p_xml = new CXML;
p_xml->InitXml();
m_critsec_XMLFile.Lock();
if(!p_xml->OpenXml(strXMLFile))
{
m_critsec_XMLFile.Unlock();
p_xml->unInitXml();
delete p_xml;
return FALSE;
}
m_critsec_XMLFile.Unlock();
if(p_xml->SetNodelist(groupname[0].c_str()) != 0)
MakePopupItem(p_xml, hmenu, 0);
if(p_xml->SetNodelist(groupname[ChannelPos].c_str()) != 0)
MakePopupItem(p_xml, hmenu, ChannelPos);
p_xml->unInitXml();
delete p_xml;
return TRUE;
}
void CChannelMenu::MakePopupItem(CXML* p_xml, HMENU hmenu, int isubgroup)
{
BOOL ischannel = (groupname[isubgroup] == _T("Channel"));
while(p_xml->ToNextNode())
{
if(!ischannel)
{
HMENU h_appendmenu = CreatePopupMenu();
if(p_xml->ToSubNodeList(groupname[isubgroup + 1].c_str()) != 0) //将组名设定成下一级的组名
{
MakePopupItem(p_xml, h_appendmenu, isubgroup + 1);
p_xml->BackParentNodeList();
}
if((isubgroup + 1 != ChannelPos) && (p_xml->ToSubNodeList(groupname[ChannelPos].c_str()) != 0)) //在本组下面寻找Channel并加入
{
MakePopupItem(p_xml, h_appendmenu, ChannelPos);
p_xml->BackParentNodeList();
}
if(GetMenuItemCount(h_appendmenu) <= 0) //如果最后子菜单中一项都没有, 这个node是错误的, 抛弃它
{
assert(0);
DestroyMenu(h_appendmenu);
}
else
{
mystring str;
p_xml->GetCurNodeAttrValue(str, _T("Name"));
AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR) h_appendmenu, str.c_str());
}
}
else//本身已经是Channel,加入菜单中
{
ChannelData data;
p_xml->GetCurNodeAttrValue(data.name, _T("Name"));
p_xml->GetCurNodeAttrValue(data.url, _T("URL"));
channellist.push_back(data);
AppendMenu(hmenu, MF_STRING , TRAYWM_CHANNELSTART + channellist.size() - 1, data.name.c_str());
}
}
}
LPCTSTR CChannelMenu::GetChannelByCmdID(DWORD m_cmdID)
{
if(m_cmdID < TRAYWM_CHANNELSTART || m_cmdID > TRAYWM_CHANNELEND)
return NULL;
size_t index = m_cmdID - TRAYWM_CHANNELSTART;
if(index >= channellist.size())
return NULL;
channellist[index].desc.append(channellist[index].url.c_str());
return channellist[index].url.c_str();
}
namespace{
//一份默认的菜单
UINT_PTR m_traycmd[] =
{
TRAYWM_HOMEPAGE,
CTrayIconMenu::ID_SEPERATOR,
//CTrayIconMenu::ID_EXTERNAL, 0,
//CTrayIconMenu::ID_SEPERATOR,
CTrayIconMenu::ID_POPUP,
TRAYWM_UPDATE,
CTrayIconMenu::ID_LANGUAGE,
CTrayIconMenu::ID_END,
CTrayIconMenu::ID_SEPERATOR,
CTrayIconMenu::ID_POPUP,
TRAYWM_HELP,
TRAYWM_NETWORK,
TRAYWM_EMAIL,
TRAYWM_ABOUT,
CTrayIconMenu::ID_END,
CTrayIconMenu::ID_SEPERATOR,
TRAYWM_EXIT,
CTrayIconMenu::ID_END};
//不同语言的菜单文本,必须和数据严格对应,每一个数据项在文本里都应该有一个*,包括ID_END, ID_SEPERATOR等
//ID_EXTERNAL除外,其后接一项没有*,而ID_POPUP后应该增加一项*作为标记
/*const TCHAR m_traystrgb[] =
_T("首页(&P)*-*频道(&C)*-*设置(&S)*SUBSTART*检查更新(&U)*选择语言(&L)*END*-*帮助(&H)*SUBSTART*使用帮助(&H)*判定网络(&N)*电子邮件(&E)*关于(&A)*END*-*退出(&E)*END*");
*/
const TCHAR m_traystrgb[] =
_T("首页(&P)*-*设置(&S)*SUBSTART*检查更新(&U)*选择语言(&L)*END*-*帮助(&H)*SUBSTART*使用帮助(&H)*判定网络(&N)*电子邮件(&E)*关于(&A)*END*-*退出(&E)*END*");
//这里用"-"表示一个分隔符,"SUBSTART"表示开始一个新子菜单,"END"表示一个菜单结束。也可以换成任何方便的字符,程序并不理会它们
const UINT m_channellisthandlepos = 3;
}
BOOL CChannelMenu::ShowRButtonTIMenu(HWND hparent)
{
h_channelmenu = CreatePopupMenu(); //初始化一个提示的菜单
AppendMenu(h_channelmenu, MF_SEPARATOR, (UINT_PTR) 0, NULL); //加条分隔线意思一下,以防万一……
m_traycmd[m_channellisthandlepos] = (UINT_PTR) h_channelmenu;;
pTrayIconMenu->ShowMenu(hparent, m_traycmd, m_traystrgb);
DestroyMenu(h_channelmenu); //放弃生成的菜单
h_channelmenu = NULL;
ParseDataOK = FALSE; //因为生成的菜单已放弃,所以已正确解析的标记变成FALSE
return TRUE;
}
void CChannelMenu::OnPopupMenu(HMENU hmenu, int popuppos)
{
if(pTrayIconMenu->OnMenuPopup(hmenu, popuppos))
return;
if(hmenu != h_channelmenu) //不是频道窗口不需要处理
return;
int count = GetMenuItemCount(hmenu);
if(count == -1) //菜单错误,放弃解析
return;
for(int i = 0; i < count; i++)
DeleteMenu(hmenu, 0, MF_BYPOSITION); //清除掉整个菜单里的内容
MultiLanguage langDll;
if(channeldataOK == 0) //数据未准备好
{
AppendMenu(h_channelmenu, MF_STRING | MF_DISABLED , (UINT_PTR) 0, langDll.GetStringByStr(_T("数据读取中...")));
}
else if(channeldataOK == -1) //获取数据错误
{
AppendMenu(h_channelmenu, MF_STRING | MF_DISABLED , (UINT_PTR) 0, langDll.GetStringByStr(_T("数据读取失败!")));
AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hmenu, MF_STRING, TRAYWM_UPDATECHANNEL, langDll.GetStringByStr(_T("更新频道列表")));
}
else
{
if(ParseChannelXML(hmenu) == TRUE)
{
AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hmenu, MF_STRING, TRAYWM_UPDATECHANNEL, langDll.GetStringByStr(_T("更新频道列表")));
}
else
{
AppendMenu(hmenu, MF_STRING | MF_DISABLED, 0, langDll.GetStringByStr(_T("频道文件解析失败")));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -