2010-08-17 5 views
16

यह आसान होना चाहिए, जब इंस्टॉलर शुरू होता है तो मुझे अपने प्रोग्राम के किसी भी पिछले संस्करण को चलाने से रोकना होगा।अद्यतन स्थापित करने से पहले प्रोग्राम का बंद संस्करण (इनो सेटअप)

अधिकांश लोगों ने exe बनाने का सुझाव दिया जो यह करता है और इनो सेटअप शुरू होने से पहले इसे कॉल करता है। मैंने ऑटोआईटी का उपयोग करके exe बनाया जो मेरे प्रोग्राम की सभी प्रक्रियाओं को मारता है। समस्या यह है कि मुझे नहीं पता कि इनो सेटअप को इसे इंस्टॉल करने से पहले इसे कॉल करने के लिए कैसे प्राप्त करें।

फ़ाइलों को स्थापित करने से पहले मैं निष्पादन योग्य कैसे कॉल करूं?

वैकल्पिक रूप से, अगर मैं सिर्फ यह पता लगा सकता हूं कि कोई प्रोग्राम चल रहा है और उपयोगकर्ता को इसे बंद करने के लिए कहें, तो यह भी काम करेगा।

उत्तर

28

यदि एप्लिकेशन में म्यूटेक्स है, तो आप अपने इनो सेटअप इंस्टॉलर में AppMutex मान जोड़ सकते हैं और यह उपयोगकर्ता को प्रोग्राम को रोकने के लिए कहने वाला एक संदेश प्रदर्शित करेगा। आप SysInternals प्रक्रिया एक्सप्लोरर का उपयोग करके और प्रोग्राम/प्रक्रिया का चयन करके और लोअर फलक में हैंडल (CTRL-H) को देखकर म्यूटेक्स (यदि यह एक है) प्राप्त करने में सक्षम हो सकता है। आप खुश हैं तो

[Setup] 
;If the application has Mutex, uncomment the line below, comment the InitializeSetup function out, and use the AppMutex. 
;AppMutex=MyApplicationMutex 

[Code] 
const 
    WM_CLOSE = 16; 

function InitializeSetup : Boolean; 
var winHwnd: Longint; 
    retVal : Boolean; 
    strProg: string; 
begin 
    Result := True; 
    try 
    //Either use FindWindowByClassName. ClassName can be found with Spy++ included with Visual C++. 
    strProg := 'Notepad'; 
    winHwnd := FindWindowByClassName(strProg); 
    //Or FindWindowByWindowName. If using by Name, the name must be exact and is case sensitive. 
    strProg := 'Untitled - Notepad'; 
    winHwnd := FindWindowByWindowName(strProg); 
    Log('winHwnd: ' + IntToStr(winHwnd)); 
    if winHwnd <> 0 then 
     Result := PostMessage(winHwnd,WM_CLOSE,0,0); 
    except 
    end; 
end; 
+0

धन्यवाद मिशेल, यह वही है जो मुझे चाहिए था। हर किसी ने उचित उत्तर प्रदान किए लेकिन यह सही समाधान साबित हुआ। – Daisetsu

+0

विंडोज 7 –

+0

पर काम नहीं करता है असल में, यह किसी भी चीज़ पर काम नहीं करता है। एक बार सही विंडो नाम का उपयोग करने के बाद, यह विंडोज 7 और अन्य ओएस पर काम करता है। मैंने FindWindowByWindowName का एक विकल्प भी जोड़ा जो FindWindowByClassName है। यदि आपके प्रोग्राम का विंडो नाम बदलता है तो FindWindowByClassName बेहतर विकल्प हो सकता है। – mirtheil

0

इनोसेटअप आपको निर्माण प्रक्रिया में विभिन्न स्थानों पर पास्कल स्क्रिप्ट संलग्न करने की अनुमति देता है। ShellExecute को कॉल करने वाली स्क्रिप्ट को जोड़ने का प्रयास करें। (जिसे आपको स्क्रिप्ट इंजन में आयात करना पड़ सकता है यदि उसके पास पहले से नहीं है।)

+0

स्क्रिप्ट इंजन में एक्सेक() है इसलिए यह समस्या नहीं है। मैं समझ नहीं पा रहा हूं कि बंडल एक्सई फ़ाइल निकालने और इसे चलाने के लिए पास्कल कोड कैसे लिखना है। – Daisetsu

4

यदि आप इनोसेटअप का उपयोग कर रहे हैं, तो आप अपने InnoSetup इंस्टॉलर को Windows SendBroadcastMessage करने के लिए देख सकते हैं, और अपना आवेदन प्राप्त कर सकते हैं उस संदेश को सुनने के लिए। जब आपका एप्लिकेशन संदेश प्राप्त करता है, तो उसे खुद को बंद करना चाहिए।

मैंने इसे स्वयं को इनोसेटअप इंस्टॉलर के साथ किया है, और यह बहुत अच्छी तरह से काम करता है।

+0

यह काम नहीं करेगा क्योंकि कार्यक्रम वर्षों से जारी किया गया है और मुझे पुराने संस्करणों को भी बंद करना होगा। – Daisetsu

0

ठीक है, मुझे लगता है कि ऐसा करने का आसान तरीका डेल्फी में एक डीएलएल बना सकता है जो यह पता लगाता है कि आपका प्रोग्राम चल रहा है या नहीं और उपयोगकर्ता को इसे बंद करने के लिए कहें, अपने डीएलएल को अपने सेटअप में रखें और ध्वज "डोंकोपी" का उपयोग करें (एक उदाहरण के लिए पास्कल स्क्रिप्टिंग \ DLLs का उपयोग करके http://www.jrsoftware.org/ishelp/ में जांचें)।

बीटीडब्ल्यू, अगली बार म्यूटेक्स का उपयोग करें, इनो सेटअप भी इसका समर्थन करता है और कहीं अधिक आसान है।

संपादित करें: और फ़ाइल निकालने के लिए (यदि आप इसका उपयोग करना चाहते हैं .exe जिसका आप उल्लेख करते हैं), बस ExtractTemporaryFile() का उपयोग करें।

1

:
http://www.vincenzo.net/isxkb/index.php?title=Detect_if_an_application_is_running

वैकल्पिक रूप से, आप InitializeSetup में इस (untested) कोड की कोशिश कर सकते:

यहाँ एक KB लेख के लिए एक लिंक है कि कई तरीकों का उल्लेख है अपना खुद का डीएलएल लिखें, आप यह निर्धारित करने के लिए कि कौन से एप्लिकेशन चल रहे हैं, TlHelp32.pas के लिए टूल हेल्प एपीआई का उपयोग कर सकते हैं, और फिर EnumWindows का उपयोग करके उनके लिए विंडो हैंडल प्राप्त करें, फिर विंडो हैंडल पर WM_CLOSE भेजें।

यह दर्द का थोड़ा सा है, लेकिन इसे काम करना चाहिए: मेरे पास कुछ उपयोगिता रैपर कक्षाएं हैं जिन्हें मैंने कुछ समय पहले एक दोस्त के साथ विकसित किया था। याद नहीं है अगर हम इसे किसी और के कोड पर आधारित करते हैं।

TWindows.ProcessISRunning और TWindows.StopProcess मदद कर सकता है।

interface 

uses 
    Classes, 
    Windows, 
    SysUtils, 
    Contnrs, 
    Messages; 

type 


TProcess = class(TObject) 
    public 
    ID: Cardinal; 
    Name: string; 
end; 

TWindow = class(TObject) 
    private 
    FProcessID: Cardinal; 
    FProcessName: string; 
    FHandle: THandle; 
    FProcessHandle : THandle; 
    function GetProcessHandle: THandle; 
    function GetProcessID: Cardinal; 
    function GetProcessName: string; 
    public 
    property Handle : THandle read FHandle; 
    property ProcessName : string read GetProcessName; 
    property ProcessID : Cardinal read GetProcessID; 
    property ProcessHandle : THandle read GetProcessHandle; 
end; 

TWindowList = class(TObjectList) 
    private 
    function GetWindow(AIndex: Integer): TWindow; 
    protected 

    public 
    function Add(AWindow: TWindow): Integer; reintroduce; 
    property Window[AIndex: Integer]: TWindow read GetWindow; default; 
end; 

TProcessList = class(TObjectList) 
    protected 
    function GetProcess(AIndex: Integer): TProcess; 
    public 
    function Add(AProcess: TProcess): Integer; reintroduce; 
    property Process[AIndex: Integer]: TProcess read GetProcess; default; 
end; 

TWindows = class(TObject) 
    protected 
    public 
    class function GetHWNDFromProcessID(ProcessID: Cardinal; BuildList: Boolean = True): THandle; 
    class function GetProcessList: TProcessList; 
    class procedure KillProcess(ProcessName: string); 
    class procedure StopProcess(ProcessName: string); 
    class function ExeIsRunning(ExeName: string): Boolean; 
    class function ProcessIsRunning(PID: Cardinal): Boolean; 
end; 

implementation 

uses 
    Forms, 
    Math, 
    PSAPI, 
    TlHelp32; 

const 
    cRSPUNREGISTERSERVICE = 0; 
    cRSPSIMPLESERVICE = 1; 

type 

TProcessToHWND = class(TObject) 
    public 
    ProcessID: Cardinal; 
    HWND: Cardinal; 
end; 

function RegisterServiceProcess(dwProcessID, dwType: DWord): DWord; stdcall; external 'KERNEL32.DLL'; 
function GetDiskFreeSpaceEx(lpDirectoryName: PChar; 
    var lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes: TLargeInteger; 
    lpTotalNumberOfFreeBytes: PLargeInteger): Boolean; stdcall;external 'KERNEL32.DLL' name 'GetDiskFreeSpaceExA' 

var 
    GProcessToHWNDList: TObjectList = nil; 

function EnumerateWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; 
var 
    proc: TProcessToHWND; 
begin 
    if Assigned(GProcessToHWNDList) then 
    begin 
    proc := TProcessToHWND.Create; 
    proc.HWND := hwnd; 
    GetWindowThreadProcessID(hwnd, proc.ProcessID); 
    GProcessToHWNDList.Add(proc); 
    Result := True; 
    end 
    else 
    Result := False; // stop enumeration 
end; 

{ TWindows } 

class function TWindows.ExeIsRunning(ExeName: string): Boolean; 
var 
    processList: TProcessList; 
    i: Integer; 
begin 
    Result := False; 

    processList := GetProcessList; 
    try 
    for i := 0 to processList.Count - 1 do 
    begin 
     if (UpperCase(ExeName) = UpperCase(processList[i].Name)) or 
      (UpperCase(ExeName) = UpperCase(ExtractFileName(processList[i].Name))) then 
     begin 
     Result := True; 
     Break; 
     end; 
    end; 
    finally 
    processList.Free; 
    end; 
end; 

class function TWindows.GetHWNDFromProcessID(
    ProcessID: Cardinal; BuildList: Boolean): THandle; 
var 
    i: Integer; 
begin 
    Result := 0; 

    if BuildList or (not Assigned(GProcessToHWNDList)) then 
    begin 
    GProcessToHWNDList.Free; 
    GProcessToHWNDList := TObjectList.Create; 
    EnumWindows(@EnumerateWindowsProc, 0); 
    end; 

    for i := 0 to GProcessToHWNDList.Count - 1 do 
    begin 
    if TProcessToHWND(GProcessToHWNDList[i]).ProcessID = ProcessID then 
    begin 
     Result := TProcessToHWND(GProcessToHWNDList[i]).HWND; 
     Break; 
    end; 
    end; 
end; 


class function TWindows.GetProcessList: TProcessList; 
var 
    handle: THandle; 
    pe: TProcessEntry32; 
    process: TProcess; 
begin 
    Result := TProcessList.Create; 

    handle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    pe.dwSize := Sizeof(pe); 
    if Process32First(handle, pe) then 
    begin 
    while True do 
    begin 
     process := TProcess.Create; 
     process.Name := pe.szExeFile; 
     process.ID := pe.th32ProcessID; 
     Result.Add(process); 
     if not Process32Next(handle, pe) then 
     Break; 
    end; 
    end; 
    CloseHandle(handle); 
end; 

function EnumWindowsProc(Ahwnd : HWND;  // handle to parent window 
    ALParam : Integer) : BOOL;stdcall; 
var 
    List : TWindowList; 
    Wnd : TWindow; 
begin 
    Result := True; 
    List := TWindowList(ALParam); 
    Wnd := TWindow.Create; 
    List.Add(Wnd); 
    Wnd.FHandle := Ahwnd; 
end; 


class procedure TWindows.KillProcess(ProcessName: string); 
var 
    handle: THandle; 
    pe: TProcessEntry32; 
begin 
    // Warning: will kill all process with ProcessName 
    // NB won't work on NT 4 as Tool Help API is not supported on NT 

    handle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    try 
    pe.dwSize := Sizeof(pe); 

    if Process32First(handle, pe) then 
    begin 
     while True do begin 
     if (UpperCase(ExtractFileName(pe.szExeFile)) = UpperCase(ExtractFileName(ProcessName))) or 
      (UpperCase(pe.szExeFile) = UpperCase(ProcessName)) then 
     begin 
      if not TerminateProcess(OpenProcess(PROCESS_TERMINATE, False, 
            pe.th32ProcessID), 0) then 
      begin 
      raise Exception.Create('Unable to stop process ' + ProcessName + ': Error Code ' + IntToStr(GetLastError)); 
      end; 
     end; 
     if not Process32Next(handle, pe) then 
      Break; 
     end; 
    end; 
    finally 
    CloseHandle(handle); 
    end; 
end; 

class function TWindows.ProcessIsRunning(PID: Cardinal): Boolean; 
var 
    processList: TProcessList; 
    i: Integer; 
begin 
    Result := False; 

    processList := GetProcessList; 
    try 
    for i := 0 to processList.Count - 1 do 
    begin 
     if processList[i].ID = PID then 
     begin 
     Result := True; 
     Break; 
     end; 
    end; 
    finally 
    processList.Free; 
    end; 
end; 

class procedure TWindows.StopProcess(ProcessName: string); 
var 
    processList: TProcessList; 
    i: Integer; 
    hwnd: THandle; 
begin 
    // Warning: will attempt to stop all process with ProcessName 
    if not Assigned(GProcessToHWNDList) then 
    GProcessToHWNDList := TObjectList.Create 
    else 
    GProcessToHWNDList.Clear; 

    // get list of all current processes 
    processList := GetProcessList; 
    // enumerate windows only once to determine the window handle for the processes 
    if EnumWindows(@EnumerateWindowsProc, 0) then 
    begin 
    for i := 0 to processList.Count - 1 do 
    begin 
     if UpperCase(ExtractFileName(processList[i].Name)) = UpperCase(ExtractFileName(ProcessName)) then 
     begin 
     hwnd := GetHWNDFromProcessID(processList[i].ID, False); 
     SendMessage(hwnd, WM_CLOSE, 0, 0); 
     end; 
    end; 
    end; 
end; 


{ TProcessList } 

function TProcessList.Add(AProcess: TProcess): Integer; 
begin 
    Result := inherited Add(AProcess); 
end; 

function TProcessList.GetProcess(AIndex: Integer): TProcess; 
begin 
    Result := TProcess(Items[AIndex]); 
end; 

{ TWindowList } 

function TWindowList.Add(AWindow: TWindow): Integer; 
begin 
    Result := inherited Add(AWindow); 
end; 

function TWindowList.GetWindow(AIndex: Integer): TWindow; 
begin 
    Result := TWindow(Items[AIndex]); 
end; 

{ TWindow } 

function TWindow.GetProcessHandle: THandle; 
begin 
    if FProcessHandle = 0 then 
    FProcessHandle := OpenProcess(Windows.SYNCHRONIZE or Windows.PROCESS_TERMINATE, 
    True, FProcessID); 
    Result := FProcessHandle; 
end; 

function TWindow.GetProcessID: Cardinal; 
var 
    Pid : Cardinal; 
begin 
    if FProcessID = 0 then 
    begin 
    Pid := 1; 
    GetWindowThreadProcessId(Handle, Pid); 
    FProcessID := Pid; 
    end; 
    Result := FProcessID; 
end; 


function TWindow.GetProcessName: string; 
var 
    Buffer : packed array [1..1024] of char; 
    len : LongWord; 
begin 
    FillChar(Buffer, SizeOf(Buffer), 0); 
    if FProcessName = '' then 
    begin 
    len := GetWindowModuleFileName(Handle, @Buffer[1], 1023); 
    FProcessName := Copy(Buffer, 1, Len); 
    end; 
    Result := FProcessName; 
end; 

end. 
+0

InnoSetup में संकलित करने में विफल, क्या कोई इसे ठीक कर सकता है? मैंने पहले कभी पास्कल का इस्तेमाल नहीं किया था। –

3

यहाँ एक Inno सेटअप स्क्रिप्ट है कि एक उपयोगकर्ता को संकेत देता लक्ष्य कार्यक्रम बंद करने के लिए, अगर यह पता लगाता है कि कार्यक्रम चल रहा है के लिए एक लिंक है। उपयोगकर्ता कार्यक्रम बंद कर देता है के बाद, वे एक "पुन: प्रयास करें" बटन पर क्लिक कर सकते हैं स्थापना के साथ आगे बढ़ने के लिए:

http://www.domador.net/extras/code-samples/inno-setup-close-a-program-before-reinstalling-it/

यह स्क्रिप्ट एक सरल स्क्रिप्ट, Inno सेटअप एक्सटेंशन ज्ञानकोष में पाया पर आधारित है:

http://www.vincenzo.net/isxkb/index.php?title=Call_psvince.dll_on_install_and_uninstall

13

(मई 2012 को जारी हुआ) संस्करण 5.5.0 Inno सेटअप में Windows Vista और नए पर Restart Manager एपीआई के लिए समर्थन जोड़ा गया।

MSDN से

उद्धरण जुड़ा हुआ प्रलेखन (जोर मेरा):

प्राथमिक कारण सॉफ्टवेयर स्थापना और अपडेट की आवश्यकता होती है एक प्रणाली को पुनः आरंभ है कि फ़ाइलों को अद्यतन किया जा रहा है वर्तमान में एक चल आवेदन के द्वारा प्रयोग किया जा रहा से कुछ या सर्विस। पुनरारंभ प्रबंधक सभी महत्वपूर्ण अनुप्रयोगों और सेवाओं को बंद करने और को पुनरारंभ करने के लिए सक्षम बनाता है। यह उन फ़ाइलों को मुक्त करता है जो उपयोग में हैं और इंस्टॉलेशन ऑपरेशंस को पूरा करने की अनुमति देते हैं। यह स्थापना या अद्यतन को पूरा करने के लिए आवश्यक सिस्टम पुनरारंभ की संख्या को भी समाप्त या कम कर सकता है।

अच्छी बात आप इसे बंद, या यह स्वचालित रूप से बंद करने के लिए उपयोगकर्ता पूछने के लिए संस्थापक या अपने आवेदन में कस्टम कोड लिखने के लिए की जरूरत नहीं है नहीं है।

यदि आप अपडेट पूरा होने के बाद अपने एप्लिकेशन को पुनरारंभ करना चाहते हैं, तो आपको पहले अपने आवेदन से RegisterApplicationRestart फ़ंक्शन को कॉल करना होगा।

नए निर्देशों के लिए डिफ़ॉल्ट मान इंस्टॉलर के [Files] अनुभाग में निहित सभी .exe, .dll और .chm फ़ाइलों को बंद कर देता है।

इसे से संबंधित परिवर्तन (रिलीज नोट्स से) कर रहे हैं:

  • जोड़ा नया [Setup] अनुभाग के निर्देश: CloseApplications, जो yes करने के लिए डिफ़ॉल्ट। यदि हाँ पर सेट किया गया है और सेटअप चुपचाप नहीं चल रहा है, तो सेटअप अब विज़ार्ड पेज को स्थापित करने की तैयारी पर रोक देगा यदि यह [Files] या [InstallDelete] अनुभाग द्वारा अपडेट किए जाने वाले फ़ाइलों का उपयोग करके अनुप्रयोगों का पता लगाता है, तो अनुप्रयोग दिखा रहा है और सेटअप को उपयोगकर्ता से पूछना चाहिए एप्लिकेशन को स्वचालित रूप से बंद करें और इंस्टॉलेशन पूरा होने के बाद उन्हें पुनरारंभ करें। यदि हाँ पर सेट किया गया है और सेटअप चुपचाप चल रहा है, तो सेटअप हमेशा इस तरह के अनुप्रयोगों को बंद और पुनरारंभ करेगा, जब तक कि कमांड लाइन के माध्यम से नहीं कहा जाता है (नीचे देखें)।
  • जोड़ा गया नया [Setup] अनुभाग निर्देश: CloseApplicationsFilter, जो *.exe,*.dll,*.chm पर डिफ़ॉल्ट है। नियंत्रित करता है कि सेटअप कौन सी फाइलें उपयोग में होने के लिए जांचेंगी। इसे *.* पर सेट करने से गति की कीमत पर बेहतर जांच मिल सकती है।
  • जोड़ा गया नया [Setup] अनुभाग निर्देश: RestartApplications, जो yes पर डिफ़ॉल्ट है। नोट: सेटअप पूर्ण होने के बाद सेटअप को पुनरारंभ करने में सक्षम होने के लिए, एप्लिकेशन को Windows RegisterApplicationRestart API फ़ंक्शन का उपयोग करने की आवश्यकता है।
  • सेटअप द्वारा समर्थित नए कमांड लाइन पैरामीटर जोड़ा गया: /NOCLOSEAPPLICATIONS और /NORESTARTAPPLICATIONS। इन्हें नए CloseApplications और RestartApplications निर्देशों को ओवरराइड करने के लिए उपयोग किया जा सकता है।
  • जोड़ा गया नया [Code] समर्थन फ़ंक्शन: RmSessionStarted
  • TWizardForm: नई PreparingMemo संपत्ति जोड़ा गया।
+2

महान जवाब, धन्यवाद! –

+0

'CloseAplplicationsFilter' कई अनुप्रयोगों के लिए महत्वपूर्ण है। फाइल प्रकारों को शामिल करने के लिए फ़िल्टर का विस्तार करें जो समस्याएं पैदा कर रहे हैं। – mafrosis

7

मैं स्वीकार किए जाते हैं जवाब (और jachguate द्वारा अनुवर्ती) अपने आवेदन लेकिन यह मार नहीं होगा उपयोग करने की कोशिश। ऐसा लगता है कि इस कारण का एक हिस्सा यह था कि मेरी एप्लिकेशन विंडो में इसके साथ कोई टेक्स्ट नहीं था, लेकिन असली कारण जो भी है, मैंने इसे मारने के लिए शेल कमांड का इस्तेमाल किया और यह काम किया। [कोड] अनुभाग में, आप निम्न फ़ंक्शन जोड़ना चाहते हैं। सेटअप फाइलों की प्रतिलिपि बनाने से ठीक पहले इसे कहा जाता है।

function PrepareToInstall(var NeedsRestart: Boolean): String; 
var 
ErrorCode: Integer; 
begin 
     ShellExec('open', 'taskkill.exe', '/f /im MyProg.exe','',SW_HIDE,ewNoWait,ErrorCode); 
end; 
1

मैं WMIC का उपयोग कर सफलता मिली है:

procedure CurStepChanged(CurStep: TSetupStep); 
var 
    ResultCode: Integer; 
    wmicommand: string; 
begin 
    // before installing any file 
    if CurStep = ssInstall then 
    begin 
     wmicommand := ExpandConstant('PROCESS WHERE "ExecutablePath like ''{app}\%%''" DELETE'); 

     // WMIC "like" expects escaped backslashes 
     StringChangeEx(wmicommand, '\', '\\', True); 

     // you can/should add an "if" around this and check the ResultCode 
     Exec('WMIC', wmicommand, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); 
    end; 
end; 

आप इसे InitializeSetup में भी कर सकते हैं, लेकिन अगर आप ऐसा करेंगे, {app} लगातार करने के लिए ध्यान रखें कि आप की जरूरत नहीं है अभी तक उपयोग में रहते हैं। मेरा प्रोग्राम इंस्टॉल पथ के लिए नहीं पूछता है, लेकिन आपका हो सकता है।

संबंधित मुद्दे