🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #4786

Re: Refresh The System Tray

#4786
From: AJ
Date: Mon, 21 Nov 2005 23:02
341 lines
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-mail
References: <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