Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2006.10.29;
Скачать: [xml.tar.bz2];

Вниз

Пара вопросов   Найти похожие ветки 

 
DelphiLamer ©   (2006-10-08 11:37) [0]

Как замутить так,
чтобы приложение можно было запустить только в одной копии?
//////////////////////////////////////////////////////////////////////////
Как узнать версию(автора, описание ит.п.) exe или dll файла?


 
ProgRAMmer Dimonych ©   (2006-10-08 12:15) [1]

Из DelphiWorld:

program Project1;

uses
 Forms,
 Windows,
 Unit1 in "Unit1.pas" {Form1};

{$R *.RES}

var
 hwnd: THandle;

begin
 hwnd := FindWindow("TForm1", "Form1");
 if hwnd = 0 then
 begin
   Application.Initialize;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
 end
 else
   SetForegroundWindow(hwnd)
end.


 
Anatoly Podgoretsky ©   (2006-10-08 13:43) [2]

Вопрос настолько популярный, ищи по ключевому слову Mutex или ко мне на сайт за FAQ


 
Johnmen ©   (2006-10-08 13:56) [3]

или по ключевому слову Semaphore


 
Anatoly Podgoretsky ©   (2006-10-08 14:33) [4]

Semaphore не для этой цели, а так конечно можно использовать большинство объектов ядра, но мьютекс самый прямой путь именно для этого и предназначен, два состояния есть/нет


 
Ученик чародея ©   (2006-10-08 14:36) [5]


program xxx;

uses
 oneruned in "oneruned.pas",
 Forms,
...

-------------------------------------------------------------------
unit oneruned;

interface

implementation
uses
 Windows;
var
 Mutex : THandle;
 MutexName : array[0..1024] of Char;

function StopLoading : boolean;
var
 L,I : integer;
begin
 // В качестве уникального имени мьютекса используем полный путь
 // к исполняемому файлу приложения
 L := GetModuleFileName(MainInstance,MutexName,SizeOf(MutexName));
 // В имени мьютекса нельзя использовать обратные слэши, поэтому
 // заменяем их на прямые
 for I := 0 to L - 1 do
   if MutexName[I] = "\" then
   begin
     MutexName[I] := "/";
   end;
 Mutex := CreateMutex(nil,false,MutexName);

 Result := (Mutex = 0) or // Если мьютекс не удалось создать
 (GetLastError = ERROR_ALREADY_EXISTS); // Если мьютекс уже существует
end;

initialization
 if StopLoading then halt;

finalization
 if Mutex <> 0 then
   CloseHandle(Mutex);
end.


 
Anatoly Podgoretsky ©   (2006-10-08 14:39) [6]

У кода есть один недостаток, программа может быть запущена из разных папок, поэтому имя мьютекса должно быть предопределенное, работа программы не должна зависить от ее положения. Поэтому если выкинуть все до CreateMutex, то будет лучше.


 
Anatoly Podgoretsky ©   (2006-10-08 14:40) [7]

Видимо это был ленивый программист или не совсем интеллектуально развитый, который или не смог придумать имя или ему было лень.


 
Percent   (2006-10-08 14:46) [8]

или ему было лень...

нажать Ctrl + Shift + G


 
Eraser ©   (2006-10-08 14:47) [9]

> [5] Ученик чародея ©   (08.10.06 14:36)

данный код можно использовать максимум на ОС Win2K, в XP может привести к ошибкам.
Terminal Services:  The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces.
(c) MSDN.
AFAIK по-умолчанию мьютекс создается в локальном пространстве имен терминальной сессии.
вот более правильный код.
function GlobalCheck: Boolean;
var
 pSD: PSECURITY_DESCRIPTOR;
 sa: SECURITY_ATTRIBUTES;
begin
 Result := true;
 pSD := PSECURITY_DESCRIPTOR(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
 if not InitializeSecurityDescriptor (pSD,
    SECURITY_DESCRIPTOR_REVISION) then
 begin
   LocalFree(HLOCAL(pSD));
   Exit;
 end;
 // Добавить NULL ACL к дескриптору безопасности.
 if not SetSecurityDescriptorDacl(pSD, true, nil, false) then begin
   LocalFree(HLOCAL(pSD));
   Exit;
 end;
 sa.nLength := sizeof(sa);
 sa.lpSecurityDescriptor := pSD;
 sa.bInheritHandle := true;
 if Win32Platform = VER_PLATFORM_WIN32_NT then
 begin
   CreateMutex(@sa, True, "Global\ROMServerGlobal");
   if GetLastError = ERROR_ALREADY_EXISTS then
   begin
     Result := false;
   end;
 end;
end;


 
Eraser ©   (2006-10-08 14:53) [10]

> [9] Eraser ©   (08.10.06 14:47)

точнее полный код выглядит так (чтобы работало на win9x/NT системах)

     CreateMutex(nil, True, "ROMServer");
     if GetLastError = ERROR_ALREADY_EXISTS then
     begin
       MessageBox(0, PChar("Already EXISTS!"), SApplicationName, MB_ICONERROR);
       Halt;
     end;
     if not GlobalCheck then
     begin
       MessageBox(0, PChar("Already EXISTS!"), SApplicationName, MB_ICONERROR);
       Halt;
     end;


 
Внук ©   (2006-10-08 14:56) [11]

>>Johnmen ©   (08.10.06 13:56) [3]
>>или по ключевому слову Semaphore
 Или по ключевому слову "замутить"


 
kaif ©   (2006-10-08 15:01) [12]

А я вот делаю проще.

Просто отыскиваю класс или название главного окна моего приложения при помощи функции API FindWindow.
Это примитивно, но дубово. Нужно лишь назвать главное окно как-нибудь хитрее, чем просто "MainForm".

Разве так нельзя?


 
Внук ©   (2006-10-08 15:02) [13]

kaif ©   (08.10.06 15:01) [12]
 Можно. Если окно уже успело создаться...


 
Eraser ©   (2006-10-08 15:03) [14]

> [12] kaif ©   (08.10.06 15:01)


> Разве так нельзя?

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


 
kaif ©   (2006-10-08 15:25) [15]

Внук ©   (08.10.06 15:02) [13]
kaif ©   (08.10.06 15:01) [12]
Можно. Если окно уже успело создаться...


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

Я как-то применял еще один способ - файл отображаемый в память. Правда не помню, как это делалось. возможно, второй способ надежнее. Но первый понятнее и удобнее в 99% случаев, ИМХО.

К тому же относительно использования GetModuleFileName или ParamStr(0) могу сказать следующее.  А что, если вдруг юзер переименует EXE-файл приложения и запустит второй экземпляр таким способом?

Как-то недавно я изводил один вирус. Вирус делал вот что: при попытке запустить RegEdit, он закрывал его. Я просто переименовал файл RegEdit, спокойно его запустил и нашел путь к файлу вируса в реестре там, где свой автозапуск прописывают все трояны на свете. После чего я вышел из системы, загрузился во второй системе, удалил файл вируса, вернулся, запустил уже нормально RegEdit и удалил лишнюю запись из HK_LOCAL_MACHINE/Software/Microsowft/Windows/CurrentVersion/Run.

Если бы создатели вируса искали не процесс RegEdit, а имя класса окна RegEdit, мне пришлось бы дольше мучиться.


 
VirEx ©   (2006-10-08 16:33) [16]

program Project1;

uses
Forms,
Windows,
Unit1 in "Unit1.pas" {Form1};

{$R *.RES}

var
hwnd: THandle;

const
txtMutex = "MYNAMEISBORISILIVEINTHEMOSCOW";


begin
if OpenMutex(MUTEX_ALL_ACCESS,false,txtMutex ) = 0 then begin
 CreateMutex(nil,true,txtMutex);//устанавливаем мьютекс

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end;
end.


 
Anatoly Podgoretsky ©   (2006-10-08 18:23) [17]


> нажать Ctrl + Shift + G

Тоже лень


 
Ученик чародея ©   (2006-10-08 18:36) [18]


> Anatoly Podgoretsky ©   (08.10.06 14:39) [6]
> У кода есть один недостаток, программа может быть запущена
> из разных папок, поэтому имя мьютекса должно быть предопределенное,
>  работа программы не должна зависить от ее положения. Поэтому
> если выкинуть все до CreateMutex, то будет лучше.


Обычно, программы запускаемые из разных папок - разные программы. А запуск одиночного приложения реализуется в основном для того чтобы пользователь зажав мышку на иконке приложения не получил 10 одновременных запусков.

Этот код хорош тем, что его можно просто подключить к проекту и дальше не думать о проблеме.


 
Anatoly Podgoretsky ©   (2006-10-08 18:40) [19]

Не всегда условие обычности выполняется, пользователи быстро поймут, что можно обойти твое ограничение просто запустив из папки. Лучше предопределенное имя, например по Ctrl + Shift + G, тоже думать не нужно и ошибка исключена и код короче.


 
vidiv ©   (2006-10-08 19:04) [20]


> program Project1;
>
> uses
> Forms,
> Windows,
> Unit1 in "Unit1.pas" {Form1};
>
> {$R *.RES}
>
> var
> hwnd: THandle;
>
> const
> txtMutex = "MYNAMEISBORISILIVEINTHEMOSCOW";
>
> begin
> if OpenMutex(MUTEX_ALL_ACCESS,false,txtMutex ) = 0 then
> begin
>  CreateMutex(nil,true,txtMutex);//устанавливаем мьютекс
>   Application.Initialize;
>   Application.CreateForm(TForm1, Form1);
>   Application.Run;
> end;
> end.

И все же данный код не дает 100% гарантию. Шанс что будет запущенно два приложения все же остается :)


 
Marser ©   (2006-10-08 19:06) [21]

> [3] Johnmen ©   (08.10.06 13:56)
> или по ключевому слову Semaphore

Семафор, надо полагать, нужен, если копий может быть две, три, четыре... но не больше N.


 
Anatoly Podgoretsky ©   (2006-10-08 19:08) [22]


> И все же данный код не дает 100% гарантию. Шанс что будет
> запущенно два приложения все же остается :)

Зато вот этот даст
Mutex := CreateMutex(nil,false,MutexName);

Result := (Mutex = 0) or // Если мьютекс не удалось создать
(GetLastError = ERROR_ALREADY_EXISTS); // Если мьютекс уже существует


 
Anatoly Podgoretsky ©   (2006-10-08 19:10) [23]


> Семафор, надо полагать, нужен, если копий может быть две,
>  три, четыре... но не больше N.

Да семафор это счетчик


 
Loginov Dmitry ©   (2006-10-08 19:17) [24]

Обычно так делаю:

program Project1;

uses
 Windows;
.........

begin
 CreateMutex(nil, False, "[{395DFCF9-4421-44AE-9090-41ED6827F034}]");
 if GetLastError = ERROR_ALREADY_EXISTS then Halt;
.....
end.


Гарантия - процентов 99, но пока ни разу не подводило :)


 
Anatoly Podgoretsky ©   (2006-10-08 19:19) [25]

А на что отводишь один процент, вроде шансов нет. Это объект ядра и создаются они только последовательно.


 
Пусик ©   (2006-10-08 19:23) [26]


> Anatoly Podgoretsky ©   (08.10.06 19:19) [25]
> А на что отводишь один процент, вроде шансов нет. Это объект
> ядра и создаются они только последовательно.


Наверное, один процент - это вероятность запуска в терминальной сессии...


 
Anatoly Podgoretsky ©   (2006-10-08 19:31) [27]

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


 
Пусик ©   (2006-10-08 19:33) [28]


> Anatoly Podgoretsky ©   (08.10.06 19:31) [27]
> Ну и что, каждый терминальный пользователь имеет право запустить
> программу, сессии изолированы.


В том случае, если программой это предусмотрено.


 
Loginov Dmitry ©   (2006-10-08 19:36) [29]

Anatoly Podgoretsky ©   (08.10.06 19:19) [25]
А на что отводишь один процент


А один процент - это когда пофиг - запустится ли прога или нет. Например мы на работе пишем софт, вероятность запуска которого - 90 %. По каким причинам оставшиеся 10 % - не известно!

... Куда-то не в то русло ушел. Короче 1% отвожу на "военное время" :)



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2006.10.29;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.06 c
1-1158750131
salexn
2006-09-20 15:02
2006.10.29
использование TWebBrowser


15-1160295530
ArtemESC
2006-10-08 12:18
2006.10.29
C C++


10-1124694868
OldNaum
2005-08-22 11:14
2006.10.29
COM-сервер


8-1143218448
mobila
2006-03-24 19:40
2006.10.29
ограничить перемещения квадрата


15-1160381309
Petr V. Abramov
2006-10-09 12:08
2006.10.29
Репозорий в BDS





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский