2016-11-07 9 views
2

私のプログラムはInno Setupを使用してそれをインストール/アンインストールします。私のアプリケーションコードでは、CreateMutex Windows API関数を使用してグローバル mutexを作成します。その後、私のInno Setupのプログラムの中で、私は次のコードを持っている:これは素晴らしい作品ログオンしているユーザーがインストール/アンインストールしようとしているアプリケーションを実行しているかどうかを確認します

AppMutex=Global\MyProgramMutex.2A23834B-2919-4007-8C0A-3C7EDCA7186E 

function InitializeSetup(): Boolean; 
begin 
    Result := True; 

    if (CreateMutex(0, False, '{#SetupSetting('AppId')}') <> 0) and (DLLGetLastError = ERROR_ALREADY_EXISTS) then 
    begin 
    Result := False; 
    MsgBox('Another instance of the Setup program is already running. Please close it and try again', mbCriticalError, MB_OK); 
    end; 

    if CheckForMutexes('{#SetupSetting('AppMutex')}') then 
    begin 
    Result := False; 
    MsgBox('{#SetupSetting('AppName')} ' + 'appears to be running. Please close all instances of the program before continuing.', mbCriticalError, MB_OK); 
    end; 
end; 

、予想通り、Inno Setupのプログラムを実行しているユーザーのために。私が持っている質問/問題は次のとおりです。「ユーザーの切り替え」を行い、別のユーザーとしてアプリケーションを起動して元のユーザーに戻すと、アプリケーションが別のユーザーで実行されていることが検出されません。

セットアッププログラムが実行中のアプリケーションを検出できるかどうかを知るには十分な知識がありません。 Inno SetupのKB Detect instances running in any user session with AppMutexで、文書化されたよう

+0

あなたはhttps://msdn.microsoft.com/en-us/library/system.threading.mutex.aspxごとなどのグローバル\接頭辞としているので、それがうまく動作するはずのように思えます。上のコードは、セットアップアセンブリまたはアプリケーションアセンブリからですか? – Botonomous

+0

AppMutexを動作させるためのコードを追加する必要はありません。アプリケーションのコードが疑わしいでしょう。 [こちらは](http://www.jrsoftware.org/iskb.php?mutexsessions)のkbエントリです。 [Here](http://stackoverflow.com/q/229565/243614)は、アプリケーション側についての質問です。 –

答えて

2

は、他のセッションで作成されたミューテックスを検出するために、2つのミューテックスを作成する必要があり、アプリケーション:Global\接頭辞1とせずに他の。

プレフィックスGlobal\を持つミューテックスには、任意のユーザーセッションからアクセスできます。セキュリティ制限やオペレーティングシステムサポートの欠如のためグローバルミューテックスの作成が失敗した場合にも、同じ名前のミューテックスをセッションネームスペースに作成する必要があります(Global\の接頭辞なし)。4.0 Terminal Server Edition以前のWindows NTグローバル\プレフィックスはサポートしていません)。

また、別のユーザーがmutexにアクセスできるようにするには、それぞれのCreateMutex()呼び出しで特別なセキュリティ記述子を渡す必要があります。

参照、C#ですべてのユーザーがミューテックスにアクセスできるようにするには:

const string mutexId = "MyProg"; 
MutexAccessRule allowEveryoneRule = 
    new MutexAccessRule(
     new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
     MutexRights.FullControl, AccessControlType.Allow); 
MutexSecurity securitySettings = new MutexSecurity(); 
securitySettings.AddAccessRule(allowEveryoneRule); 

Mutex globalMutex = null; 

try 
{ 
    bool createdNew; 
    globalMutex = new Mutex(false, "Global\\" + mutexId, out createdNew, securitySettings); 
} 
catch (UnauthorizedAccessException) 
{ 
    // Ignore 
} 

Mutex localMutex = new Mutex(false, mutexId); 

try 
{ 
    // Run your program here 
} 
finally 
{ 
    // These have to be called only after the application (its windows) closes. 
    // You can also remove these calls and let the system release the mutexes. 
    if (globalMutex != null) 
    { 
     globalMutex.Dispose(); 
    } 
    localMutex.Dispose(); 
} 

:合計で
What is a good pattern for using a Global Mutex in C#?

を、あなたのC#アプリケーションのコードは次のようにする必要がありますInno Setup側では、両方のmutexをリストすることが必要です。AppMutex directive

[Setup] 
AppMutex=MyProg,Global\MyProg 

CreateMutexCheckForMutexesコールは、InitializeSetup機能では必要ありません。

+0

Martin、「回答」機能を悪用したことをお詫び申し上げます。私は無知でそれをやった。だから、今朝私はすぐに私のアプリケーションコードであなたの提案をコーディングしました。 Inno Setupスクリプトでは、 "InitializeSetup"関数からmutexコードを削除し、[Setup]セクションでAppMutex設定を変更しました。アプリケーションをインストールして実行しました。私はインストーラを再実行しましたが、実行中のアプリケーションは検出されませんでした。それは、継続するために必要なファイルを使用していたプログラム(私のアプリ)があることを検出しました。私は何が欠けているのか分からないのですか?もう一度ありがとう... – RETierney

+0

あなたのプログラム全体はどこで実行されていますか、 'あなたのプログラムをここで実行する 'コメントはどこですか?単純なコンソールアプリケーションを作成し、その場所に 'Console.ReadLine'を置いて別のセッションでアプリケーションを実行すると、インストーラはそれを完全に検出します。 –

+0

はい。これは、あなたが指示したWPFアプリケーションです。私は 'code'を持っています。MainWindow mainWin = new MainWindow(); mainWin.Show(); 'code'男、私は困惑しています。 – RETierney

1

素晴らしいアイデア。ここでは、他のログインユーザーがWPFアプリケーションを実行中であっても、Inno Setupプログラムが検出するWPFのmutexオブジェクトを使用するための完全なソリューションがあります。 BTW。私はVisual Studioを使いました。

  1. は、WPFアプリとプロジェクトの両方が呼ばれているものとする「MyWPFApp」
  2. MyWPFAppのためのプロジェクトのプロパティを開きます。 [アプリケーション]タブで、スタートアップオブジェクトが 'MyWPFApp.App'であることを確認します。
  3. App.xamlのビルドアクションをApplicationDefinitionからPageに変更します。
  4. App.xamlからStartupUriプロパティを削除します(使用されている場合)。
  5. Application.Startupイベントが使用されている場合は、MainWindowをインスタンス化して表示するコードをすべて削除します。
  6. Appクラスの一部としてApp.xaml.csに次のコードまたは類似のコードを追加します。

    public partial class App : Application 
    { 
        private static readonly string _MutexID = "MyWPFApp"; // or whatever 
    
        [STAThread] 
        public static void Main() 
        { 
         var application = new App(); 
         application.InitializeComponent(); 
    
         MutexAccessRule allowEveryoneRule = new MutexAccessRule(
            new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
            MutexRights.FullControl, 
            AccessControlType.Allow); 
    
         MutexSecurity securitySettings = new MutexSecurity(); 
         securitySettings.AddAccessRule(allowEveryone); 
    
         Mutex globalMutex = null; 
    
         try 
         { 
          bool createdNew; 
          globalMutex = new Mutex(false, "Global\\" + _MutexID, out createdNew, securitySettings); 
         } 
         catch (UnauthorizedAccessException) 
         { 
          // ignore 
         } 
    
         Mutex localMutex = new Mutex(false, _MutexID); 
    
         try 
         { 
          MainWindow mainWin = new MainWindow(); 
          application.Run(mainWin); 
         } 
         finally 
         { 
          if (globalMutex != null) 
          { 
           globalMutex.Dispose(); 
          } 
    
          localMutex.Dispose(); 
         } 
        } 
    } 
    

最後のステップは、Inno Setupのスクリプトに以下の行を含めることです。

[Setup] 
AppMutex=MyWPFApp,Global\MyWPFApp 

私は両方のミューテックスのためのC#usingステートメントを使用して建築家にコードを試してみましたが、私は脳を持ってフリーズする。

また、Mainメソッドを含む別のクラスを作成し、そこに上記のコードを配置することもできます。これは上記の手順4と5を必要とし、手順2でStartupオブジェクトをMainメソッドを含む新しいクラスに変更します。

ありがとうございました。

ボブ

関連する問題