Author:水如煙
這裡用到TypeHelper類 。
我們知道,桌面應用程序一般有兩種類型,一是Windows應用程序,二是控制台應用程序。
如何判斷調用自己所在Dll的主程序是Windows還是控制台應用程序呢?
解決這個問題,基點是ApplicationBase,ConsoleApplicationBase和WindowsFormsApplicationBase,
攻擊的地方,當然是Application了。
我也曾想到能否從Thread.CurrentContext,Thread.CurrentThread,AppDomain.CurrentDomain來切入,不過沒有去看。現在想“當然”的Application,有點武斷,況且,Application源於System.Windows.Forms空間,用它來判斷ConsoleApplicationBase,總覺得有些刺。
據自己的測試,主程序的有三種體現方式,如下:
Public Enum ApplicationType
WindowsForms ''這是Form啟動的Windows應用程序
ConsoleForms ''這是Main啟動且含代碼Application.Run(New Form)的控制台應用程序
Console ''這是Main啟動無窗體的控制台應用程序,就算是Form.ShowDialog也列於此項
End Enum
MyApplicationBase.vb
Imports Microsoft.VisualBasic.ApplicationServices
Namespace LzmTW.uSystem.uForms
Public Class MyApplicationBase
''System.Windows.Forms.Application+ThreadContext
Private Shared gThreadContextType As uReflection.TypeHelper
''Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase+WinFormsAppContext
Private Shared gWinFormsAppContextType As uReflection.TypeHelper
Private gAppContext As Object = Nothing ''ApplicationContext or WinFormsAppContext
Private gWindowsFormsApplicationBase As WindowsFormsApplicationBase = Nothing
Private gCurrentType As ApplicationType
Shared Sub New()
gThreadContextType = New uReflection.TypeHelper(GetType(Application), "ThreadContext", True)
gWinFormsAppContextType = New uReflection.TypeHelper(GetType(WindowsFormsApplicationBase), "WinFormsAppContext", True)
End Sub
Sub New()
GetApplicationContext()
GetWindowsFormsApplicationBase()
gCurrentType = GetApplcationType()
End Sub
Private Sub GetApplicationContext()
Dim mCurrentThreadContext As Object
mCurrentThreadContext = gThreadContextType.MethodInvoke("FromCurrent")
gThreadContextType.SetCurrentObj(mCurrentThreadContext)
gAppContext = gThreadContextType.GetMemberValue("ApplicationContext")
End Sub
Private Sub GetWindowsFormsApplicationBase()
If Not gWinFormsAppContextType.CurrentType.IsInstanceOfType(gAppContext) Then Return
gWinFormsAppContextType.SetCurrentObj(gAppContext)
gWindowsFormsApplicationBase = CType(gWinFormsAppContextType.GetMemberValue("m_App"), WindowsFormsApplicationBase)
End Sub
Private Function GetApplcationType() As ApplicationType
If gAppContext Is Nothing Then
Return ApplicationType.Console
End If
If gWindowsFormsApplicationBase Is Nothing Then
Return ApplicationType.ConsoleForms
End If
Return ApplicationType.WindowsForms
End Function
Public ReadOnly Property ApplicationContext() As ApplicationContext
Get
Return CType(gAppContext, ApplicationContext)
End Get
End Property
Public ReadOnly Property WindowsFormsApplicationBase() As WindowsFormsApplicationBase
Get
Return gWindowsFormsApplicationBase
End Get
End Property
Public ReadOnly Property CurrentType() As ApplicationType
Get
Return gCurrentType
End Get
End Property
Public Enum ApplicationType
WindowsForms
ConsoleForms
Console
End Enum
End Class
End Namespace
控制台的一個測試:
Public Class Program
Shared Sub Main()
Console.WriteLine((New LzmTW.uSystem.uForms.MyApplicationBase).CurrentType.ToString)
Application.Run(New Form1)
Console.WriteLine((New LzmTW.uSystem.uForms.MyApplicationBase).CurrentType.ToString)
Console.Read()
End Sub
End Class
而Form1中有一個按鈕也來測試
Private Sub ButtonTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonTest.Click
Console.WriteLine((New LzmTW.uSystem.uForms.MyApplicationBase).CurrentType.ToString)
End Sub
那麼,顯示的結果,先是Console,後是ConsoleForms,最後是Console。
MyApplicationBase有沒有用?
這當然看自己的需求。
舉例來說,如果有一個類需要輸出信息,如是控制台應用程序,就輸出到控制台,如是WinForm程序,就以Form的形式顯示,
這個時候,就需要MyApplicationBase來判定的了。
另,如果是WinForm應用程序,MyApplicationBase.WindowsFormsApplicationBase其實就是My.Application,
這裡有大量的信息供自己使用。
個人感覺,這個類可能還是蠻有用的。