none
使用 SendMessage Show 出另一個執行中程式,該執行中程式若為 Hide 時會 Show 失敗 RRS feed

  • 問題

  • 在 Form 中加入 NotifyIcon,NotifyIcon.Visible = False,
    透過 Form.Resize 將程式 Hide 並 NotifyIcon.Visible = True,

        Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
            If Me.WindowState = FormWindowState.Minimized Then
                NotifyIcon1.Visible = True
                Me.Hide()
            End If
        End Sub


    於 Form.Load 中使用 Mutex 判斷程式是否重複開啟,若有就執行 SendMessage,
    然後執行程式執行檔,程式啟動後將視窗最小化,

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            If IsMyMutex() Then
                send()  'SendMessage()
                End
            End If
        End Sub
    
        Private Function IsMyMutex() As Boolean
            Dim IsExist As Boolean
            Dim MyMutex As New Mutex(True, "OnlyRun", IsExist)
            If IsExist Then
                Return False
            Else
                Return True
            End If
        End Function


    SendMessage :

     Private Sub send()
            Dim s As String = "Twins"
    
            Dim vProcesses As Process() = Process.GetProcessesByName("aa")
            If vProcesses.Length <= 0 Then
                vProcesses = Process.GetProcessesByName("aa.vshost")
            End If
    
            If vProcesses.Length <= 0 Then
                Return
            End If
    
            Dim vCopyDataStruct As New CopyDataStruct
            vCopyDataStruct.dwData = 0
            vCopyDataStruct.cdData = s.Length * Len(New Char) + Len(New Char) 
            vCopyDataStruct.lpData = Marshal.StringToBSTR(s)
    
            Dim vAddress = Marshal.AllocCoTaskMem(Marshal.SizeOf(vCopyDataStruct))
            Marshal.StructureToPtr(vCopyDataStruct, vAddress, True)
    
            For Each vProcess As Process In vProcesses
                SendMessage(vProcess.MainWindowHandle, WM_COPYDATA, 0, CInt(vAddress))
            Next
    
            Marshal.FreeBSTR(vCopyDataStruct.lpData)
            Marshal.FreeCoTaskMem(vAddress)
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            Select Case m.Msg
                Case WM_COPYDATA
                    Dim vCopyDataStruct As CopyDataStruct = CType(Marshal.PtrToStructure(m.LParam, GetType(CopyDataStruct)), CopyDataStruct)
    
                    Me.Label1.Text = Marshal.PtrToStringBSTR(vCopyDataStruct.lpData)
                    Me.Show()
                    Me.WindowState = 0 
                    Me.Activate()
                    Me.TopMost = True
                    NotifyIcon1.Visible = False
    
                    Exit Select
            End Select
            MyBase.WndProc(m)
        End Sub

    此時再執行一次執行檔,先前啟動的程式沒有如期被 Show 出來,若註解掉 Form.Resize 裡的 Me.Hide() 就沒問題。
    我想要程式被重複啟動時直接 Sohw 已執行中的程式而不至於重複開啟,請問有辦法嗎?

    另外 Form.Hide 時是不是無法控制視窗?
    因為 
    Form.Hide 時,Protected Overrides Sub WndProc() 並沒有執行 Label 顯示,
    但我用下面的程式卻又可以修改 Label1.Hide 物件。

       Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            If Label1.Visible Then
                Label1.Hide()
            Else
                Label1.Show()
            End If
        End Sub
    
        Dim a As Integer
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            a += 1
            Label1.Text = a
        End Sub



    • 已編輯 C.Kevin 2013年2月4日 上午 06:13
    2013年2月4日 上午 06:10

解答

  • Hi,

    是~我說你的程式Mutex有問題就是在release偶爾會出錯

    解決辦法我都寫在那兩篇了...

    你應該要把它變成成員變數~不該是區域變數

    如果是區域變數也要用using之類的語法確保不會被回收

    另外你不該在Form內去用這道函式判斷

    而是要向上篇我回覆你的那樣

    設定從main去啟動程式

    如果mutex已經建立就發送訊息給舊的程式讓他恢復正常狀態

    如果還沒建立就繼續啟動

    你這樣在Form內去判斷會建立不必要的Form實體

    在發送訊息時也會不好處理


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/

    2013年2月5日 上午 08:05

所有回覆

  • Hi,

    建議你先把我上一篇給你的兩個連結看一下

    Mutex的用法會有問題~

    sendmessage改用class name下去找

    依你的需求也不需要copydata

    你只要發送訊息過去就好了

    也許訊息的編號是0x401這樣

    接收端收到0x401就還原帶出本來的視窗


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/

    2013年2月4日 上午 06:23
  • 我改不出來.....

        Private Function IsMyMutex() As Boolean
            Dim IsExist As Boolean
            Dim MyMutex As New Mutex(True, "OnlyRun", IsExist)
            MyMutex.WaitOne()
            GC.Collect()
            If IsExist Then
                Return False
            Else
                Return True
            End If
            MyMutex.ReleaseMutex()
        End Function

    到 Release 去還是會重複啟動程式。

    Class Name 也改不出來。


    • 已編輯 C.Kevin 2013年2月5日 上午 07:06
    2013年2月5日 上午 07:05
  • Hi,

    是~我說你的程式Mutex有問題就是在release偶爾會出錯

    解決辦法我都寫在那兩篇了...

    你應該要把它變成成員變數~不該是區域變數

    如果是區域變數也要用using之類的語法確保不會被回收

    另外你不該在Form內去用這道函式判斷

    而是要向上篇我回覆你的那樣

    設定從main去啟動程式

    如果mutex已經建立就發送訊息給舊的程式讓他恢復正常狀態

    如果還沒建立就繼續啟動

    你這樣在Form內去判斷會建立不必要的Form實體

    在發送訊息時也會不好處理


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/

    2013年2月5日 上午 08:05
  • Class name 那一篇我看得眼點眼花,把 Hide 的程式 Show 出來是不是這麼困難
    2013年2月6日 上午 03:55