Page 1 of 2

Set Multiple

Posted: Thu Nov 22, 2007 1:33 pm
by Peterg
Hi all
If I call SetMultiple(.F.) at the tope of my main function this does not prevent my app from running more than once on the same PC

Is there something else that I should be doing

Thanks
Peter

Posted: Thu Nov 22, 2007 2:10 pm
by driessen
Peter,

You could add this code at the beginning of your main function :

Code: Select all

IF IsExeRunning(cFileName(HB_ARGV(0)))
   MsgAlert("Your application is already running !","Attention")
   Quit
ENDIF
This function tests if your current application is already running on your system.

Good luck.

Posted: Thu Nov 22, 2007 2:44 pm
by Peterg
Many thanks that works well

Posted: Thu Nov 22, 2007 8:31 pm
by Otto
What do you pass as cFileName - the name of the EXE or the Title of the window? Does it work if the exe is minimized?
Regards,
Otto

Posted: Thu Nov 22, 2007 8:38 pm
by Antonio Linares
Otto,

The parameter is HB_ARGV(0) which it is the name and path of the EXE

Posted: Thu Nov 22, 2007 10:32 pm
by Enrico Maria Giordano
Otto wrote:What do you pass as cFileName
Please note that cFileName() is a function.

EMG

Posted: Fri Nov 23, 2007 12:11 am
by James Bott
This works similar to the old 16bit way; if the EXE is already running it maximizes it and brings it to the foreground.

James

9/15/2005 5:28 PM
Run only 1 instance of an exe

Code: Select all

// Author: "hua" <tomyam At rocketmail Dot com>

 function main()
  if AlreadyRunning()
     return
  endif
  .
  .
return
/**************************************************************************

  If an exe is already running, bring window to front and maximize it.

  NOTE: Though the exe is the same, but if it's being run from a different
        path, they're considered different exe when using this routine.
*********/
#include "fivewin.ch"
#define GW_HWNDFIRST     0
#define GW_HWNDLAST         1
#define GW_HWNDNEXT         2
#define GW_HWNDPREV         3
#define GW_OWNER         4
#define GW_CHILD         5

#define SW_SHOWMAXIMIZED 3

function AlreadyRunning()
  local lRet := .f., cMod := hb_Argv( 0 ), hWnd
  if isExeRunning( cFileName( cMod ) )
     hWnd := findWindowByModuleFilename( cMod )
     setForeGroundWindow(hWnd)
     showWindow( hWnd, SW_SHOWMAXIMIZED)
     lRet := .t.
  endif
return lRet
//----------------------------------------------------------------------
static function FINDWINDOWBYMODULEFILENAME( cModuleFileName )

    LOCAL hWnd := getForegroundWindow(), cFile, hRet

    while hWnd != 0
        cFile := getWindowModuleFilename( hWnd )
        cFile := left(cFile, len(cFile)-1) // remove null-termination char
        IF cFile == cModuleFileName
           hRet := hWnd
           exit
        ENDIF

        hWnd := getWindow( hWnd, GW_HWNDNEXT )
    enddo
return hRet
//--------------------------------------------------------------------------
DLL32 FUNCTION GETFOREGROUNDWINDOW() AS LONG;
      PASCAL FROM "GetForegroundWindow" LIB "user32.dll"
//--------------------------------------------------------------------------
#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"

HB_FUNC( GETWINDOWMODULEFILENAME ) // ( hWnd ) --> cFileName
{
    char szFileName[ 256 ];

    UINT wChar = GetWindowModuleFileName( ( HWND ) hb_parnl( 1 ),
szFileName, 256 );

    hb_retclen( szFileName, wChar );
}

#pragma ENDDUMP

Posted: Fri Nov 23, 2007 8:03 am
by Otto
Thanks to all. Thank you James.

I was too quick with my question.
What I search is a method to bring the running prg to the forground.

At the moment I do the task the following way but I thought there would be a better method without a fix coded Window title - as I check for a previous exe before I create the main window.


if IsExeRunning( cFileName( HB_ARGV( 0 ) ) )
ShowApplication()
else
/*
Main Programm
********** -> On first start of the program I write oWnd:cTitle() to a ini-file.
*/
endif

Then I test with IsExeRunning and if YES
I call function ShowApplication
in the FindWnd() function I use the Window-title which is stored in the Ini-file.

I will try as James suggested with FINDWINDOWBYMODULEFILENAME in stet of FindWnd().

Posted: Fri Nov 23, 2007 8:13 am
by Richard Chidiak
Otto

This is a sample

#include "FiveWin.ch"

#define GW_CHILD 5
#define GW_HWNDNEXT 2

function Main()

local oWnd

if IsExeRunning( cFileName( HB_ARGV( 0 ) ) )
ShowApplication()
else
DEFINE WINDOW oWnd TITLE "Test"

ACTIVATE WINDOW oWnd
endif

return nil

function ShowApplication()

local hWnd := FindWnd( cFileNoExt( HB_ARGV( 0 ) ) )

if hWnd != nil
SetForeGroundWindow( hWnd )
endif

return nil

function FindWnd( cTitle )

local hWnd := GetWindow( GetDesktopWindow(), GW_CHILD )

while hWnd != 0
if Upper( cTitle ) $ Upper( GetWindowText( hWnd ) )
return hWnd
endif

hWnd = GetWindow( hWnd, GW_HWNDNEXT )
end

return nil

Posted: Fri Nov 23, 2007 8:34 am
by Otto
Thank you Richard. Does this work on minimized?
I tested your code but it does not bring a minimized window to the foreground.
This is my test:
FindWnd1 is your code

FindWnd1
hWnd = 36700336 and cTitle = xRechnung
FindWnd the way with INI-file
hWnd=38732612 and cTitle = W i n H o t e l * 2007-Juni Demo - Computer-Nr: 5
This way it works. I use Vista.

function FindWnd1( cTitle )
local hWnd := GetWindow( GetDesktopWindow(), GW_CHILD )
msginfo(cTitle )
while hWnd != 0
if Upper( cTitle ) $ Upper( GetWindowText( hWnd ) )
return hWnd
endif
hWnd = GetWindow( hWnd, GW_HWNDNEXT )
end
return nil


function FindWnd( cTitle )
local hWnd := GetWindow( GetDesktopWindow(), GW_CHILD )
msginfo(cTitle )
while hWnd != 0
if Upper( cTitle ) $ Upper( GetWindowText( hWnd ) )
return hWnd
endif
hWnd = GetWindow( hWnd, GW_HWNDNEXT )
end
return nil

Posted: Fri Nov 23, 2007 6:12 pm
by James Bott
I found a bug in the code I posted above. This line:

Code: Select all

        cFile := left(cFile, len(cFile)-1) // remove null-termination char 
Apparently there is no null-termination character so it is truncating the name by one character and this the funcion is returning hWnd as nil always. I fixed it like this:

Code: Select all

if right( cFile, 1) == chr(0)
   cFile := left(cFile, len(cFile)-1) // remove null-termination char 
endif
So hWnd is found.

However setForegroundWindow() window doesn't appear to do anything. I researched this via Google and it seems that you have to call allowSetForegroundWindow() first, but xHarbour does not have this function. I found it in xHarbour\contrib\what32\source\_winwnd.c and I cut and pasted it into the test program. But still no luck. Anyone have any ideas?

James

Code: Select all

#pragma BEGINDUMP


#ifndef ASFW_ANY
  #define ASFW_ANY    ((DWORD)-1)
#endif

HB_FUNC( ALLOWSETFOREGROUNDWINDOW )
{

   HINSTANCE h = LoadLibraryEx( "user32.dll", NULL, 0 );
   BOOL bASFWRet = (BOOL) FALSE ;
   DWORD dwProcessId = ISNIL( 1 ) ? ASFW_ANY : (DWORD) hb_parnl( 1 );

   if( h )
   {
      typedef BOOL (WINAPI *xbAllowSetForegroundWindow)( DWORD dwProcessId );
      xbAllowSetForegroundWindow pfnASFW = (xbAllowSetForegroundWindow)
      GetProcAddress( h, "AllowSetForegroundWindow") ;

      if( pfnASFW )
      {
         bASFWRet = (BOOL) pfnASFW( dwProcessId ) ;
      }

      FreeLibrary( h );
   }

   hb_retl( bASFWRet );
}
#pragma ENDDUMP

Posted: Fri Nov 23, 2007 6:33 pm
by James Bott
I forgot to mention that oWnd:hWnd and findWindowByModuleFilename( cMod ) don't have the same value. I would think that they should. Perhaps we are sending the wrong hWnd to setForeground()?

James

Posted: Fri Nov 23, 2007 7:20 pm
by Enrico Maria Giordano
Otto wrote:What do you pass as cFileName - the name of the EXE or the Title of the window? Does it work if the exe is minimized?
Regards,
Otto
Try this:

Code: Select all

#include "Fivewin.ch"


FUNCTION MAIN()

    LOCAL oWnd

    LOCAL cTitle := "This is a test"

    IF ISEXERUNNING( CFILENAME( HB_ARGV( 0 ) ) )
        SHOWWINDOW( FINDWINDOW( 0, cTitle ), 9 )
        SETFOREGROUNDWINDOW( FINDWINDOW( 0, cTitle ) )
        RETURN NIL
    ENDIF

    DEFINE WINDOW oWnd;
           TITLE cTitle

    ACTIVATE WINDOW oWnd

    RETURN NIL
EMG

Posted: Fri Nov 23, 2007 7:37 pm
by James Bott
Enrico,

Your function works. I note that FindWindow() and oWnd:hWnd have the same value. I don't know why the findWindowByModuleFilename( cMod ) in the code I posted doesn't return the same value as oWnd:hWnd.

There are issues when using the window title. If you have a folder open with the same name, then it can get confused. I expect this is not a big issue as normally a user wouldn't have the folder open, but it did happen to me when testing.

Also, what if you are running a MDI application and the name changes when you open a MDI child. Does it still find a match even though the complete titles are different?

James

Posted: Fri Nov 23, 2007 8:31 pm
by Enrico Maria Giordano
Try this other:

Code: Select all

#include "Fivewin.ch"


FUNCTION MAIN()

    LOCAL oWnd

    LOCAL cTitle := "This is a test"

    IF ISEXERUNNING( CFILENAME( HB_ARGV( 0 ) ) )
        SHOWWINDOW( FINDWND( cTitle ), 9 )
        SETFOREGROUNDWINDOW( FINDWND( cTitle ) )
        RETURN NIL
    ENDIF

    DEFINE WINDOW oWnd;
           TITLE "Prefix - " + cTitle + " - Postfix"

    ACTIVATE WINDOW oWnd

    RETURN NIL


#define GW_HWNDFIRST 0
#define GW_HWNDLAST  1
#define GW_HWNDNEXT  2
#define GW_HWNDPREV  3
#define GW_OWNER     4
#define GW_CHILD     5


FUNCTION FINDWND( cTitle )

    LOCAL hWnd := GETWINDOW( GETDESKTOPWINDOW(), GW_CHILD )

    WHILE hWnd != 0
        IF UPPER( cTitle ) $ UPPER( GETWINDOWTEXT( hWnd ) )
            RETURN hWnd
        ENDIF

        hWnd = GETWINDOW( hWnd, GW_HWNDNEXT )
    ENDDO

    RETURN NIL
EMG