Article View: borland.public.cppbuilder.nativeapi
Article #4786Re: Refresh The System Tray
From: AJ
Date: Mon, 21 Nov 2005 23:02
Date: Mon, 21 Nov 2005 23:02
341 lines
12571 bytes
12571 bytes
I didn't know my question was going to spur such a debate. I found an
example of how to enumerate the active processes. Once I found the
particular process I want to end, I end it by sending Windows messages.
Here is the code:
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)
{
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
EnumInfoStruct sInfo;
// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD);
BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);
BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);
// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *);
BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD,
LPDWORD);
DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD);
// VDMDBG Function Pointers.
INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM);
osver.dwOSVersionInfoSize = sizeof(osver);
if (!GetVersionEx(&osver))
return FALSE;
// If Windows NT 4.0
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion == 4) {
__try {
hInstLib = LoadLibraryA("PSAPI.DLL");
if (hInstLib == NULL)
return false;
hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
return false;
// Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress(hInstLib,
"EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD)) GetProcAddress(hInstLib,
"GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
return false;
dwSize2 = 256 * sizeof(DWORD);
do {
if (lpdwPIDs) {
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
dwSize2 *= 2;
}
lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0,
dwSize2);
if (lpdwPIDs == NULL)
return false;
if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize))
return false;
} while (dwSize == dwSize2);
dwSize /= sizeof(DWORD);
// Loop through each ProcID.
for (dwIndex = 0; dwIndex < dwSize; dwIndex++) {
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hProcess, &hMod,
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hProcess, hMod,
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam))
break;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL");
if (hInstLib == NULL)
return false;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
return false;
}
lpfCreateToolhelp32Snapshot =
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot");
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapshot == NULL)
return false;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
return false;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapShot, &procentry);
// While there are processes, keep looping.
while (bFlag) {
String sExeFile = procentry.szExeFile;
if(sExeFile.LowerCase() == "TheOneIWantToTerminate")
{
TerminateApp(procentry.th32ProcessID,2000);
}
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32ProcessID, 0,
procentry.szExeFile, lParam)) {
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot, &procentry);
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
//---------------------------------------------------------------------------
DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
{
HANDLE hProc ;
DWORD dwRet ;
hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,
dwPID);
if(hProc == NULL)
{
return TA_FAILED ;
}
EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;
if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)
dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
else
dwRet = TA_SUCCESS_CLEAN ;
CloseHandle(hProc) ;
return dwRet ;
}
//------------------------------------------------------------------
BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
{
DWORD dwID ;
GetWindowThreadProcessId(hwnd, &dwID) ;
if(dwID == (DWORD)lParam)
{
PostMessage(hwnd, WM_QUERYENDSESSION, 0, 0) ;
PostMessage(hwnd, WM_ENDSESSION, 0, 0) ;
}
return TRUE ;
}
//--------------------------------------------------------------------
Again, I found most of this code in an example trying to end an application.
It works beautifully. The only thing is the system tray icon. My reasoning
for thinking I could use the Shell_NotifyIcon function is that this code
gives me the HANDLE (HWND) for the application. All I need then is the
taskbarID. If there is no hope for the Shell_NotifyIcon, I get back to one
of my original questions. Is there any other way to do a general refresh of
the system tray programatically? I did try one thing that half way worked.
I set the cursor position down into the system tray. If it just happened to
land on the icon, it did go away.
Thanks again,
AJ
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:43821387$1@newsgroups.borland.com...
>
> "AJ" <adam_bouchard@sbcglobal.net> wrote in message
> news:438201d2@newsgroups.borland.com...
>
>> When my application ends it, the icon is still in the
>> system tray until the mouse pointer is pointed on the
>> system tray.
>
> How exactly are you terminating the application? It sounds like you are
> not
> allowing it to terminate gracefully and clean up after itself.
>
>> I have tried to investigate the Shell_NotifyIcon function,
>> but since the application is not mine, I do not know the
>> taskbar ID of the application.
>
> You cannot use Shell_NotifyIcon() to control other application's icons,
> only
> your own.
>
>> Is there any other way to do a general refresh of the system tray
>> (similar to what happens when the mouse pointer is on the system tray)
>> programatically?
>
>> In searching the web, Visual C++ has a utility call Spy++ that can
>> imspect the icons in the system tray and return the taksbar ID.
>
> Spy++ is not part of VC++ specifically. It is a standalone utility that
> you
> can download from Microsoft separately. It does not, however, have a
> specific option of inspecting System Tray icons. It can, however,
> intercept
> and peek into any message for any window. So, you can intercept the
> WM_COPYDATA message that Shell_NotifyIcon() sends to the System Tray.
> Shell_NotifyIcon() puts a copy of the NOTIFYICONDATA structure into the
> WM_COPYDATA message (amongst sone other things). You can also intercept
> the
> WM_COMMAND messages that are sent when the mouse is moved over the icons.
> The wID member of the message will be the icon ID.
>
>> Then the Shell_NotifyIcon function can be used.
>
> It is quite not that simple. Shell_NotifyIcon() also requires an HWND.
> It
> is the combination of HWND and ID that uniquely identifies each icon in
> the
> System Tray. You would have to know which HWND is also being passed with
> the ID.
>
>> Does C++ Builder have any utility like this
>
> BCB ships with WinSight, which works similarly to Spy++. I prefer Spy++
> myself, though, because it works better than WinSight. WinSight is a
> memory
> hog and tends to crash a lot.
>
>
> Gambit
>
>
Technical Details
Message-ID:
<438251cb@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailReferences:
<438201d2@newsgroups.borland.com> <43821387$1@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,8ad97936ff76c516 X-Google-Attributes: gid10cc67,public X-Google-Language: ENGLISH,ASCII-7-bit Reply-To: "AJ" <adam_bouchard@sbcglobal.net> From: "AJ" <adam_bouchard@sbcglobal.net> Newsgroups: borland.public.cppbuilder.nativeapi References: <438201d2@newsgroups.borland.com> <43821387$1@newsgroups.borland.com> Subject: Re: Refresh The System Tray Date: Mon, 21 Nov 2005 17:02:30 -0600 Lines: 343 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.2180 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180 X-RFC2646: Format=Flowed; Original NNTP-Posting-Host: 70.250.210.228 Message-ID: <438251cb@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1132614091 70.250.210.228 (21 Nov 2005 15:01:31 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail