📄 windowstrayiconmemoryleak.cpp
字号:
}
// Handle icon mouse event (left/right button)
void HandleNotifyIcon(WPARAM id_num, LPARAM lParam) {
switch (lParam) {
case WM_LBUTTONDOWN:
// Callback Java class in new thread using "MousePressedCallback()"
if (id_num >= 0) CallJavaVMSThread(MousePressedCallback,id_num,0);
break;
case WM_RBUTTONDOWN:
if (id_num >= 0) {
// If menu defined, then show it
if (tray_icons[id_num].popup != NULL) {
POINT pos;
GetCursorPos(&pos);
// Display and track the popup menu
PopupMenu *menu = tray_icons[id_num].popup;
menu->TrackPopupMenu(TPM_RIGHTALIGN | TPM_RIGHTBUTTON,&pos,my_hDlg);
} else {
// Callback Java class in new thread using "MousePressedCallback()"
CallJavaVMSThread(MousePressedCallback,id_num,1);
}
}
break;
}
}
// Windows message proc for hidden window
// Receives mouse/menu events for the apps tray icons
LONG APIENTRY WndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam) {
switch (iMessage) {
case WM_DESTROY:
// Exit message thread
PostQuitMessage(0) ;
break;
case MYWM_NOTIFYICON:
// Mouse event for icon (left/right button)
HandleNotifyIcon(wParam, lParam);
break;
case MYWM_APPTALK:
// ID used for sendWindowsMessage()
// Callback Java class using "WindowsMessageCallback()"
return CallJavaVMS(WindowsMessageCallback,0,(int)lParam);
case WM_COMMAND:
// Menu command for icon
HandleMenuCommand(LOWORD(wParam));
break;
// Do nothing for other messages
case WM_CREATE:
case WM_GETMINMAXINFO:
case WM_PAINT:
case WM_MOUSEMOVE:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOVE:
case WM_SIZE:
case WM_LBUTTONDOWN:
case WM_KEYDOWN:
break;
// Or use default handler
default:
return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
}
return 0L ;
}
// Create the hidden window to receive the icon's mouse messages
HWND MakeHWND(HINSTANCE hInst) {
HWND hWnd;
// Create window class
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC) WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon(hInst, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) return NULL;
// Create window
hWnd = CreateWindow(szAppName, szWndName, WS_OVERLAPPEDWINDOW,
0,0,100,100,
NULL, NULL, hInst, NULL);
return hWnd;
}
// Remove the hidden window (on app closing)
void RemoveHWND() {
// Close dial
if (my_hDlg != NULL) {
// Create wait event
exit_event = CreateEvent(NULL,FALSE,FALSE,NULL);
// Send destroy messages
PostMessage(my_hDlg, WM_NCDESTROY, 0, 0);
PostMessage(my_hDlg, WM_DESTROY, 0, 0);
// Wait for window to destroy
WaitForSingleObject(exit_event,10000);
CloseHandle(exit_event);
exit_event = NULL;
}
// Free handle
if (wait_event != NULL) {
CloseHandle(wait_event);
wait_event = NULL;
}
}
// The thread proc that creates the hidden window an listens for messages
void DialogThread(void *dummy) {
MSG msg;
// Create window
my_hDlg = MakeHWND(g_hinst);
// Signal wait event
if (wait_event != NULL) SetEvent(wait_event);
// Hide window
ShowWindow(my_hDlg, SW_HIDE);
UpdateWindow(my_hDlg);
// Process messages
while (GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
// Unregister window class
UnregisterClass(szAppName, g_hinst);
// Signal exit event (so app knows hidden window is destroyed)
if (exit_event != NULL) SetEvent(exit_event);
}
// New icon resource with no bitmap and zero size
IconData::IconData() {
wd = hi = 0;
hBitmapAND = hBitmapXOR = NULL;
}
// Destroy icon resources (and and xor bitmap)
IconData::~IconData() {
if (hBitmapAND != NULL) DeleteObject(hBitmapAND);
if (hBitmapXOR != NULL) DeleteObject(hBitmapXOR);
}
// Make icon using and and xor bitmaps (returns handle to new icon)
HICON IconData::makeIcon(HINSTANCE hInst) {
ICONINFO ii;
ii.fIcon = TRUE;
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = hBitmapAND;
ii.hbmColor = hBitmapXOR;
return CreateIconIndirect(&ii);
}
// Set icon's image data (pixel array, width, height)
int IconData::setData(unsigned long *data, int wd, int hi) {
// Set size
this->wd = wd;
this->hi = hi;
// Clean up if setData was called before
if (hBitmapAND != NULL) DeleteObject(hBitmapAND);
if (hBitmapXOR != NULL) DeleteObject(hBitmapXOR);
// To protect against java sending a dud image
if (wd > 0 && hi > 0) {
// Set up the header for creating our 24 bit colour bitmap
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = wd;
bih.biHeight = hi;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
// Create memory DC
HDC hdc = CreateCompatibleDC(NULL);
// Make the 24-bit DIB
hBitmapXOR = CreateDIBSection(hdc, (LPBITMAPINFO)&bih, DIB_RGB_COLORS, (LPVOID *)NULL, NULL, 0);
// Select it into the DC so we can draw onto it
SelectObject(hdc, hBitmapXOR);
// Calloc memory to be used to create a monochrome bitmask
long size = (wd*hi/8)+1;
unsigned char *andMask = new unsigned char[size];
if (andMask != NULL) {
for (int i = 0; i < size; i++) andMask[i] = 0;
// Loop through the given pixels and draw onto the colour and mono bitmaps
unsigned long pixel;
unsigned char red, green, blue, alpha;
for (int row = 0; row < hi; row++) {
for (int col = 0; col < wd; col++) {
pixel = data[(row*wd)+col];
alpha = (unsigned char)((pixel >> 24) & 0x000000ff);
red = (unsigned char)((pixel >> 16) & 0x000000ff);
green = (unsigned char)((pixel >> 8) & 0x000000ff);
blue = (unsigned char)( pixel & 0x000000ff);
if (alpha == 0xFF) {
// Pixel is not transparent - update xor bitmap
SetPixel(hdc, col, row, RGB(red, green, blue));
} else {
// Pixel is transparent - update and mask
int p = (row*wd) + col;
andMask[p/8] |= 1 << (7-(p%8));
}
}
}
// Create the monochrome bitmask with transparency info
hBitmapAND = CreateBitmap(wd, hi, 1, 1, andMask);
// Free memory
delete andMask;
// Release the memory DC
ReleaseDC(NULL, hdc);
return 0;
}
// Release the memory DC
ReleaseDC(NULL, hdc);
}
// Error on zero size icons
return -1;
}
// Find free menu id for submenu item (given icon id = owner)
// Each tray icon with a submenu has a number of menu ids, one for each menu item
long getFreeMenuId(int id_num) {
long size = arrUsedMenuIds->getSize();
long id = 0;
BOOL done = FALSE;
// Find for free id in array that maps menu ids to icon ids
for (id = 0; id < size && !done; id++)
if (arrUsedMenuIds->getElementAt(id) == -1) done = TRUE;
// Found none, create new id
if (!done) {
id = size;
arrUsedMenuIds->addElement(-1);
}
// Mark id in array as belonging to icon with id id_num
arrUsedMenuIds->setElementAt(id, id_num);
// Return id for new submenu item
return id;
}
// Free all menu ids for a given icon
void setFreeMenuId(int id_num) {
long size = arrUsedMenuIds->getSize();
// Find ids for given icon and free them
for (long ps = 0; ps < size; ps++) {
if (arrUsedMenuIds->getElementAt(ps) == id_num)
arrUsedMenuIds->setElementAt(ps, -1);
}
// Shrink array if there are trailing empty places
long delofs = arrUsedMenuIds->getSize();
while (delofs > 0 && arrUsedMenuIds->getElementAt(delofs-1) == -1) {
delofs--;
arrUsedMenuIds->removeElementAt(delofs);
}
}
// Map menu id to icon id
int getMenuItemIdNum(int id) {
long size = arrUsedMenuIds->getSize();
if (id < size) return arrUsedMenuIds->getElementAt(id);
else return -1;
}
// Make new popup menu
PopupSubMenu::PopupSubMenu() {
hMenu = CreatePopupMenu();
bSub = FALSE;
}
// Make new popup menu (reset all class members)
void PopupSubMenu::reNewMenu() {
if (!isSub()) DestroyMenu(hMenu);
hMenu = CreatePopupMenu();
bSub = FALSE;
}
// Destroy popupmenu
PopupSubMenu::~PopupSubMenu() {
if (!isSub()) DestroyMenu(hMenu); // Only needed when parent menu, not for submenus
}
// Is this a submenu or a parent popup menu
BOOL PopupSubMenu::isSub() {
return bSub;
}
// Mark this popup menu as being a submenu
void PopupSubMenu::makeSub() {
bSub = TRUE;
}
// Get the windows menu handle, used for AppendMenu,..
HMENU PopupSubMenu::getMenu() {
return hMenu;
}
// Display the popupmenu at given position (in neighbourhood of tray icon)
void PopupSubMenu::TrackPopupMenu(UINT flags, POINT* pos, HWND hWnd) {
// SetForegroundWindow/PostMessage are hacks because TrackPopupMenu contains bug/feature
// Otherwise it's not hidden properly when the user clicks on desktop
SetForegroundWindow(hWnd);
::TrackPopupMenu(hMenu, flags, (*pos).x, (*pos).y, 0, hWnd, NULL);
PostMessage(hWnd, WM_NULL, 0, 0);
}
// Make new popup main menu with maximum submenu depth
PopupMenu::PopupMenu(int levels) {
nbLevels = levels;
popup = new PtrPopupSubMenu[levels];
for (int ctr = 0; ctr < levels; ctr++) popup[ctr] = NULL;
}
// Destroy main popup menu
PopupMenu::~PopupMenu() {
// Destroy all submenu levels
for (int ctr = 0; ctr < nbLevels; ctr++)
if (popup[ctr] != NULL) delete popup[ctr];
delete popup;
}
// Init menu at given level (make new or call reNewMenu())
void PopupMenu::initMenu(int level) {
if (level >= nbLevels) return;
if (popup[level] != NULL) popup[level]->reNewMenu();
else popup[level] = new PopupSubMenu();
}
// Return windows menu handle for given level (should be 0 for main menu)
HMENU PopupMenu::getMenu(int level) {
PopupSubMenu *menu = getSubMenu(level);
if (menu == NULL) return NULL;
else return menu->getMenu();
}
// Return sub menu @ given level (used in getMenu()/TrackPopupMenu())
PopupSubMenu* PopupMenu::getSubMenu(int level) {
if (level >= nbLevels) return NULL;
return popup[level];
}
// Display the popupmenu at given position (in neighbourhood of tray icon)
void PopupMenu::TrackPopupMenu(UINT flags, POINT* pos, HWND hWnd) {
PopupSubMenu *menu = getSubMenu(0);
if (menu != NULL) menu->TrackPopupMenu(flags, pos, hWnd);
}
// Create new growable integer array
QSIntArray::QSIntArray() {
m_Array = new int[5];
m_ArrSize = 5;
m_Size = 0;
m_Grow = 10;
}
// Create new growable integer array with initial size and grow term
QSIntArray::QSIntArray(long size, long grow) {
m_Array = new int[size];
m_ArrSize = size;
m_Size = 0;
m_Grow = grow;
}
// Delete growable integer array
QSIntArray::~QSIntArray() {
delete m_Array;
}
// Get size
long QSIntArray::getSize() {
return m_Size;
}
// Get integer @ given position
int QSIntArray::getElementAt(long idx) {
return m_Array[idx];
}
// Add integer at end of array
void QSIntArray::addElement(int element) {
m_Size++;
grow();
m_Array[m_Size-1] = element;
}
// Set integer @ given position (may be >= getSize() - array grows)
void QSIntArray::setElementAt(long idx, int element) {
m_Size = max(m_Size, idx+1);
grow();
m_Array[idx] = element;
}
// Remove integer at given position
void QSIntArray::removeElementAt(long idx) {
m_Size--;
for (long pos = idx; pos < m_Size; pos++)
m_Array[pos] = m_Array[pos+1];
shrink();
}
// Empty array
void QSIntArray::removeAll() {
m_Size = 0;
shrink();
}
// Shrink array to convenient size
void QSIntArray::shrink() {
if (m_Size < m_ArrSize - m_Grow) {
long nSize = m_Size + m_Grow;
int* nArray = new int[nSize];
for (long idx = 0; idx < m_Size; idx++)
nArray[idx] = m_Array[idx];
delete m_Array;
m_Array = nArray;
m_ArrSize = nSize;
}
}
// Grow array to convenient size
void QSIntArray::grow() {
if (m_Size > m_ArrSize) {
long nSize = m_Size + m_Grow;
int* nArray = new int[nSize];
for (long idx = 0; idx < m_ArrSize; idx++)
nArray[idx] = m_Array[idx];
delete m_Array;
m_Array = nArray;
m_ArrSize = nSize;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -