Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 290
  • Last Modified:

Only One Instance Based on Window Title

Hi:

Trying to get a prgram working which will allow only one instance based on the Window's Title, not the exe name. Two windows with the same title are not allowed. It will switch to the current open window if a another copy of the same app is started with the same window title. Before tring the following I tried: HANDLE hSem = CreateSemaphore(NULL, 1, 1, m_pszAppName);

Then I tried:

bool CcdsgraphApp::FindLastInstance()
{
  char chBuff[1024];
  GetWindowText(hWndGraph, chBuff, 1024);
  if (hWndGraph != NULL) SendMessage(hWndGraph, WM_USER + 1, NULL, (LPARAM)chBuff);

   HANDLE hSem = CreateSemaphore(NULL, 1, 1, chBuff);

   if (GetLastError() == ERROR_ALREADY_EXISTS)
     {
          CloseHandle(hSem);
          HWND hWndPrevious = GetWindow(GetDesktopWindow(), GW_CHILD);

          while (IsWindow(hWndPrevious))
          {
         
               if (GetProp(hWndPrevious, chBuff))
               {
                    if (IsIconic(hWndPrevious))
                         ShowWindow(hWndPrevious, SW_RESTORE);

                    SetForegroundWindow(hWndPrevious);
                    SetForegroundWindow(GetLastActivePopup(hWndPrevious));
                    return true;
               }
               
               hWndPrevious = GetWindow(hWndPrevious, GW_HWNDNEXT);
          }
          return true;
     }
     return false;
}//FindLastInstance

Can someone plase help me here. Thanks very much.
Doug
0
DougC
Asked:
DougC
  • 5
  • 4
1 Solution
 
imadjinnCommented:
There is a good deal of discussion about this topic as well as a few different implementations at http://www.experts-exchange.com/Programming/Programming_Languages/MFC/Q_11003321.html

I use the CLimitSingleInstance class for this purpose because it is concise and quite usable.  Add the following header file to your project and then create an instance of it first thing in your application.  If there is another instance running just you just exit.

// LimitSingleInstance.h

#ifndef LimitSingleInstance_H
#define LimitSingleInstance_H

#include <windows.h>

class CLimitSingleInstance
{
protected:
  DWORD  m_dwLastError;
  HANDLE m_hMutex;
 
public:
  CLimitSingleInstance(TCHAR *strMutexName)
  {
    //be sure to use a name that is unique for this application otherwise
    //two apps may think they are the same if they are using same name for
    //3rd parm to CreateMutex
    m_hMutex = CreateMutex(NULL, FALSE, strMutexName); //do early
    m_dwLastError = GetLastError(); //save for use later...
  }
 
  ~CLimitSingleInstance()
  {
    if (m_hMutex)  //don't forget to close handles...
    {
      CloseHandle(m_hMutex); //do as late as possible
      m_hMutex = NULL; //good habit to be in
    }
  }
 
  BOOL IsAnotherInstanceRunning()
  {
    return (ERROR_ALREADY_EXISTS == m_dwLastError);
  }
};
#endif
0
 
DougCAuthor Commented:
Mode Detail:

I should have mentioned the reason that I wanted to use the Window title is that the title changes based on a slected object. I want only one instance of my app per object, but multiple instances if the object is different. That is why I wanted to use the title. I assume that I can use the title with Mutexes?

Thanks,
Doug
0
 
imadjinnCommented:
Yes you can, although I would put some unusual application string before the title to ensure it is yours. (i.e. 'MyApPlIcAtIoN' + Title)  You would also need to create a rename function if the window title will change.  Something like:

void Rename(TCHAR *strMutexName)
{
  // Get rid of our old window title
  CloseHandle(m_hMutex);
  m_hMutex = NULL; //good habit to be in

  m_hMutex = CreateMutex(NULL, FALSE, strMutexName);
  m_dwLastError = GetLastError(); //save for use later...
}
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
DougCAuthor Commented:
Shouldn't this work? The title is unique. It does not seem to work.

bool CcdsgraphApp::FindLastInstance()
{
     char chBuff[128];
     GetWindowText(hWndGraph, chBuff, 128);
     CWnd *pWnd = CWnd::FindWindow(NULL, chBuff );
     if (pWnd)
     {
        // Graph Application already exists: activate it
        pWnd->SetForegroundWindow();
     return TRUE;
     }
     else
     {
     // Graph Application doesn't exist    
     return FALSE;
     }//FindLastInstance

Doug
0
 
arkanesCommented:
That looks like it should work, assuming that the window title is actually 127 characters or less (in production code, use GetWindowTextLength() first).  Check your return values and GetLastError(), maybe that will tell you something.
0
 
imadjinnCommented:
The reason why FindWindow does not always work is that it only examines top-level windows.  If your application is an MDI or creates child windows to handle different files they will not show up.

If you are using a MDI application or some similar architecture perhaps it would be better to limit it to a single instance of the application and store a set of the currently open windows at the application level.  Then you can manage the windows directly without having to make any API calls before creating new windows.
0
 
DougCAuthor Commented:
Still not working. Please Help. len is zero and chbuff is not correct.

MFC Application, .exe file. Only one window, the main app window.


HWND hWndGraph=0;

// CcdsgraphApp initialization

BOOL CcdsgraphApp::InitInstance()
{
     if (FindLastInstance()) return FALSE; //Only one instance allowed

     // Do it here....
return TRUE;
}

bool CcdsgraphApp::FindLastInstance()
{
     char chBuff[1024];
     int len=0;

     len = GetWindowTextLength(hWndGraph);
     GetWindowText(hWndGraph, chBuff, len);
     CWnd *pWnd = CWnd::FindWindow(NULL, chBuff );
     if (pWnd)
     {
    // Graph Application already exists: activate it
     pWnd->SetForegroundWindow();
      return TRUE;
     }
     else
     {
     // Graph Application doesn't exist    
     return FALSE;
     }//FindLastInstance
}
0
 
DougCAuthor Commented:
It seems to be using GetWindowText from winuser.h in \platform sdk\include. The afxwin.h version of GetWindowText only has 2 params.
0
 
imadjinnCommented:
A few things to note:

First, in the call to GetWindowText len should be the length of your buffer, you do not need to check for the length first.

Second, you set hWndGraph to 0.  This is equivalent to NULL.  You will always get an empty chBuff whenever you call the function like this.  It does not have window text yet because it has not been created yet.  Maybe you should generate the title based rather than trying to read it off of the window.
0
 
DougCAuthor Commented:
Thanks for all of yor help.
0

Featured Post

[Webinar] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now