Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / FoxPro, Visual FoxPro Новый топик    Ответить
 Отсечение повторного запуска приложения  [new]
Чернышов Вадим Константинович
Member

Откуда:
Сообщений: 47
Как в visual FoxPro организовать такую штуку:
Если приложение уже запущено, то при повторном запуске этого приложения, оно просто не запускалось.
9 июл 03, 18:04    [256345]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Crip
Member

Откуда:
Сообщений: 2490
Поищите на http://nsvisual.com/ph/list.php3?f=5
Там это много обсуждалось.
При желании могу прислать свой вариант сделанный с помощью виндовых семафоров
9 июл 03, 18:13    [256359]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
thanks universalthread:
************************************************************

* FUNCTION FirstInstance()
************************************************************
* Author............: Gary Foster, Pointsource Consulting, Inc. 104171.3677@compuserve.com
* Project...........: Starbase
* Created...........: 03/13/98 15:39:58
* Copyright.........: Public Domain
*) Description.......: This function uses the creation of a named MUTEX
*) : to determine existing instance of an application.
*) : Call this function very early in an application's
*) : startup to create a named object that can be checked
*) : every time the application is started. If the named
*) : object exists, the function will try to bring foreward
*) : the applications main frame. In this case, the main frame
*) : is the FoxPro _SCREEN. Any other hWnd would do as well.
*) :
* Calling Samples...: IF !FirstInstance()
* : QUIT && Or something along that line.
* : ELSE
* : yada yada yada...
*) Parameter List...: lcStarBase - уникальный идентификатор прилодения
*) : в виде строковой константы
* Major change list.:

FUNCTION FirstInstance()
LPARAMETERS lcStarBase

*-- Declare just enough API functions and constant defines to support this function.
#DEFINE SW_RESTORE 9
#DEFINE ERROR_ALREADY_EXISTS 183
#DEFINE GW_HWNDNEXT 2
#DEFINE GW_CHILD 5

DECLARE INTEGER CreateMutex IN win32api INTEGER, INTEGER, STRING @
DECLARE INTEGER CloseHandle IN win32api INTEGER
DECLARE INTEGER GetLastError IN win32api
DECLARE INTEGER SetProp IN win32api INTEGER, STRING @, INTEGER
DECLARE INTEGER GetProp IN win32api INTEGER, STRING @
DECLARE INTEGER RemoveProp IN win32api INTEGER, STRING @
DECLARE INTEGER IsIconic IN win32api INTEGER
DECLARE INTEGER SetForegroundWindow IN USER32 INTEGER
DECLARE INTEGER GetWindow IN USER32 INTEGER, INTEGER
DECLARE INTEGER ShowWindow IN WIN32API INTEGER, INTEGER
DECLARE INTEGER GetDesktopWindow IN WIN32API

*-- We need a function from Foxtools. I know I could get this from the API, but I'
m lazy.
IF !("FOXTOOLS" $ UPPER(SET("LIBRARY")))
SET LIBRARY TO FOXTOOLS.fll ADDI
ENDIF

LOCAL cExeFlag && Name of the MUTEX
LOCAL nExeHwnd && MUTEX handle
LOCAL hWnd && Window handle
LOCAL lRetVal && Return value of this function

*-- Try and create a new MUTEX with this name.

*!* cExeFlag = "STARBASE"+CHR(0)
IF EMPTY(lcStarBase)
cExeFlag = "STARBASE"+CHR(0)
ELSE
cExeFlag = lcStarBase+CHR(0)
ENDIF
nExeHwnd = CreateMutex(0,1,@cExeFlag)

*-- If the named MUTEX creation fails because it exists already, try to display

*-- the existing application and have this function return .F., presumably

*-- to a calling routine that is deciding whether to continue instantiation.

IF GetLastError() = ERROR_ALREADY_EXISTS

*-- Get the hWnd of the first top level window on the Windows Desktop.

HWND = GetWindow(GetDesktopWindow(), GW_CHILD)

*-- Loop through the windows. If the application has no top level window,

*-- the loop will quickly run out of desktop windows and simply exit.

DO WHILE HWND > 0

*-- Is this the proper window? GetProp looks() for a property we added

*-- the first time, not a caption.

IF GetProp(HWND, @cExeFlag) = 1

*-- If the application window is minimized, open %af_src_str_1failed to open%af_src_str_2t need it any more.

CloseHandle(nExeHwnd)

lRetVal = .F.

ELSE
*-- Add a property to the FoxPro main frame so we can identify this

*-- window again regardless of caption changes.

SetProp(MainHwnd(), @cExeFlag, 1)
lRetVal = .T.
ENDIF

RETURN lRetVal

ENDFUNC


ЗЫ В vfp 7/8, естественно, MainHwnd() лучше заменить на _screen.hWnd.
9 июл 03, 21:17    [256531]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
IgorProgrammer
Member

Откуда:
Сообщений: 687
NNN: Зачем так сложно???

Можно по-простому...
Создать пустую таблицу...

В главной проге вначале всего несколько строк... + функция выхода...
И хай хоть 100 клацають... {:-)}


on error do my_exit
if !used('tab1')
sele 0
use tab1 exclu
endif
on error

Procedure my_exit
messagebox(' Пощастыть наступного разу',64,'')
Quit

При втором заходе побежит по обработчику ошибок на выход...
9 июл 03, 21:46    [256539]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2IgorProgrammer

> Зачем так сложно???

1. Подними запущенную программу, если она свернута в панель задач.
2. Удали файл tab1.dbf (или поломай его, измени пути в программе и т.д.) и попробуй запустить программу хотя бы один раз (только не говори, что пользователь это сделать не сможет)
3. Предложи схему, основанную на твоем методе, при которой программа повторно не запускалась бы под одним логином, но позволяла запускаться под другим.
9 июл 03, 22:01    [256551]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
IgorProgrammer
Member

Откуда:
Сообщений: 687
NNN:

1 При втором входе она сразу идет на выход... Ведь нельзя поднять того че нету...

2 Таблицу надо кинуть туда же где и ехе-шник(там всегда найдет). А если пользователь хряпнет таблицу... так приложение и первый раз не запустится... Пусть пользователь еще и все конфиги с сисами хряпнет... иль отформатит диск где винда и спршивает че у него приложение не запускается...

3 Если я правильно понял его вопрос... Так вроде ему надо что б второй раз небыло... Можно даже с нехорошой мессагой кинуть... Иль в этой таблице занести кому мона - кому нет...


У тебя есть нормальный грусский хелп по win32api...
У меня хелп есть, но через одно место написана... Хотелось бы человеческий...
9 июл 03, 22:23    [256563]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2IgorProgrammer

Дружественней надо быть, юзверь он тоже человек и иногда с него можно поиметь пиво..

> 1 При втором входе она сразу идет на выход... Ведь нельзя поднять того че нету...

Почему нету? Программа уже запущна? Запущена. Зачем заставлять пользователя искать окно программы, если его можно вывести на передный план?

> 2 Таблицу надо кинуть туда же где и ехе-шник(там всегда найдет). А если пользователь хряпнет таблицу... так приложение и первый раз не запустится... Пусть пользователь еще и все конфиги с сисами хряпнет... иль отформатит диск где винда и спршивает че у него приложение не запускается...

Юзвери тоже люди, но зачем лишний раз с ними общаться, особенно когда они не в хорошем расположении духа? Если файла нет, то ему ничего не грозит, следовательно, меньше поводов для общения.

> 3 Если я правильно понял его вопрос... Так вроде ему надо что б второй раз небыло... Можно даже с нехорошой мессагой кинуть... Иль в этой таблице занести кому мона - кому нет...

Попробую обрисовать мой работающий вариант.
1. С любого компьютера под своим логином к sql server может обращаться любой пользователь.
2. Иногда надо запусть две копии программы, например, когда два пользователя хотят сверить свои данные.
3. Если пользователь еще не подключился - висит окно с логином, второе окно с логином не появится.
4. Если пользователь ввел правильнвй пароль, то при повторной запуске его либо перебросит на уже запущенное приложение, либо программа запустится с новым логином.
Это, конечно, выходит за рамки сабжа, но все-таки, попробуй реализовать такую схему через use?
Кстати, еще проще (без поднятия окна):
lcUniqueFileName='..'

if fcreate(lcUniqueFileName)<0
=messagebox('..')
quit


> У тебя есть нормальный русский хелп по win32api...

Есть :) В виде книги. Это практически перевод основных функций:
http://market.yandex.ru/search.xml?hid=&text=%D1%E0%E9%EC%EE%ED+windows+2000+api

> У меня хелп есть, но через одно место написана... Хотелось бы человеческий...

Меня вполне устраивает MSDN. Какой-то вариант лежит здесь:
http://www.cs.virginia.edu/~lcc-win32/
9 июл 03, 23:11    [256579]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Crip
Member

Откуда:
Сообщений: 2490
В vfp 7/8, естественно, MainHwnd() лучше заменить на _screen.hWnd.
Правильно на _vfp.Hwnd ...
10 июл 03, 13:37    [257305]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2Crip

Ну это если уж очень правильно :)
10 июл 03, 14:05    [257376]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Crip
Member

Откуда:
Сообщений: 2490
Нет это просто правильно. _Screen.Hwnd дает не тот hwnd. Я это еще когда сам делал защиту от повторного доступа столкнулся. Думаю и че у меня SetForegroundWindow не отрабатывает
10 июл 03, 14:57    [257499]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2Crip

А у меня в обоих случаях отрабатывет нормально. Относительно, вот так надежнее, наверняка вылетит, а не будет моргать на панели:
n=_screen.WindowState

_screen.WindowState= 1
_screen.WindowState= n

Кстати, у них заголовки разные, что приятно, можно вверху ничего не менять, а в панели задач какой-нибудь счетчик пустить.
10 июл 03, 15:12    [257552]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Crip
Member

Откуда:
Сообщений: 2490
В любом случае
set library to foxtools.fll

messageb(_vfp.Hwnd = Mainhwnd())

Выдаст .T.
10 июл 03, 15:24    [257581]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Чернышов Вадим Константинович
Member

Откуда:
Сообщений: 47
Да уж палемику вы развили :)
Дело в том, что я не особый сторонник фокса, даже противник, но по долгу службы приходится вести одну дырявую прогу, которую писал, соответственно я. Так вот в этой проге призпуске происходит копирование базы данных из одной папки в другую, и если вдрук глупый юзверь запускает ее два раза подряд, то файлы начисто убиваются, а так как фокс с файлами работает на дос уровне, то их поднять нериально, если конечно прям сразу это сделать, но как правило, юзер наделает еще всяких всячин, а уж потом сообщает о глюках :(

Ну так вот текст там такой:

LOCAL lcMainClassLib
LOCAL lcLastSetTalk,lcLastSetPath,lcLastSetClassLib,lcOnShutdown
*-- Save and configure environment.
lcLastSetTalk=SET("TALK")
SET TALK OFF
set exact on
lcLastSetPath=SET("PATH")
*CD "\foxpro projects\rat\"
SET PATH TO ;DATA;INCLUDE;FORMS;GRAPHICS;HELP;LIBS;MENUS;PROGS;REPORTS
PUSH MENU _msysmenu
lcLastSetClassLib=SET("CLASSLIB")
lcMainClassLib="libs\rat"
SET CLASSLIB TO (lcMainClassLib) ADDITIVE
lcOnShutdown="ShutDown()"
ON SHUTDOWN &lcOnShutdown
ON ERROR ErrorHandler(ERROR(),PROGRAM(),LINENO())
_shell="DO Cleanup IN progs\rat"

*-- Instantiate application object.
RELEASE goApp
PUBLIC goApp
goApp=CREATEOBJECT("cApplication")

*-- Configure application object.

goApp.SetCaption("Рейтинг")
*goApp.cStartupMenu="menus\rat"
goApp.cStartupForm="forms\start"
* Запуск через пороль
*goApp.cStartupForm="forms\password"

*-- Show application.
goApp.Show


*-- Release application.
RELEASE goApp

*-- Restore default menu.
POP MENU _msysmenu

*-- Restore environment.
ON ERROR
ON SHUTDOWN
IF NOT lcLastSetClassLib==SET("classlib")
RELEASE CLASSLIB (lcMainClassLib)
ENDIF
IF EMPTY(lcLastSetPath)
SET PATH TO
ELSE
SET PATH TO &lcLastSetPath
ENDIF
IF lcLastSetTalk=="ON"
SET TALK ON
ELSE
SET TALK OFF
ENDIF
RETURN



FUNCTION ErrorHandler(nError,cMethod,nLine)
LOCAL lcErrorMsg,lcCodeLineMsg

WAIT CLEAR
lcErrorMsg=MESSAGE()+CHR(13)+CHR(13)
lcErrorMsg=lcErrorMsg+"Method: "+cMethod
lcCodeLineMsg=MESSAGE(1)
IF BETWEEN(nLine,1,10000) AND NOT lcCodeLineMsg="..."
lcErrorMsg=lcErrorMsg+CHR(13)+"Line: "+ALLTRIM(STR(nLine))
IF NOT EMPTY(lcCodeLineMsg)
lcErrorMsg=lcErrorMsg+CHR(13)+CHR(13)+lcCodeLineMsg
ENDIF
ENDIF
IF MESSAGEBOX(lcErrorMsg,17,_screen.Caption)#1
ON ERROR
RETURN .F.
ENDIF
ENDFUNC



FUNCTION ShutDown
*IF TYPE("goApp")=="O" AND NOT ISNULL(goApp)
* RETURN goApp.OnShutDown()
*ENDIF
*Cleanup()

*nDialogType = 4 + 32 + 256
*set date to ITALIAN
*SET HOURS TO 24
*SET SECONDS ON
*dt = DATETIME()
*s = TTOC(dt)
*MESSAGEBOX(s , nDialogType, "ДАТА/ВРЕМЯ")
*zapusk = ".\BackUpData.bat " + "/" + alltrim(s)
*MESSAGEBOX( zapusk , nDialogType, "ДАТА/ВРЕМЯ")


! /N "BackUp.exe"

CLOSE ALL
QUIT
ENDFUNC


FUNCTION Cleanup

IF CNTBAR("_msysmenu")=7
RETURN
ENDIF
ON ERROR
ON SHUTDOWN
SET CLASSLIB TO
SET PATH TO
CLEAR ALL
CLOSE ALL
POP MENU _msysmenu
RETURN


Вы мне можите точно написать в каком месте, и какой код нужно вставить :)
Буду признателен, а то уже эта проблема достала.
14 июл 03, 18:16    [261247]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2Чернышов Вадим Константинович

> но по долгу службы приходится вести одну дырявую прогу, которую писал, соответственно я.

Сдается мне, что сию дырявую прогу писал преимущественно визард..

> Вы мне можите точно написать в каком месте, и какой код нужно вставить :)

В самом начале (перед всем остальным)
IF !FirstInstance('MyProgram')

CANCEL
ENDIF
14 июл 03, 21:33    [261401]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Чернышов Вадим Константинович
Member

Откуда:
Сообщений: 47
Вот ведь, сам и описался
Прогу на самомом деле писал не я :)

Ну вставил я в сомое начало:


IF !FirstInstance('Baza')
CANCEL
ENDIF



А при компиляции FoxPro (5.0) ругается:

Unable to find Unknown FIRSTINSTANSE

Что дальше то делать?
16 июл 03, 14:46    [264217]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
2Чернышов Вадим Константинович

Ах, ну да!
Будь проще и люди к тебе потянутся: Короче, вместо того, что я тебе написал в прошлый раз, пиши:
if fcreate('tmp12345.tmp')<0

cancel
endif
16 июл 03, 15:01    [264259]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
linnad
Member

Откуда:
Сообщений: 7
Привет!
При запуске создавай файл (любой), при выходе удаляй.
Перед запуском сделай проверку наличия этого файла.
18 июл 03, 06:08    [266645]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Чернышов Вадим Константинович
Member

Откуда:
Сообщений: 47
Привет всем
Решил я эту проблему вот так:
В самом начале проги рисуем:

if (file('test.tmp') == .t.)
quit
else
fcreate('test.tmp')
endif


И в функции ShutDown добавляем строчку:

delete file test.tmp


И все работает.
Только вот, одна деталь, дырка есть, если вдруг юзверь при работающей проге файл "test.tmp" грохнет, то прога может быть повторно запущена.
Если же при создании файла "test.tmp" устанавливать ему атрибут СКРЫТЫЙ, то тогда прога не работает :(((
Что можите посоветовать?
19 июл 03, 14:19    [268358]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Чернышов Вадим Константинович
Member

Откуда:
Сообщений: 47
2NNN
Твой метод я так и не просек! (Либо лыжи не едут либо ....)
Ошибка все равно повторяется!
19 июл 03, 14:21    [268361]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
Чернышов Вадим Константинович

> Только вот, одна деталь, дырка есть, если вдруг юзверь при работающей проге файл "test.tmp" грохнет, то прога может быть повторно запущена.
Если же при создании файла "test.tmp" устанавливать ему атрибут СКРЫТЫЙ, то тогда прога не работает :(((
Что можите посоветовать?


Объясняю свой код от 16 июл 03, 15:01. Более правильный код:
public hFile

hFile=fcreate('test.tmp')
if hFile <0
quit
endif
*!* ShutDown
=fclose(hFile)
delete file test.tmp


Перерь о том, как это работает. Резервирует глобальную переменную для хендла файла. Следующий этап создание файла. Возможные варианты:
1. Файл отсутсвует. В этом случае будет созадан новый файл, который будет монопольно захвачен и удалить его, пока программа работает, невозможно. Значение hFile будет больше нуля.
2. Файл существует и захвачен работающей программой. В этом случае произойдет ошибка при создании файла и значение hFile будет -1 (type 'help fcreate').
3. Файл существует, но не захвачен. Будет создан новый файл, который перезапишет старый. Далее как в варианте 1.
Привыходе закрываем файл и удаляем его.
Почему до этого я привел более короткий вариант? Да просто я не считаю, что один кластер на диске стоит возни с отслеживанием глобальных переменных в программе.

> Твой метод я так и не просек! (Либо лыжи не едут либо ....)
Ошибка все равно повторяется!


Unable to find Unknown FIRSTINSTANSE?
При сборке проект не может найти функцию FirstInstance, которая приведена в моей мессаге от 9 июл 03, 21:17. Сразу скажу, что файл FOXTOOLS.fll должен быть виден ехешнику, иначе будет runtime error.
Если тебе ненужно поднимать свернутые окна и выводить программу на передний план, то достаточно и варианта с файлом.
19 июл 03, 15:03    [268365]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
NNN
Member

Откуда:
Сообщений: 2141
По поводу скрытых файлов:
?FILE('c:\boot.ini') && .F.

?FILE('c:\boot.ini',1) && .T.
19 июл 03, 15:07    [268366]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Aijik
Member

Откуда:
Сообщений: 147
2 NNN

В вашем споре с Crip'ом относительно хэндла фоксового окна, Crip совершенно прав. Согласно нововведениям в VFP7, эти два объекта были разделены. А именно: _VFP проедставляет всё окно фокса целиком, _SCREEN представляет клиентскую часть этого окна (то, куда выводится результат ?<тра-та-та>). Поэтому в контексте рассматриваемого вопроса _VFP.hWnd правильнее.
23 июл 03, 14:51    [272605]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Aijik
Member

Откуда:
Сообщений: 147
2 IgorProgrammer

Есть еще одна ситуация, когда способ NNN с Mutex'ом предпочтительней. А именно - если EXE лежит в сети и по-сети же и запускается. В вашем способе с USED при таких обстоятельствах 2-й юзер на другом сетевом компе не запустит прогу, т.к. нарвется на эксклюзивную блокировку таблицы, лежащей там же на серваке. Mutex же создается в памяти винды на каждой отдельной машине и ограничивает запуск 2-й копии проги на ЭТОМ ЖЕ компе. На любой же другой машине по-сети прогу запустить можно
23 июл 03, 15:09    [272666]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Samir
Member

Откуда: Азербайджан, г. Баку
Сообщений: 1382
if file('test.tmp')
quit
else
create table test.tmp (i i)
endif
24 июл 03, 09:24    [273631]     Ответить | Цитировать Сообщить модератору
 Re: Отсечение повторного запуска приложения  [new]
Samir
Member

Откуда: Азербайджан, г. Баку
Сообщений: 1382
Или еще лучше

err=.f.
if file('test.dbf')
on error err=.t.
use test excl
if err
quit
endif
else
create table test (i i)
endif
24 июл 03, 09:26    [273637]     Ответить | Цитировать Сообщить модератору
Все форумы / FoxPro, Visual FoxPro Ответить