You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
11 KiB

Imports System.Windows.Forms
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO
Imports EDOKALib.Common
Public Module mMain
Public Class SerialHelper
'///Class mercilessly ripped-off from Dr GUI.Net #3 :)
Public Shared Function SerializeToBase64String(ByVal o As Object) As String
Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim serialMemoryStream As New MemoryStream()
formatter.Serialize(serialMemoryStream, o)
Dim bytes() As Byte = serialMemoryStream.ToArray()
Return Convert.ToBase64String(bytes).Trim()
End Function
Public Shared Function DeserializeFromBase64String(ByVal base64String As String) As Object
Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
base64String = base64String.Trim(ControlChars.NullChar)
Dim bytes() As Byte = Convert.FromBase64String(base64String)
Dim serialMemoryStream As New MemoryStream(bytes)
Return formatter.Deserialize(serialMemoryStream)
End Function
End Class
Public Class SingleInstance
Public Interface ISingleInstanceForm
Delegate Sub _WndProc(ByVal m As Message, ByRef Cancel As Boolean)
Event WndProc As _WndProc
ReadOnly Property Handle() As IntPtr
Sub HandleCommand(ByVal strCmd As String)
End Interface
#Region "API"
Private Const WM_COPYDATA As Integer = &H4A
<StructLayout(LayoutKind.Sequential)> _
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As Integer
End Structure
Private Declare Auto Function GetProp Lib "user32" (ByVal hWnd As Integer, ByVal lpString As String) As Integer
Private Declare Auto Function SetProp Lib "user32" (ByVal hWnd As Integer, ByVal lpString As String, ByVal hData As Integer) As Integer
Private Delegate Function EnumWindowsProc(ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As Integer) As Integer
Private Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
Public Declare Function SendMessageTimeout Lib "user32" Alias "SendMessageTimeoutA" _
(ByVal windowHandle As IntPtr, _
ByVal Msg As UInt16, _
ByVal wParam As IntPtr, _
ByRef lParam As COPYDATASTRUCT, _
ByVal flags As SendMessageTimeoutFlags, _
ByVal timeout As UInt16, _
ByVal result As IntPtr) As IntPtr
<Flags()> _
Public Enum SendMessageTimeoutFlags As Short
SMTO_NORMAL = &H0 '0x0000
SMTO_BLOCK = &H1 ''0x0001
SMTO_ABORTIFHUNG = &H2 '0x0002
SMTO_NOTIMEOUTIFNOTHUNG = &H8 '0x0008
End Enum
#End Region
#Region "EnumWindows"
Private Shared _EWP As New EnumWindowsProc(AddressOf EWP)
Private Shared Function EWP(ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
' Customised windows enumeration procedure. Stops
' when it finds another application with the Window
' property set, or when all windows are exhausted.
Try
If IsThisApp(hWnd) Then
_hWnd = hWnd
Return 0
Else
Return 1
End If
Catch
Return 0
End Try
End Function
Private Shared Function IsThisApp(ByVal hWnd As Long) As Boolean
' Check if the windows property is set for this
' window handle:
If GetProp(hWnd, _mcThisAppID & "_APPLICATION") = 1 Then
Return True
End If
End Function
Private Shared Function FindWindow() As Boolean
If _hWnd = -1 Then
EnumWindows(_EWP, 0)
If _hWnd = -1 Then
Return False
Else
Return True
End If
Else
Return True
End If
End Function
Private Shared Function SendCDSToWindow(ByVal CD As COPYDATASTRUCT) As Boolean
Try
Dim lpCD As IntPtr = Marshal.AllocHGlobal(Len(CD))
Marshal.StructureToPtr(CD, lpCD, False)
'SendMessage(_hWnd, WM_COPYDATA, _hWnd, lpCD)
Dim result As IntPtr
Dim retVal As IntPtr
Dim handle As New IntPtr(_hWnd)
retVal = SendMessageTimeout(handle, Convert.ToUInt16(WM_COPYDATA), handle, CD, SendMessageTimeoutFlags.SMTO_NORMAL, Convert.ToUInt16(2000), result)
Marshal.FreeHGlobal(lpCD)
Return True
Catch ex As Exception
TKBLib.Errorhandling.TraceHelper.Msg("EdokaApp.mMain.SendCDSToWindow", ex.Message & ex.StackTrace, TraceLevel.Error)
Return False
End Try
End Function
Private Shared Function SendMessageToWindow(ByVal strCmd As String) As Boolean
If _hWnd = -1 Then Return False
If Len(strCmd) = 0 Then
Try
Dim CD As COPYDATASTRUCT
With CD
.dwData = 0
.cbData = 0
.lpData = 0
End With
Return SendCDSToWindow(CD)
Catch
Return False
End Try
Else
Try
Dim B() As Byte = Encoding.Default.GetBytes(strCmd)
Dim lpB As IntPtr = Marshal.AllocHGlobal(B.Length)
Marshal.Copy(B, 0, lpB, B.Length)
Dim CD As COPYDATASTRUCT
With CD
.dwData = 0
.cbData = B.Length
.lpData = lpB.ToInt32
End With
Erase B
Try
If SendCDSToWindow(CD) Then
Return True
Else
Return False
End If
Catch
Return False
Finally
Marshal.FreeHGlobal(lpB)
End Try
Catch
Return False
End Try
End If
End Function
Private Shared Function SendMessageToWindow(ByVal oCmd As Object) As Boolean
Try
Dim strCmd As String = SerialHelper.SerializeToBase64String(oCmd)
Return SendMessageToWindow(strCmd)
Catch
Return False
End Try
End Function
#End Region
Private Shared _hWnd As Integer = -1
Private Shared _mcThisAppID As String
Private Shared oMutex As Threading.Mutex
Private Shared _MutexOwned As Boolean = False
Private Shared WithEvents MainForm As ISingleInstanceForm
Shared Sub New()
_mcThisAppID = Reflection.Assembly.GetExecutingAssembly().FullName
oMutex = New Threading.Mutex(True, _mcThisAppID & "_APPLICATION_MUTEX", _MutexOwned)
If Not _MutexOwned Then
If Not FindWindow() Then
_MutexOwned = True
End If
End If
AddHandler AppDomain.CurrentDomain.ProcessExit, AddressOf OnExit
End Sub
Private Shared Sub OnExit(ByVal sender As Object, ByVal e As EventArgs)
Try
If Not oMutex Is Nothing Then
oMutex.ReleaseMutex()
CType(oMutex, IDisposable).Dispose()
oMutex = Nothing
End If
Catch
'Do Nothing
End Try
End Sub
Public Shared ReadOnly Property IsFirstInstance() As Boolean
Get
Return _MutexOwned
End Get
End Property
Public Shared Function NotifyPreviousWindow() As Boolean
Return SendMessageToWindow(vbNullString)
End Function
Public Shared Function NotifyPreviousWindow(ByVal strText As String) As Boolean
Return SendMessageToWindow(strText)
End Function
Public Shared Function NotifyPreviousWindow(ByVal oCmd As Object) As Boolean
Return SendMessageToWindow(oCmd)
End Function
Public Shared Sub SetMainForm(ByVal frm As ISingleInstanceForm)
MainForm = frm
Try
Dim hWnd As Integer = frm.Handle.ToInt32
SetProp(hWnd, _mcThisAppID & "_APPLICATION", 1)
Catch
MainForm = Nothing
End Try
End Sub
Private Shared Sub MainForm_WndProc(ByVal m As System.Windows.Forms.Message, ByRef Cancel As Boolean) Handles MainForm.WndProc
Select Case m.Msg
Case WM_COPYDATA
Dim B() As Byte
Try
Dim CD As COPYDATASTRUCT = m.GetLParam(GetType(COPYDATASTRUCT))
ReDim B(CD.cbData)
Dim lpData As IntPtr = New IntPtr(CD.lpData)
Marshal.Copy(lpData, B, 0, CD.cbData)
Dim strData As String = Encoding.Default.GetString(B)
TKBLib.Errorhandling.TraceHelper.Msg("EdokaApp.mMain.SingleeInstance.MainForm_WndProc", "Received Windows Msg " & strData, TraceLevel.Info)
MainForm.HandleCommand(strData)
Cancel = True
Catch
Cancel = False
Finally
Erase B
End Try
Case Else
Cancel = False
End Select
End Sub
End Class
Private MainForm As EDOKAMain
<STAThread()> Public Function Main(ByVal CmdArgs() As String) As Integer
If SingleInstance.IsFirstInstance Then
Try
g_bRun = True
MainForm = New EDOKAMain()
MainForm.CmdArgsSimulated = CmdArgs
SingleInstance.SetMainForm(MainForm)
Application.Run(MainForm)
Catch ex As Exception
If Not Force_Exit Then
MsgBox(ex.Message)
End If
End Try
Else
g_bRun = True
SingleInstance.NotifyPreviousWindow(CmdArgs)
End If
End Function
End Module