#include <windows.h>
#include <shellapi.h>
#include "resource.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <shellapi.h> // tray
#include <stdlib.h>
#include <commctrl.h> // CB_SETMINVISIBLE
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include <msxml.h>
#include <objsafe.h>
#include <objbase.h>
#include <atlbase.h>
#define WM_TRAY (WM_APP+1)
CComPtr<IXMLDOMElement> getXMLRootByURI(LPCWSTR uri){
HRESULT hr;
CComPtr<IXMLDOMDocument> iXMLDoc;
hr = iXMLDoc.CoCreateInstance(__uuidof(DOMDocument));
if(iXMLDoc.p == NULL || FAILED(hr)){
MessageBox(NULL, L"Не удалось загрузить MSXML. Корректная работа приложения невозможна.\n"
L"Проверьте, установлен ли корректно Internet Explorer.", L"", 0);
exit(1);
}
VARIANT_BOOL bSuccess = false;
iXMLDoc->put_async(VARIANT_FALSE);
hr = iXMLDoc->load(CComVariant(uri),&bSuccess);
if(!bSuccess || FAILED(hr)){
//MessageBox(NULL, L"Не удалось загрузить документ.", L"", 0);
return NULL;
}
CComPtr<IXMLDOMElement> iRootElm;
hr = iXMLDoc->get_documentElement(&iRootElm);
if(iRootElm.p == NULL || FAILED(hr)){
//MessageBox(NULL, L"Не удалось загрузить документ.", L"", 0);
return NULL;
}
return iRootElm;
}
LPTSTR getTagValueByPath(CComPtr<IXMLDOMElement> root, LPCWSTR path){
CComBSTR bstrSS(path);
CComPtr<IXMLDOMNode> iXMLSubElem;
HRESULT hr = root->selectSingleNode(bstrSS,&iXMLSubElem);
if(FAILED(hr) || iXMLSubElem.p == NULL)
return NULL;
CComVariant varValue(VT_EMPTY);
hr = iXMLSubElem->get_nodeTypedValue(&varValue);
if(FAILED(hr) || varValue.vt != VT_BSTR)
return NULL;
USES_CONVERSION;
LPTSTR lpstrMsg = W2T(varValue.bstrVal);
return lpstrMsg;
}
typedef void iterator(CComPtr<IXMLDOMNode>);
void forEachNode(CComPtr<IXMLDOMElement> root, LPCWSTR path, iterator f){
CComBSTR bstrSS(path);
CComPtr<IXMLDOMNodeList> iXMLSubElems;
HRESULT hr = root->selectNodes(bstrSS,&iXMLSubElems);
if(FAILED(hr) || iXMLSubElems.p == NULL)
return;
CComPtr<IXMLDOMNode> iXMLSubElem;
while(true){
iXMLSubElem = NULL;
hr = iXMLSubElems->nextNode(&iXMLSubElem);
if(FAILED(hr))
break;
if(!iXMLSubElem)
break;
f(iXMLSubElem);
}
}
CComPtr<IXMLDOMNode> getSubNode(CComPtr<IXMLDOMElement> root, LPCWSTR path){
CComBSTR bstrSS(path);
CComPtr<IXMLDOMNode> iXMLSubElem;
HRESULT hr = root->selectSingleNode(bstrSS,&iXMLSubElem);
if(FAILED(hr) || iXMLSubElem.p == NULL)
return NULL;
return iXMLSubElem;
}
class Multiline {
private:
LPCWSTR ss[1024];
int sn, cur;
public:
Multiline(){
this->sn = 0;
}
Multiline(LPCWSTR fs, ...){
LPCWSTR param;
this->sn = 0;
va_list arglist;
param = fs;
va_start(arglist, fs);
while(param){
this->append(param);
param = va_arg(arglist, LPCWSTR);
}
va_end(arglist);
}
void append(LPCWSTR s){
if(this->sn < 1024){
this->ss[this->sn++] = s;
}
}
void resetPointer(){
this->cur = 0;
}
LPCWSTR get(){
return (this->cur < this->sn) ?
this->ss[this->cur++] : NULL;
}
};
void timerPopupEvent(HWND, UINT, UINT_PTR, DWORD);
class TrayIcon {
private:
NOTIFYICONDATA nid;
HINSTANCE hInstance;
HICON hIcon;
int tid;
public:
TrayIcon(){
;
}
TrayIcon(HWND hWnd, HINSTANCE hInstance){
this->hInstance = hInstance;
memset(&(this->nid), 0, sizeof(this->nid));
this->nid.cbSize = sizeof(this->nid);
this->nid.hWnd = hWnd;
this->hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WAIT));
this->nid.hIcon = this->hIcon;
this->nid.uCallbackMessage = WM_TRAY;
this->nid.uFlags = NIF_ICON|NIF_MESSAGE;
this->show();
}
void updateIcon(LPCWSTR icon){
//memset(&(this->nid), 0, sizeof(this->nid));
//this->nid.cbSize = sizeof(this->nid);
DestroyIcon(this->hIcon);
this->hIcon = LoadIcon(this->hInstance, icon);
this->nid.hIcon = this->hIcon;
this->nid.uFlags = NIF_ICON;
Shell_NotifyIcon(NIM_MODIFY, &(this->nid));
}
void updateTip(LPCWSTR text){
//memset(&(this->nid), 0, sizeof(this->nid));
//this->nid.cbSize = sizeof(this->nid);
/* lstrcpyn(this->nid.szTip, text, sizeof(this->nid.szTip)/sizeof(this->nid.szTip[0]));
this->nid.uFlags = NIF_TIP;
Shell_NotifyIcon(NIM_MODIFY, &(this->nid)); */
;
}
~TrayIcon(){
this->hide();
DestroyIcon(this->hIcon);
}
void show(){
Shell_NotifyIcon(NIM_ADD, &(this->nid));
}
void hide(){
Shell_NotifyIcon(NIM_DELETE, &(this->nid));
}
};
class Popup {
private:
HWND hWnd;
LPCWSTR caption;
Multiline text;
HBRUSH hbBackground;
int w, h;
public:
int timerID;
Popup(HWND hWnd){
this->hWnd = hWnd;
this->w = 200; this->h = 150;
this->caption = L"";
this->hbBackground = CreateSolidBrush(RGB(240,240,80));
}
void setCaption(LPCWSTR s){
this->caption = s;
}
void setText(Multiline s){
this->text = s;
}
void resize(int w, int h){
this->w = w;
this->h = h;
}
void show(){
int x, y;
// где же наш таскбарчик?
APPBARDATA abd;
abd.hWnd = FindWindow(L"Shell_TrayWnd", NULL);
abd.cbSize = sizeof(abd);
bool pOnTop = (SHAppBarMessage(ABM_GETSTATE, &abd) & ABS_ALWAYSONTOP);
bool pAutoHide = (SHAppBarMessage(ABM_GETSTATE, &abd) & ABS_AUTOHIDE) ;
RECT rT, rS;
GetWindowRect(abd.hWnd, &rT);
GetWindowRect(GetDesktopWindow(), &rS);
if((rT.right-rT.left)<rS.right){
// Вааау! Вертикально расположенный таскбар!
y = rS.bottom-this->h;
x = (rT.left>0)?rT.left-this->w:rT.right;
}else{
x = rS.right-this->w;
y = (rT.top>0)?rT.top-this->h:rT.bottom;
}
ShowWindow(this->hWnd, SW_SHOW);
MoveWindow(this->hWnd, x, y, this->w, this->h, TRUE);
this->timerID = SetTimer(this->hWnd, 0, 5000, (TIMERPROC)(timerPopupEvent));
}
void hide(){
ShowWindow(this->hWnd, SW_HIDE);
}
void draw(HDC hdc){
/* CFont f;
memset(&f, 0, sizeof(f)); */
HFONT hf;
// FIXME частичная перерисовка
SelectObject(hdc, this->hbBackground);
Rectangle(hdc, 0, 0, this->w, this->h);
SetBkMode(hdc, TRANSPARENT);
hf = CreateFont(14, 0, 0, 0, 800, FALSE, TRUE, FALSE, UNICODE,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Sans");
SelectObject(hdc, hf);
TextOut(hdc, 12, 4, this->caption, lstrlen(this->caption));
DeleteObject(hf);
hf = CreateFont(12, 0, 0, 0, 500, FALSE, FALSE, FALSE, UNICODE,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Sans");
SelectObject(hdc, hf);
this->text.resetPointer();
for(int i=20; ; i+=14){
LPCWSTR ln = this->text.get();
if(!ln) break;
TextOut(hdc, 12, i, ln, lstrlen(ln));
}
DeleteObject(hf);
}
~Popup(){
DeleteObject(this->hbBackground);
}
};
void registerCity(CComPtr<IXMLDOMNode>);
class Cities {
private:
LPCWSTR countries[512];
LPCWSTR cities[512][1024];
int codes[512][1024];
public:
int getCountry(LPCWSTR country){
for(int i=0;i<512;i++)
if(this->countries[i] && !wcscmp(this->countries[i], country))
return i;
return -1;
}
LPCWSTR getCountry(int id){
return this->countries[id];
}
LPCWSTR getCity(int countryID, int cityID){
return this->cities[countryID][cityID];
}
int getCity(int countryID, LPCWSTR city){
for(int i=0;i<1024;i++)
if(this->cities[countryID][i] && !wcscmp(this->cities[countryID][i], city))
return i;
return -1;
}
LPCWSTR getCity(int city){
for(int i=0;i<512;i++){
if(!this->countries[i])
break;
for(int j=0;j<1024;j++){
if(!this->cities[i][j])
break;
if(this->codes[i][j]==city)
return this->cities[i][j];
}
}
return NULL;
}
int getCityCode(int countryID, int cityID){
return this->codes[countryID][cityID];
}
int countCountries(){
int i;
for(i=0; i<512; i++)
if(!countries[i])
break;
return i;
}
int setCountry(LPCWSTR country){
int c = this->getCountry(country);
if(c != -1)
return c;
c = this->countCountries();
this->countries[c] = country;
return c;
}
int countCities(int countryID){
int i;
for(i=0; i<1024; i++)
if(!cities[countryID][i])
break;
return i;
}
void setCity(LPCWSTR country, LPCWSTR city, int code){
int countryID = this->setCountry(country);
int cities = this->countCities(countryID);
this->cities[countryID][cities] = city;
this->codes[countryID][cities] = code;
}
void load(){
CComPtr<IXMLDOMElement> root = getXMLRootByURI(L"gmbartlist.xml"); // http://bar.gismeteo.ru/
if(root){
forEachNode(root, L"t", registerCity);
}else{
MessageBox(NULL, L"Не удалось загрузить список городов. Корректная работа приложения невозможна", L":'(", 0);
exit(1);
}
}
Cities(){
for(int i=0;i<512;i++){
this->countries[i] = NULL;
for(int j=0;j<1024;j++){
this->cities[i][j] = NULL;
}
}
}
};
struct Weather {
LPCWSTR name;
int day, month, year, hour, cloud, precip,
mintemp, maxtemp, minpress, maxpress,
minwind, maxwind, minrelwet, maxrelwet,
winddir;
};
// Эти переменные столь глобальны, что они живут здесь
Popup* popup;
TrayIcon* ti;
Cities* cities;
int city = 27612;
Weather w;
HINSTANCE hInst;
void timerPopupEvent(HWND hWnd, UINT msg, UINT_PTR idTimer, DWORD dwTimer){
popup->hide();
KillTimer(hWnd, popup->timerID);
}
LPCWSTR getTagAttr(CComPtr<IXMLDOMNode> item, LPCWSTR name){
CComPtr<IXMLDOMNamedNodeMap> attrs;
HRESULT hr = item->get_attributes(&attrs);
if(FAILED(hr))
return NULL;
CComPtr<IXMLDOMNode> iXMLAttr = NULL;
CComVariant varValue(VT_EMPTY);
attrs->getNamedItem(CComBSTR(name), &iXMLAttr);
iXMLAttr->get_nodeTypedValue(&varValue);
// Они долбанулись в своём мелкософте! Придумали кучу типов строк, а простого способа
// создать новый экземпляр с выделением памяти и копированием старого значения - нет
wchar_t* result = (wchar_t*)malloc(1024*sizeof(wchar_t)); // если больше - ССЗБ
wcscpy(result, W2T(varValue.bstrVal));
return result;
}
/* Do it indian way, dude */
void registerCity(CComPtr<IXMLDOMNode> item){
cities->setCity(
getTagAttr(item, L"c"),
getTagAttr(item, L"n"),
_wtoi(getTagAttr(item, L"i")));
}
bool wloaded = true;
void showWeather(){
Multiline m;
wchar_t* s = (wchar_t*)malloc(1024*sizeof(wchar_t));
wchar_t* rs;
popup->setCaption(w.name);
swprintf((wchar_t*)s, (wchar_t*)L"%d.%d.%d %d:00", w.day, w.month, w.year, w.hour);
rs = (wchar_t*)malloc(1024*sizeof(wchar_t)); wcscpy(rs, s);
m.append(rs);
switch(w.cloud){
case 0:
m.append(L"ясно");
ti->updateIcon(MAKEINTRESOURCE(IDI_SUNNY));
break;
case 1:
m.append(L"малооблачно");
ti->updateIcon(MAKEINTRESOURCE(IDI_CLOUDY));
break;
case 2:
m.append(L"облачно");
ti->updateIcon(MAKEINTRESOURCE(IDI_CLOUDY));
break;
case 3:
m.append(L"пасмурно");
ti->updateIcon(MAKEINTRESOURCE(IDI_MOSTCLOUDY));
break;
}
switch(w.precip){
case 4: m.append(L"дождь"); break;
case 5: m.append(L"ливень"); break;
case 6: m.append(L"снег"); break;
case 7: m.append(L"снег"); break;
case 8: m.append(L"гроза"); break;
case 9: break;
case 10: m.append(L"без осадков"); break;
}
swprintf((wchar_t*)s, (wchar_t*)L"Температура %d...%d C", w.mintemp, w.maxtemp);
rs = (wchar_t*)malloc(1024*sizeof(wchar_t)); wcscpy(rs, s);
m.append(rs);
swprintf((wchar_t*)s, (wchar_t*)L"Ветер %d...%d м/с", w.minwind, w.maxwind);
rs = (wchar_t*)malloc(1024*sizeof(wchar_t)); wcscpy(rs, s);
m.append(rs);
popup->setText(m);
popup->show();
}
void registerWeather(CComPtr<IXMLDOMNode> item){
if(!wloaded){
w.day = _wtoi(getTagAttr(item, L"day"));
w.month = _wtoi(getTagAttr(item, L"month"));
w.year = _wtoi(getTagAttr(item, L"year"));
w.hour = _wtoi(getTagAttr(item, L"hour"));
CComPtr<IXMLDOMNode> temp;
item->selectSingleNode(L"TEMPERATURE", &temp);
w.mintemp = _wtoi(getTagAttr(temp, L"min"));
w.maxtemp = _wtoi(getTagAttr(temp, L"max"));
CComPtr<IXMLDOMNode> press;
item->selectSingleNode(L"PRESSURE", &press);
w.minpress = _wtoi(getTagAttr(press, L"min"));
w.maxpress = _wtoi(getTagAttr(press, L"max"));
CComPtr<IXMLDOMNode> wind;
item->selectSingleNode(L"WIND", &wind);
w.minwind = _wtoi(getTagAttr(wind, L"min"));
w.maxwind = _wtoi(getTagAttr(wind, L"max"));
w.winddir = _wtoi(getTagAttr(wind, L"direction"));
/* switch(_wtoi(getTagAttr(wind, L"direction"))){
case 0: w.winddir = L"С"; break;
case 1: w.winddir = L"СВ"; break;
case 2: w.winddir = L"В"; break;
case 3: w.winddir = L"ЮВ"; break;
case 4: w.winddir = L"Ю"; break;
case 5: w.winddir = L"ЮЗ"; break;
case 6: w.winddir = L"З"; break;
case 7: w.winddir = L"СЗ"; break;
} */
CComPtr<IXMLDOMNode> relwet;
item->selectSingleNode(L"WIND", &relwet);
w.minrelwet = _wtoi(getTagAttr(relwet, L"min"));
w.maxrelwet = _wtoi(getTagAttr(relwet, L"max"));
CComPtr<IXMLDOMNode> phenom;
item->selectSingleNode(L"PHENOMENA", &phenom);
w.cloud = _wtoi(getTagAttr(phenom, L"cloudiness"));
w.precip = _wtoi(getTagAttr(phenom, L"precipitation"));
/* switch(_wtoi(getTagAttr(phenom, L"cloudiness"))){
case 0: w.cloud = L"ясно"; break;
case 1: w.cloud = L"малооблачно"; break;
case 2: w.cloud = L"облачно"; break;
case 3: w.cloud = L"пасмурно"; break;
}
switch(_wtoi(getTagAttr(phenom, L"precipitation"))){
case 4: w.precip = L"дождь"; break;
case 5: w.precip = L"ливень"; break;
case 6: w.precip = L"снег"; break;
case 7: w.precip = L"снег"; break;
case 8: w.precip = L"гроза"; break;
case 9: w.precip = L"нет данных"; break;
case 10: w.precip = L"без осадков"; break;
} */
wloaded = true;
}
}
void loadCityWeather(){
wchar_t* uri = (wchar_t*)malloc(1024*sizeof(wchar_t));
swprintf(uri, (wchar_t*)L"http://informer.gismeteo.ru/xml/%d_1.xml", city);
CComPtr<IXMLDOMElement> root = getXMLRootByURI(L"27612_1.xml"); //;(LPCWSTR)uri);
wloaded = false;
if(root){
forEachNode(root, L"REPORT/TOWN/FORECAST", registerWeather);
showWeather();
}else{
MessageBox(NULL, L"Не удалось загрузить погоду. Проверьте соединение с Сетью.", L":'(", 0);
}
}
BOOL CALLBACK ChooseCityDlgProc(HWND hWndD, UINT message, WPARAM wParam, LPARAM lParam){
HWND comboCountries = GetDlgItem(hWndD, IDC_COMBO1);
HWND comboCities = GetDlgItem(hWndD, IDC_COMBO2);
switch (message){
case WM_INITDIALOG:
SendMessage(comboCountries, CB_RESETCONTENT, 0, 0);
for(int i=0;i<512;i++){
LPCWSTR country = cities->getCountry(i);
if(!country) break;
SendMessage(comboCountries, CB_ADDSTRING, 0, (LPARAM)country);
}
return TRUE;
case WM_COMMAND:
/* In all cases, the low-order word of the wParam parameter
contains the control identifier, the high-order word of wParam
contains the notification code, and the lParam parameter
contains the control window handle. (c) MSDN */
switch (LOWORD(wParam)){
case IDC_COMBO1:
char tmp[256];
if(HIWORD(wParam)==CBN_SELCHANGE){
SendDlgItemMessage(hWndD, IDC_COMBO1,
WM_GETTEXT, sizeof(tmp),
(LPARAM)tmp);
//MessageBox(NULL, (LPCWSTR)tmp, L"", 0);
int countryCode = cities->setCountry((LPCWSTR)tmp);
SendMessage(comboCities, CB_RESETCONTENT, 0, 0);
for(int i=0;i<1024;i++){
LPCWSTR city = cities->getCity(countryCode, i);
if(!city) break;
SendMessage(comboCities, CB_ADDSTRING, 0, (LPARAM)city);
}
}
break;
case IDOK:
SendDlgItemMessage(hWndD, IDC_COMBO1,
WM_GETTEXT, sizeof(tmp),
(LPARAM)tmp);
int countryCode;
LPCWSTR country;
country = (LPCWSTR)tmp;
countryCode = cities->setCountry((LPCWSTR)tmp);
SendDlgItemMessage(hWndD, IDC_COMBO2,
WM_GETTEXT, sizeof(tmp),
(LPARAM)tmp);
if(strlen(tmp)==0){
MessageBox(hWndD, L"Эй! Ты же ничего не выбрал!", L"Нехорошо!", 0);
break;
}
int cityCode;
cityCode = cities->getCity(countryCode, (LPCWSTR)tmp);
city = cities->getCityCode(countryCode, cityCode);
wchar_t* rs;
rs = (wchar_t*)malloc(1024*sizeof(wchar_t)); wcscpy(rs, (LPCWSTR)tmp);
w.name = (LPCWSTR)rs;
loadCityWeather();
//MessageBox(NULL, (LPCWSTR)tmp, L"", 0);
// there is no break
case IDCANCEL:
EndDialog(hWndD, wParam);
return TRUE;
}
default:
return FALSE;
}
}
void ShowPopupMenu(HWND hWnd){
HMENU hMenu = GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)), 0); //, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE)
SetForegroundWindow(hWnd);
POINT p;
GetCursorPos(&p);
TrackPopupMenu(hMenu, 0, p.x, p.y, 0, hWnd, NULL);
DestroyMenu(hMenu);
}
void openSite(){
char *url;
url = (char*)malloc(sizeof(char)*512);
sprintf(url, "http://gismeteo.ru/city/daily/%d/", city);
popup->hide();
// С недавних пор на сайте коды городов стали несовпадать О_о
//ShellExecuteA(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL);
free(url);
}
void quit(HWND hWnd){
SendMessage(hWnd, WM_DESTROY, 0, 0);
}
void chooseCity(HWND hWnd){
DialogBox(hInst,
MAKEINTRESOURCE(IDD_DIALOG1),
hWnd,
(DLGPROC)ChooseCityDlgProc);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
case WM_COMMAND:
int wmID;
wmID = LOWORD(wParam);
switch(wmID){
case ID_EXIT:
quit(hWnd);
break;
case ID_CHOOSECITY:
chooseCity(hWnd);
break;
}
break;
case WM_LBUTTONUP:
openSite();
break;
case WM_RBUTTONUP:
popup->hide();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_TRAY:
bool dclicked;
dclicked = false;
switch((UINT)lParam){
case WM_RBUTTONDOWN:
ShowPopupMenu(hWnd);
break;
case WM_LBUTTONDOWN:
// Вот индусы в Microsoft! Посылают сообщение о клике и двойном клике единовременно!
long t;
t = GetTickCount() + 100;
while(t < GetTickCount()){
if(dclicked){
dclicked = false;
return 0; // break не подходит, а жаль.
}
}
showWeather();
break;
case WM_LBUTTONDBLCLK:
dclicked = true;
openSite();
break;
}
break;
case WM_PAINT:
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
popup->draw(hdc);
EndPaint(hWnd, &ps);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM RegMyWindowClass(HINSTANCE hInstance, LPCTSTR lpzClassName)
{
WNDCLASS wcWindowClass = {0};
wcWindowClass.lpfnWndProc = (WNDPROC)WndProc;
wcWindowClass.style = CS_HREDRAW|CS_VREDRAW;
wcWindowClass.hInstance = hInstance;
wcWindowClass.lpszClassName = lpzClassName;
wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
return RegisterClass(&wcWindowClass);
}
void timerMainEvent(HWND hWnd, UINT msg, UINT_PTR idTimer, DWORD dwTimer){
loadCityWeather();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
hInst = hInstance;
CoInitialize(NULL);
wchar_t* className = L"twHint";
if (!RegMyWindowClass(hInstance, className))
return 1;
HWND hWnd = CreateWindowW(className, L"Loading...",
(/* WS_VISIBLE | */WS_EX_TOOLWINDOW),
0, 0, 250, 100, NULL, NULL,
hInstance, NULL);
if(!hWnd) return 1;
hWnd = CreateWindow(className, L"",
(WS_POPUPWINDOW | WS_EX_TOPMOST) & (~WS_DLGFRAME),
0, 0, 300, 150, hWnd, NULL, hInstance, NULL);
if(!hWnd) return 1;
ti->updateTip(L"Подгружаю список городов...");
cities = new Cities();
cities->load();
FILE* f = _wfopen(L".settings", L"r");
if(f){
fwscanf(f, L"%ld", &city); // badptr - wtf?
w.name = cities->getCity(city);
fclose(f);
}
ti = new TrayIcon(hWnd, hInstance);
popup = new Popup(hWnd);
loadCityWeather();
int timerID = SetTimer(hWnd, 1, 60*60*1000, (TIMERPROC)(timerMainEvent)); // проверяем погоду каждый час
MSG msg = {0};
int msgStatus = 0;
while ((msgStatus = GetMessage(&msg, NULL, 0, 0)) != 0){
if (msgStatus == -1) return 1;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
delete popup;
delete ti;
delete cities;
KillTimer(hWnd, timerID);
f = _wfopen(L".settings", L"w");
if(f){
city = fwprintf(f, L"%ld", city);
fclose(f);
}
CoUninitialize();
return 0;
}