• Переменные среды
  • Как раскрыть строки с подстановками вида '%SystemRoot%\IOSUBSYS\'?
  • Изменение системного времени из Delphi II
  • Завершение работы Windows
  • Определение завершения работы Windows
  • Как консольное приложение может узнать, что Винды завершаются?
  • Как корректно перехватить сигнал выгрузки операционной системы, если в моей программе нет окна?
  • Постепенное умирание
  • Разное
  • Как не допустить запуск второй копии программы VIII
  • Как не допустить запуск второй копии программы IX
  • Как не допустить запуск второй копии программы X
  • Как не допустить запуск второй копии программы XI
  • Как не допустить запуск второй копии программы XII
  • Как правильно завершить некое приложение?
  • Как отчитывать промежутки времени с точностью, большей чем 60 мсек?
  • Как сделать чтобы при событиях моя программа отпpавляла кому-либо сообщение на мой компьютеp?
  • Что нужно давать WSAAsyncSelect в качестве параметра handle, если тот запускается и используется в dll (init), и никакой формы (у которой можно было бы взять этот handle) в этой dll не создается?
  • Вызов других программ
  • Получение списка запущеных приложений
  • Как мне запустить какую-нибудь программу? А как подождать, пока эта программа не отработает? Как выяснить, работает ли программа или уже завершилась? Как принудительно закрыть выполняющуюся программу?
  • Открытие выбранного файла в работающем приложении
  • Убиваем активное приложение
  • API

    Переменные среды

    Как раскрыть строки с подстановками вида '%SystemRoot%\IOSUBSYS\'?

    Nomadic советует:

    Используй вызов

    ExpandEnvironmentStrings(LPCTSTR lpSrc, LPTSTR lpDst, DWORD nSize);

    Изменение системного времени из Delphi II

    Delphi 1

    Можно. Попробуйте следующий код:

    Procedure settime(hour, min, sec, hundreths : byte); assembler;

    asm

     mov  ch, hour

     mov  cl, min

     mov  dh, sec

     mov  dl, hundreths

     mov  ah, $2d

     int  $21

    end;

    Procedure setdate(year : word; month, day : byte); assembler;

    asm

     mov  cx, year

     mov  dh, month

     mov  dl, day

     mov  ah, $2b

     int  $21

    end;

    Завершение работы Windows

    Определение завершения работы Windows

    НОМЕР ДОКУМЕНТА: TI3133

    ПРОДУКТ: Delphi

    Версия: 1.0

    ОС: Windows

    Дата: 1 октября, 1996

    Тема: Определение завершения работы Windows

    Существует ли возможность определения завершения работы Windows для нормального завершения работы работающего приложения Delphi?

    Самым простым решением является создание обработчика события главной формы OnCloseQuery. Данное событие возникает как результат сообщения WM_QUERYENDSESSION, которое посылается всем работающим приложениям Windows в момент инициализации процесса окончания работы Windows. Логическая переменная CanClose, передаваемая обработчику как var-параметр, может позволить программе (и Windows) завершить свою работу, если имеет значение True, значение же False не позволит программе завершить свою работу.

    Следующий код демонстрирует как можно воспользоваться данным событием.

    Демонстрационный код

    procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

    begin

     {Спрашиваем пользователя, если инициировано завершение работы.}

     if MessageDlg('Вы уверены?', mtConfirmation, mbYesNoCancel, 0) = mrYes then CanClose := true    {Разрешаем завершение работы.}

     else CanClose := false; {Не разрешаем завершение работы.}

    end;

    Как консольное приложение может узнать, что Винды завершаются?

    Nomadic рекомендует следующий код:

    Все процессы получают сигналы CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT. А делается это (грубо говоря :) так:

    BOOL Ctrl_Handler(DWORD Ctrl) {

     if ((Ctrl == CTRL_SHUTDOWN_EVENT) || (Ctrl == CTRL_LOGOFF_EVENT)) {

      // Вау! Юзер обламывает!

     } else {

      // Тут что-от другое можно творить. А можно и не творить :-)

     }

     return TRUE;

    }


    function Ctrl_Handler(Ctrl: Longint): LongBool;

    begin

     if Ctrl in [CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT] then begin

    // Вау, вау

     end

     else begin

    // Am I creator?

     end;

     Result := true;

    end;

    А где-то в программе:

    SetConsoleCtrlHandler(Ctrl_Handler, TRUE);

    Таких обработчиков можно навесить кучу. Если при обработке какого-то из сообщений обработчик возвращает FALSE, то вызывается следующий обработчик. Можно настроить таких этажерок, что ого-го :-)))

    Короче, смотри описание SetConsoleCtrlHandler — там всё есть.

    Как корректно перехватить сигнал выгрузки операционной системы, если в моей программе нет окна?

    Nomadic рекомендует следующий способ:

    Используй GetMessage(), в качестве HWND окна пиши NULL (на Паскале — 0). Если в очереди сообщений следующее — WM_QUIT, то эта функция фозвращает FALSE. Если ты пишешь программу для Win32, то запихни это в отдельный поток, организующий выход из программы.

    Постепенное умирание

    The_Sprite пишет:

    Вопрос: А как реализовать в одном компоненте такие функции как выключение компьютера, перезагрузка, завершение сеанса работы пользователя, Eject CD, выключение питания монитора и т.д.? Ответ: предлагаем посмотреть следующий пример…

    Совместимость: все версии Delphi

    Пример:

    procedure TForm1.Button1Click(Sender: TObject);

    begin

     PowerControl1.Action:=actCDEject;// Или...

     actLogOFF, actShutDown...

     PowerControl1.Execute;

    end

    Component Code:

    unit

     PowerControl;

    interface


    uses WinTypes, WinProcs, Messages, SysUtils, Classes, Controls,Forms, Graphics,MMSystem;

    type

    TAction =(actLogOFF,actShutDown,actReBoot,actForce,actPowerOFF,

     actForceIfHung,actMonitorOFF,actMonitorON,actCDEject,actCDUnEject);


    type TPowerControl = class(TComponent)

    private

     FAction : TAction;

     procedure SetAction(Value : TAction); protected

    public

     function Execute :Boolean;

    published

     property Action :TAction read FAction write SetAction;

    end;


    procedure Register;


    implementation


    procedure Register;

    begin

     RegisterComponents('K2',[TPowerControl]);

    end;


    procedure TPowerControl.SetAction(Value : TAction);

    begin

     FAction := Value;

    end;


    function TPowerControl.Execute : Boolean;

    begin

     with (Owner as TForm) do case FAction of

      actLogOff: ExitWindowsEx(EWX_LOGOFF, 1);

      actShutDown: ExitWindowsEx(EWX_SHUTDOWN, 1);

      actReBoot:ExitWindowsEx(EWX_REBOOT, 1);

      actForce:ExitWindowsEx(EWX_FORCE, 1);

      actPowerOff:ExitWindowsEx(EWX_POWEROFF, 1);

      actForceIfHung:ExitWindowsEx(EWX_FORCEIFHUNG, 1);

      actMonitorOFF:SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, 0);

      actMonitorON: SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1);

      actCDEject: mciSendstring('SET CDAUDIO DOOR OPEN WAIT', nil, 0, Handle);

      actCDUnEject: mciSendstring('SET CDAUDIO DOOR CLOSED WAIT', nil, 0, Handle);

     end; {Case}

     Result := True;

    end;


    end.

    Разное

    Как не допустить запуск второй копии программы VIII

    Игорь Пролис рекомендует следующий код:

    {*******************************************************}

    {                                                       }

    {                     HTMLCoolEdit                      }

    {                                                       }

    {           Copyright (c) 1999-2000 PROFOX              }

    {                                                       }

    {*******************************************************}

    unit multinst;


    interface


    uses Forms, Windows, Dialogs, SysUtils;


    const

     MI_NO_ERROR = 0;

     MI_FAIL_SUBCLASS = 1;

     MI_FAIL_CREATE_MUTEX = 2;


    function GetMIError: Integer;

    function InitInstance : Boolean;


    implementation


    uses RegWork, FileWork;


    var

     UniqueAppStr : PChar;

     MessageId: Integer;

     WProc: TFNWndProc = Nil;

     MutHandle: THandle = 0;

     MIError: Integer = 0;


    function GetMIError: Integer;

    begin

     Result := MIError;

    end;


    function NewWndProc(Handle: HWND; Msg: Integer; wParam, lParam: Longint): Longint; StdCall;

    begin

     Result := 1;

     if Msg = MessageID then begin

      if IsIconic(Application.Handle) then OpenIcon(Application.Handle)

      else SetForegroundWindow(Application.Handle);

      FileWork.LoadFileName(RegWork.RWGetParamStr1);

     end

     else Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);

    end;


    procedure SubClassApplication;

    begin

     WProc := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(@NewWndProc)));

     if WProc = Nil then MIError := MIError or MI_FAIL_SUBCLASS;

    end;


    procedure DoFirstInstance;

    begin

     SubClassApplication;

     MutHandle := CreateMutex(Nil, False, UniqueAppStr);

     if MutHandle = 0 then MIError := MIError or MI_FAIL_CREATE_MUTEX;

    end;


    procedure BroadcastFocusMessage;

    begin

     Application.ShowMainForm := False;

     PostMessage(HWND_BROADCAST, MessageId, 0, 0);

    end;


    function InitInstance : Boolean;

    begin

     MutHandle := OpenMutex(MUTEX_ALL_ACCESS, False, UniqueAppStr);

     if MutHandle = 0 then begin

    ShowWindow(Application.Handle, SW_ShowNormal);

      Application.ShowMainForm:=True;

      DoFirstInstance;

      result := True;

     end

     else begin

      RegWork.RWSetParamStr1;

      BroadcastFocusMessage;

      result := False;

     end;

    end;


    initialization

    begin

     UniqueAppStr := PChar(Application.ExeName);

     MessageID := RegisterWindowMessage(UniqueAppStr);

     ShowWindow(Application.Handle, SW_Hide);

     Application.ShowMainForm:=FALSE;

    end;


    finalization

    begin

     if WProc <> Nil then SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(WProc));

    end;


    end.

    Как не допустить запуск второй копии программы IX

    YoungHacker рекомендует следующий код:

    Был взят из кулибы и доработан, поскольку возникали ситуации когда программа, по HotKey назначенным на ярлык, запускалась дважды и более раз. Связано с тем что поиск мутекса и его создание разнесены во времени и пока в одном приложении мутекс не нашелся но еще не создался второе приложение тоже не находит мутекса и инициирует его создание

    Поиск окон и создание их нарываются на те-же проблемы. Из RxLib Функция тоже не обходит этой ситуации.

    Мой вариант немного дорабатывает уже значительно переработанное то что предоставили разработчики Delphi 2 Пачека (Pacheco) и Тайхайра (Teixeira). и находится в файле TPrevInstUnit. В файле проекта пишется следующий вызов:

    begin

     //– Найти предыдущую версию программы

     if (initinstance) then begin

      …

      Application.Initialize;

      …

      Application.CreateForm();

      …

      Application.Run;

     end;

    end.

    Файл TPrevInstUnit

    unit TPrevInstUnit;


    interface


    uses Forms, Windows, Dialogs, SysUtils;


    function InitInstance : Boolean;


    implementation


    const

     UniqueAppStr : PChar = #0; // Различное для каждого приложения

                                // Но одинаковое для каждой копии программы

    var

     MessageId : Integer;

     OldWProc : TFNWndProc = Nil;

     MutHandle : THandle = 0;

     SecondExecution : Boolean = False;


    function NewWndProc(Handle: HWND; Msg: Integer; wParam, lParam: Longint): Longint; StdCall;

    begin

     //- Если это - сообщение о регистрации... }

     if (Msg = MessageID) then begin

    //- если основная форма минимизирована

      if IsIconic(Application.Handle) then begin

    //- восстанавливаем

       ееApplication.Restore;

      end

      else begin

    //- вытаскиваем на перед

       ShowWindow(Application.Handle, SW_SHOW);

       SetForegroundWindow(Application.Handle);

       Application.BringToFront;

      end;

      Result := 0;

     end

     else

    { В противном случае посылаем сообщение предыдущему окну }

      Result := CallWindowProc(OldWProc, Handle, Msg, wParam, lParam);

    end;


    function InitInstance : Boolean;

    var

     BSMRecipients: DWORD;

    begin

     Result := False;

     //- пробуем открыть MUTEX созданный предыдущей копией программы

     MutHandle := CreateMutex(Nil, True, UniqueAppStr);

     //- Мутекс уже был создан ?

     SecondExecution := (GetLastError = ERROR_ALREADY_EXISTS);

     if (MutHandle = 0) then begin

    ShowMessage('Ошибка создания Mutex.');

      Exit;

     end;

     if Not (SecondExecution) then begin

    //- назначаем новый обработчик сообщений приложения, а старый сохраняем

      OldWProc := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(@NewWndProc)));

      //- если обработчик не найден устанавливаем ошибку

      if (OldWProc = Nil) then begin

    ShowMessage('Ошибка поиска стандартного обработчика сообщений приложения.');

       Exit;

      end;

      //- Установить "нормальный" статус основного окна приложения

      ShowWindow(Application.Handle, SW_ShowNormal);

      //- покажем основную форму приложения

      Application.ShowMainForm := True;

      //- все нормально мама трын тин тин тин тири тын тын

      Result := True;

     end

     else begin

    //- установить статус окна приложения "невидимый"

      ShowWindow(Application.Handle, SW_Hide);

      //- Не покажем основную форму приложения

      Application.ShowMainForm := False;

      //- Посылаем другому приложению сообщение и информируем о необходимости

      // перевести фокус на себя

      BSMRecipients := BSM_APPLICATIONS;

      BroadCastSystemMessage(BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE, @BSMRecipients, MessageID, 0, 0);

     end;

    end;


    initialization

    begin

     //- Создать ункальную строку для опознания приложения

     UniqueAppStr := PChar('YoungHackerNetworkDataBaseProgramm');

     //- Зарегистрировать в системе уникальное сообщение

     MessageID := RegisterWindowMessage(UniqueAppStr);

    end;


    finalization

    begin

     if (OldWProc <> Nil) then

    { Приводим приложение в исходное состояние }

      SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(OldWProc));

     end;


    end.

    Как не допустить запуск второй копии программы X

    Nomadic рекомендует следующий код:

    FindWindow является неполным решением (если меняется заголовок окна или если есть другая программа с таким же заголовком или типом окна).

    Вторично: Это работает медленно.

    Правильно — использовать обьекты синхронизации Win32 API.

    Лениво пользовать семафоры, покажу на именованных мутексах (семафоры с двумя состояниями).

    Unit OneInstance32;


    interface


    implementation


    uses

     Forms;


    var

     g_hAppMutex: THandle;


    function OneInstance: boolean;

    var

     g_hAppCritSecMutex: THandle;

     dw: Longint;

    begin

     g_hAppCritSecMutex := CreateMutex(nil, true, PChar(Application.Title + '.OneInstance32.CriticalSection'));

     // if GetLastError - лениво писать

     g_hAppMutex := CreateMutex(nil, false, PChar(Application.Title + 'OneInstance32.Default'));

     dw := WaitForSingleObject(g_hAppMutex, 0);

     Result := (dw <> WAIT_TIMEOUT);

     ReleaseMutex(g_hAppCritSecMutex); // необязательно вследствие последующего закрытия

     CloseHandle(g_hAppCritSecMutex);

    end;


    initialization

     g_hAppMutex := 0;


    finalization

     if LongBool(g_hAppMutex)  then begin

      ReleaseMutex(g_hAppMutex); // необязательно

      CloseHandle(g_hAppMutex);

     end;


    end.

    Как не допустить запуск второй копии программы XI

    Михаил Чумак рекомендует следующий код:

    Есть такая штука Atom (см. Help).

    program SelfCheck;


    uses

     Windows,Forms,Unit1 in 'Unit1.pas' {Form1};


    const

     AtStr='MyProgram';


    function CheckThis : boolean;

    var

     Atom: THandle;

    begin

     Atom:= GlobalFindAtom(AtStr);

     Result:= Atom <> 0;

     if not result then GlobalAddAtom(AtStr);

    end;


    begin

     if not CheckThis then begin

     // Запуск программмы

      Application.Initialize;

      Application.CreateForm(TForm1, Form1);

      Application.Run;

      GlobalDeleteAtom(GlobalFindAtom(AtStr));

      // !!!

     end

     else begin

    MessageBox(0,'Нельзя запустить две копии','Моя программа',0);

     end;

    end.

    Элегантно и работает однозначно. Спасибо Славе Шубину.

    Как не допустить запуск второй копии программы XII

    Nomadic рекомендует следующее:

    A: Воспользуйтесь функцией ActivatePrevInstance из библиотеки rxLib. Для завершения второго экземпляра используйте Application.Terminate.

    (AS): Другой вариант: X:\DELPHI2\DEMOS\IPCDEMOS\ipcthrd.pas, функция IsMonitorRunning().

    Как правильно завершить некое приложение?

    Nomadic рекомендует следующий код:

    Если не принудительно, то можно послать на его Instance сообщение WM_QUIT. Если же необходимо принудительно терминировать приложение, то смотрите ниже — под Windows NT процесс можно терминировать через специально предназначенный для этого хэндл. Иначе гарантии нет. Предположим, что процесс создаем мы, ожидая его завершения в течение maxworktime. Тогда —

    var

     dwResult: Longint; // This example was converted from C source.

    begin

    // Not tested. Some 'nil' assignments must be applied

     // as zero assignments in Pascal. Some vars need to

     // be declared (maxworktime, si, pi). AA.

     if CreateProcess(nil, CmdStr, nil, nil, FALSE,CREATE_NEW_CONSOLE, nil, nil, si, pi) then begin

      CloseHandle(pi.hThread);

      dwResult := WaitForSingleObject(pi.hProcess, maxworktime*1000*60);

      CloseHandle(pi.hProcess);

      if dwResult <> WAIT_OBJECT_0 then begin

       pi.hProcess := OpenProcess(PROCESS_TERMINATE, FALSE, pi.dwProcessId);

       if pi.hProcess <> nil then begin

         TerminateProcess(pi.hProcess, 0);

         CloseHandle(pi.hProcess);

       end;

      end;

     end;

    end;

    Как отчитывать промежутки времени с точностью, большей чем 60 мсек?

    Nomadic рекомендует следующий код:

    Для начала описываешь процедуру, которая будет вызываться по сообщению от таймера :

    procedure FNTimeCallBack(uTimerID, uMessage: UINT;dwUser, dw1, dw2: DWORD); stdcall;

    begin

     //// Тело процедуры.

    end;

    а дальше в программе (например по нажатию кнопки) создаешь Таймер и вешаешь на него созданную процедуру

     uTimerID:=timeSetEvent(10, 500, @FNTimeCallBack, 100, TIME_PERIODIC);

    Подробности смотри в Help. Hу и в конце убиваешь таймер

    timeKillEvent(uTimerID);

    И все. Точность этого способа до 1 мсек. минимальный интервал времени можно задавать 1 мсек.

    Обратите внимание на то, что все CALLBACK-функции, вызываемые Windows, должны использовать соглашение о вызовах stdcall.

    Как сделать чтобы при событиях моя программа отпpавляла кому-либо сообщение на мой компьютеp?

    Nomadic рекомендует следующий код:

    Если только послать, то проще всего, пожалуй…

    W32: F1 «NetMessageBufferSend»;

    Win16: Почему-то не описан, но руками наковырял…

    function NetMessageBufferSend(Zero1, Zero2: Word; WhoTo: PChar; Buffer: PChar; BufSize: Word): Integer; external 'netapi' index 525;

    «Кому» может быть '*' == всем.

    Что нужно давать WSAAsyncSelect в качестве параметра handle, если тот запускается и используется в dll (init), и никакой формы (у которой можно было бы взять этот handle) в этой dll не создается?

    Nomadic рекомендует следующий код:

    const WM_ASYNCSELECT = WM_USER+0;

    type TNetConnectionsManager = class(tobject)

    protected

     FWndHandle : HWND;

    procedure WndProc(var MsgRec : TMessage);

     …

    end;


    constructor TNetConnectionsManager.Create

    begin

     inherited Create;

     FWndHandle := AllocateHWnd(WndProc);

     …

    end;


    destructor TNetConnectionsManager.Destroy;

    begin

     …

     if FWndHandle<>0 then DeallocateHWnd(FWndHandle);

     inherited Destroy;

    end;


    procedure TNetConnectionsManeger.WndProc(var MsgRec : TMessage);

    begin

     with MsgRec do

      if Msg = WM_ASYNCSELECT then WMAsyncSelect(MsgRec)

      else DefWindowProc(FWndHandle, Msg, wParam, lParam);

    end;

    Hо pекомендую посмотpеть WinSock2, в котоpом можно:

    WSAEventSelect(FSocket, FEventHandle, FD_READ or fd_close);

    WSAWaitForMultipleEvents();

    WSAEnumNetworkEvents(FSocket, FEventHandle, lpNetWorkEvents);

    То есть, обойтись без окон и без очеpеди сообщений windows, а заодно иметь возможность pаботать и с IPX/SPX, и с netbios.

    Вызов других программ

    VRSLazy@mail.ru пишет:

    Доброго времени суток,

    Вот посмотрел Ваше произведение Советы по делфи, мне очень понравилось :-)

    Правда в вопросе/решении запустить другую программу просто обалдел :-( Я как то долго мучился с этим самым ShellExecute пока не пришёл к следующему:

    uses …ToolWin, Windows …


    procedure Run(App: String);

    var

     ErrStr : String;

     PMSI: TStartupInfo;

    PMPI: TProcessInformation;

    begin

     try

      CreateProcess(nil, @App[1] , nil, nil, False, NORMAL_PRIORITY_CLASS, nil, nil, PMSI, PMPI);

     except

     ErrStr := 'Fault run process: '''+App+'''';

     Application.MessageBox(@ErrStr[1],'Failure process', MB_OK+MB_ICONERROR);

    end;

    разумеется это одно из самых корявых решений, но всё же работает, как вариант сойдет?

    Получение списка запущеных приложений

    Igor Nikolaev aKa The Sprite предлагает следующий код:

    procedure TForm1.Button1Click(Sender: TObject);

    VAR

     Wnd : hWnd;

     buff: ARRAY [0..127] OF Char;

    begin

     ListBox1.Clear;

     Wnd := GetWindow(Handle, gw_HWndFirst);

     WHILE Wnd <> 0 DO BEGIN {Hе показываем:}

      IF (Wnd <> Application.Handle) AND {-Собственное окно}

       IsWindowVisible(Wnd) AND {-Hевидимые окна}

       (GetWindow(Wnd, gw_Owner) = 0) AND {-Дочернии окна}

       (GetWindowText(Wnd, buff, sizeof(buff)) <> 0)

       THEN BEGIN

       GetWindowText(Wnd, buff, sizeof(buff));

       ListBox1.Items.Add(StrPas(buff));

      END;

      Wnd := GetWindow(Wnd, gw_hWndNext);

     END;

     ListBox1.ItemIndex := 0;

    end;

    Как мне запустить какую-нибудь программу? А как подождать, пока эта программа не отработает? Как выяснить, работает ли программа или уже завершилась? Как принудительно закрыть выполняющуюся программу?

    Nomadic рекомендует следующее:

    A: WinExec() или ShellExecute. У второй больше возможностей.

    (SO): CreateProcess() в параметре process info возвращает handle запущенного процесса. Вот и делаешь WaitForSingleObject(pi.hProcess, INFINITE);

    (AA): (Win16) Delay можно взять из rxLib.

    handle := WinExec();

    if handle >= 32 then

    while GetModuleUsage(handle) > 0 do Delay(nn);

    else raise …

    (AM): Чтобы выяснить, работает ли программа, используйте GetProcessTimes(), параметр lpExitTime.

    (Win32) Для принудительного завершения процесса — TerminateProcess.

    (Win16) (RR): Надо послать программе сообщение WM_QUIT:

    Handle := Winexec(App, 0);

    PostMessage(Handle, WM_QUIT, 0, 0);

    Открытие выбранного файла в работающем приложении

    Пангин Дмитрий Викторович прислал письмо следующего содержания:

    При программировании MDI-приложений возникает следующая задача: Если пользователь кликнул на файле, тип которого поддерживается создаваемым приложением, то, если приложение уже запущено, не нужно запускать новую копию приложения, а нужно открыть выбранный файл в уже работающем приложении. Я сделал это так (возможно есть более красивое решение):

    \\ В файле проекта:

    var

     i: integer;

     hMainForm:hwnd;

     copyDataStruct:TCopyDataStruct;

     ParamString:string;

     WParam,LParam:integer;

    begin

     \\ ищем главное окно приложения, вместо Caption - nil,

     \\ поскольку к заголовку главного окна может добавиться заголовок MDIChild

     \\ (нужно позаботиться об уникальности имени класса главной формы)

     hMainForm:= FindWindow('TMainForm', nil);

     if  hMainForm = 0 then begin

    Application.Initialize;

      Application.CreateForm(TFrmMain, frmMain);

      for i:=1 to ParamCount do TMainForm(Application.MainForm).OpenFile(ParamStr(i));

      Application.Run;

     end

     else begin

    ParamString:='';

      for i:=1 to ParamCount do begin

       \\ запихиваем все параметры в одну строку с разделителями ?13

       ParamString:=ParamString+ParamStr(i)+ #13;

      end;

      \\ создаем запись типа TCopyDataStruct

      CopyDataStruct.lpData:=PChar(ParamString);

      CopyDataStruct.cbData:=Length(ParamString);

      CopyDataStruct.dwData:=0;

      WParam:=Application.Handle;

      LParam:=Integer(@CopyDataStruct);

      \\ отсылаем сообщение WM_COPYDATA главному окну открытого приложения

      SendMessage(hMainForm,WM_CopyData,WParam,LParam);

      Application.Terminate;

     end;

    end.


    \\ Обработчик сообщения WM_COPYDATA

    procedure TMainForm.CopyData(var Msg: TWMCopyData);

    var

     ParamStr:string;

     CopyDataStructure:TCopyDataStruct;

     i:integer;

     len:integer;

    begin

     CopyDataStructure:= Msg.CopyDataStruct^;

     ParamStr:='';

     len:=  CopyDataStructure.cbData;

     for i:=0 to len-1 do begin

    ParamStr:=ParamStr+(PChar(CopyDataStructure.lpData)+i)^;

     end;

     i:=0;

     while not(Length(ParamStr)=0) do begin

      if isDelimiter(#13,ParamStr,i) then begin

    OpenFile(Copy(ParamStr,0,i-1));

       ParamStr:=Copy(ParamStr,i+1,Length(ParamStr)-i-1);

      end;

      inc(i);

     end;

     inherited;

    end;

    Убиваем активное приложение

    The_Sprite прислал письмо следующего содержания:

    Данная функция позволяет завершить выполнение любой активной программы по её classname или заголовку окна.

    Совместимость: Все версии Delphi

    Исходный код функции

    procedure KillProgram(Classname : string; WindowTitle : string);

    const

     PROCESS_TERMINATE = $0001;

    var

     ProcessHandle : THandle;

     ProcessID: Integer;

     TheWindow : HWND;

    begin

     TheWindow := FindWindow(Classname, WindowTitle);

     GetWindowThreadProcessID(TheWindow, @ProcessID);

     ProcessHandle := OpenProcess(PROCESS_TERMINATE, FALSE, ProcessId);

     TerminateProcess(ProcessHandle, 4);

    end;

    Комментарии

    Xianguang Li=(22 Октября 2000) В Delphi 5, при компиляции получается следующая ошибка:

    Incompatible types: 'String' and 'PChar'.

    После изменения выражения

    TheWindow := FindWindow(ClassName, WindowTitle)

    на

    TheWindow := FindWindow(PChar(ClassName), PChar(WindowTitle))

    Нормально откомпилировалось.

    И ещё: если мы не знаем ClassName или WindowTitle программы, которую мы хотим убить, то мы не сможем её завершить. Причина в том, что нельзя вызвать функцию в виде:

    KillProgram(nil, WindowTitle)

    или

    KillProgram(ClassName, nil)

    Компилятор не позволяет передать nil в переменную типа String.

    Итак, я изменил объявление

    KillProgram(ClassName: string; WindowTitle: string)

    на

    KillProgram(ClassName: PChar; WindowTitle: PChar),

    вот теперь функция действительно может завершить любое приложение, если вы не знаете ClassName или WindowTitle этого приложения.








    Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Наверх