• ベストアンサー

タイトルバーのないアプリに二重起動防止機能を付けたい

今、タイトルバーのないアプリを作っているのですが、このアプリのウインドウを別アプリから、APIのFindWindow関数で見つけたいのですが、タイトルがないのでクラス名でしか見つけれません。同じクラスのウインドウが他にもあった場合、区別が付かず困っています。 具体的に申しますと、作ったアプリに二重起動防止機能を付けたい(すでに起動されている場合はそのアプリのウインドウを元の大きさに戻してアクティブにする)のですが、そのアプリにはタイトルバーがなく、FindWindowでは見つけれない場合があります。 このような場合どうすればいいでしょうか? よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.6

 VB6.0で2重起動のチェック&2重起動時に起動中のウィンドウを 手前に持ってくるサンプルです。 Sub Main() Dim lngReturnValue As Long Dim strMyTitle As String Dim lngPrevHwnd As Long Dim lngTopHwnd As Long Dim lngThreadID1 As Long Dim lngThreadID2 As Long ' 2重起動の場合は、手前に持ってきて自分自身は終了する strMyTitle = App.Title App.Title = "$" & App.Title lngPrevHwnd = FindWindow("ThunderRT6Main", strMyTitle) If lngPrevHwnd <> 0 Then lngTopHwnd = GetLastActivePopup(lngPrevHwnd) If IsIconic(lngTopHwnd) = WIN32API_TRUE Then lngReturnValue = ShowWindow(lngTopHwnd, SW_NORMAL) End If lngThreadID1 = GetWindowThreadProcessId(GetForegroundWindow(), ByVal 0&) lngThreadID2 = GetCurrentThreadId() lngReturnValue = AttachThreadInput(lngThreadID2, lngThreadID1, 1) lngReturnValue = SetForegroundWindow(lngTopHwnd) lngReturnValue = AttachThreadInput(lngThreadID2, lngThreadID1, 0) Exit Sub End If App.Title = strMyTitle Form1.Show End Sub  APIの定義です。 Public Const WIN32API_TRUE As Long = 1 Public Const WIN32API_FALSE As Long = 0 Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Declare Function GetLastActivePopup Lib "user32" _ (ByVal hwndOwnder As Long) As Long Public Declare Function IsIconic Lib "user32" _ (ByVal hwnd As Long) As Long Public Declare Function ShowWindow Lib "user32" _ (ByVal hwnd As Long, _ ByVal nCmdShow As Long) As Long Public Const SW_NORMAL = 1 Public Const SW_MAXIMIZE = 3 Public Const SW_MINIMIZE = 6 Public Declare Function GetForegroundWindow Lib "user32" () As Long Public Declare Function SetForegroundWindow Lib "user32" _ (ByVal hwnd As Long) As Long Public Declare Function GetWindowThreadProcessId Lib "user32" _ (ByVal hwnd As Long, _ lpdwProcessId As Long) As Long Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long Public Declare Function AttachThreadInput Lib "user32" _ (ByVal idAttach As Long, _ ByVal idAttachTo As Long, _ ByVal fAttach As Long) As Long  VB5.0の場合は、ThunderRT6Main が ThunderRT5Main だと思います。  これは、VBのEXEで実行時にクラス名が ThunderRT6Main で キャプションがプロジェクトのプロパティの実行ファイルの作成タブの アプリケーションのタイトル(=App.Title=タスクマネージャのタスク に表示されるタスク名)のウィンドウが必ず存在するので このウィンドウをチェックしています。(このウィンドウは、サイズが 0なので見えません。) また、開発環境(IDE)で動かすとこのウィンドウは存在しないので EXEファイルにして実行して確認してください。

noname#208339
質問者

お礼

うぉ~~、 すごい~!! ありがとうございます。 ThunderRT5Mainに書き換えたら動きました。 > これは、VBのEXEで実行時にクラス名が ThunderRT6Main で > キャプションがプロジェクトのプロパティの実行ファイルの作成タブの > アプリケーションのタイトル(=App.Title=タスクマネージャのタスク > に表示されるタスク名)のウィンドウが必ず存在するので そのようなウインドウが存在するとは知りませんでした!! App.Titleを実行中に変更できるなんて思いもしませんでした。 おかげさまでシンプルなコードになりました。 どうもありがとうございました。 尚、ここで解決とさせて頂きます。 いろいろとごご教授くださった皆様、 どうもありがとうございました。

その他の回答 (5)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

フォームの外枠を可変にしたいのでしょうか? そうなると ControlBoxとCaptionで操作することになりますね 固定でよいのなら BorderStyleを 0の無しに設定してみてはいかがでしょう これなら Captionは設定してあっても タイトルバーは表示されませんよ

noname#208339
質問者

お礼

どうもありがとうございます。 > BorderStyleを 0の無しに設定してみてはいかがでしょう そうすると今度はタスクバーにも表示されなくなってしまうので・・・;; noocyteさんが教えてくださったMutexを使ったやり方はむずかしかったので、ダミーのコマンドボタンを貼り付けるやり方で実現しました。 いろいろとありがとうございました。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.4

>>SendMessageでCaptionを取得してみましょう >タイトルバーがないのでCaptionもなく・・・;; タイトルバーがなくても 作成したアプリケーションのフォームのCaptionプロパティが設定されているのであれば WM_GETTEXTで取得できる場合がありますよ 先の投稿も一応検証してから アップしております VB6ですけどね ...

noname#208339
質問者

お礼

何度も、ありがとうございます。 > タイトルバーがなくても 作成したアプリケーションのフォームのCaptionプロパティが設定されているのであればWM_GETTEXTで取得できる場合がありますよ VB5でフォームのCaptionプロパティを設定するとタイトルバーがなくならないです。(私のやり方が悪いのかも。) フォームのControlBox プロパティを False にして、Caption プロパティを "" (プロパティウインドウになにも文字列を入力しない)にすることでタイトルバーが消えてくれますが、逆に Caption プロパティを""にしてないとどうしてもタイトルバーが消えてくれないです。(ほんとただ私のやり方が悪いだけなのかも。) Caption プロパティを設定したままタイトルバーを消す方法があるのでしょうか? > 先の投稿も一応検証してから アップしております VB6ですけどね ... 検証までして頂いてありがとうございます。 私の場合、SendMessageでWM_GETTEXTを送ると、ファイル名なのかプロジェクト名なのかわからないような名前(例えば、「abcd~1」みたいな文字列が返ってきました。) よくわかりませんが・・・;; 度々、ありがとうございました。

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

> VB5にはご紹介頂いたMutexや Eventはないようです;; 「+VB +Windows +API」で Google 検索 http://www.google.co.jp/search?sourceid=navclient-ff&ie=UTF-8&rls=GGGL,GGGL:2006-34,GGGL:ja&q=%2BVB+%2BWindows+%2BAPI すると,↓こんなサイトが見つかりました. 「WinAPI Database for VB Programmer」は、WindowsAPIの解説を1600以上保有するサイト。 http://www.winapi-database.com/ VB5 でも API を使えるようになるかどうかは知りませんが…. 使えそうであれば,次の API を探して使ってください. ・CreateMutex() ・CreateEvent() ・SetEvent() ・ResetEvent() Windows API の VB 用宣言を集めたファイルというのを以前どこかで 見かけたことがあるので,このサイトでも探せば見つかるかもしれません. また,ウインドウメッセージと Event を同時に待つには,メッセージループの 中で次のどちらかの API を使えば実現できますが,VB のメッセージループを プログラマが変更できるのか,あるいは変更できないまでも,Event を待つように 指定できるのかどうかは知りません.(ここが一番難関になりそうですが.) ・MsgWaitForMultipleObjects() ・MsgWaitForMultipleObjectsEx()

noname#208339
質問者

お礼

ありがとうございます。 > こんなサイトが見つかりました. 便利なサイトを教えて頂いてりがとうございます。サンプルがたくさんあってわかりやすいですね。 > VB5 でも API を使えるようになるかどうかは知りませんが VB5 でも API は使えます。 > 次の API を探して使ってください. そういうAPIもあるんですね。 参考にさせて頂きます。 難しそうですががんばってみます。 どうもありがとうございました。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

VBはどのバージョンでしょう? VB6でしょうか ... 実行ファイルの位置(パス)が同じなら PrevInstanseで確認できます すでに起動している自分自身を見つけるには EnumWindowsのコールバックで WM_GETTEXTを引数にしてSendMessageでCaptionを取得してみましょう Dim buf(256) as Byte dim s as String, n as Integer if IsWindowVisible( hWnd ) then  ' IsWindowsVisibleも WinAPIです ...  SendMessage hwnd, WM_GETTEXT, 256, buf(0)  s = StrConv( buf, vbUnicode )  n = Instr( buf, char(0) )  s = left( s, n -1 ) end if といった具合で ...

noname#208339
質問者

お礼

どうもありがとうございます。 すいません、VB5です。 >SendMessageでCaptionを取得してみましょう タイトルバーがないのでCaptionもなく・・・;; ウインドウをウインドウテキストやクラス名以外で検索する方法が、他にあるのではないかと思って質問させて頂いたのですが、簡単に一つのAPIで検索する方法はないようですね。 ダミーのコマンドボタンを貼り付けて、そのコマンドボタンを検索することで実現しようと思います。 どうもありがとうございました。

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.1

> アプリに二重起動防止機能を付けたい 二重起動防止は,Mutex を使えばできます. .NET TIPS:Windowsアプリケーションの多重起動を禁止するには? (VB サンプルあり) http://www.atmarkit.co.jp/fdotnet/dotnettips/145winmutex/winmutex.html > すでに起動されている場合はそのアプリのウインドウを > 元の大きさに戻してアクティブにする これはやったことがないのでわかりませんし,VB を知らないので VB で使えるかどうか も知りませんが,Windows API レベルの話をすれば,Mutex と同様に名前付き Event を使えばできそうな気がします. (1) (名前付き) Mutex と同様に,(名前付き) Event を作成する. (2a) (1) に失敗 (ERROR_ALREADY_EXISTS) した場合には,既にアプリケーションが起動 されている.このとき,既に作成済の Event のハンドルが得られるので, そのイベントをシグナル状態にすることにより,最初に起動されたアプリに 二重起動されそうになったことを知らせる. (2b) (1) に成功した場合には,メッセージループで常に上記のイベントを監視しておき, それがシグナル状態になったらウインドウを元の大きさに戻してアクティブにする. Windows API のレベルでは,この方法でできると思いますが,VB で Event が使えるか, また VB のメッセージループで Event を監視する方法があるかどうかは知りません.

noname#208339
質問者

お礼

どうもありがとうございます。 すいません;;、バージョンを言うのを忘れていました。VB5です。 VB5にはご紹介頂いたMutexや Eventはないようです;; .NETにはそのような機能があるのですね。 勉強になりました。 どうもありがとうございました。

関連するQ&A