• 0

[VB.NET] Starting with a form and without


Question

Suppose I have Form1 and there's only 1 button in there (Button1) and I start my application through a Public Sub Main() in Module 1. Then, in Module 1 I have the fomr variable declared this way: Dim frmMain as New Form1; and inside the Sub Main() I have: Application.Run(frmMain). If I have the frmMain inside the Run(), the form will show, if I don't, no form will be shown. And no matter if I have something inside Run() or not, the code will notcontinue after that point unless some function is called from some button, menu or something... I mean:

Public Sub Main()
    Application.Run(frmMain)
    Debug.WriteLine("Test") ' This line won't be processed...
End Sub

Also, on the Module 1 I have some function like:

Public Sub Function1()
End Sub

It doesn't matter what's inside, it's just a function I need to use.

I need to call this function when I click the Button1; no problem with that, it's easy. Now... My application can be accessed with 1 parameter or not and this is my problem. Not reading parameters, cause for that I use the following code:

For Each Argument As String In CmdArguments
            If (Argument = "/monitor") Then
                MonSwitch = True
                Exit For
            End If
        Next

(also in Module1 declarations I have: Dim MonSwitch as Boolean)

I only need this (/monitor) parameter, so, if the application is executed normally, without any parameters, I want it to run as usual and show Form1 but if the parameter is found (MonSwitch = True) I want the application to run normally but without showing the form and after all that, I want to call Function1.

I can't find a way to make it work...

The contentes of my Function1 are:

Public Sub Function1()
        ' Make MainForm as invisible
        frmMain.ShowInTaskbar = False
        frmMain.Hide()

        ' Put icon in the notification area?
        If (frmMain.CheckIcon.Checked = True) Then
            frmMain.NotifyIcon.Visible = True
        End If
    End Sub

Because this code will be called at start (if /monitor is in the parameters) or when I press button1. As you can see, I have a NotifyIcon wich has visible property set to false in the design view and I set it to False when I press Button1 or I start the app with /monitor, wich means I don't want to show Form, I just want the app to rest on the notification area monitoring some files (that's what I want to do).

Basically, I want the app to start hidden and start monitor some files if the parameter /monitor is there, if it's not, show Form1 with all the settings about what to monitor and Button1 is to save the settings and start monitor.

Any help? Can't make all this mess work...

19 answers to this question

Recommended Posts

  • 0

I think you're making this way harder than it needs to be. What I would do is overload the constructor for your frmMain. Have the new New take a boolean as an argument. Store the argument in a private member variable of your form. Handle the Load event for the form and put the code from Function1 in it, except enclose it in an If statement that test the value of the member variable.

Module mainMod
    Public Sub Main(ByVal args() As String)
        Dim MonSwitch As Boolean = False
        For Each s As String In args
            If s = "/monitor" Then
                MonSwitch = True
                Exit For
            End If
        Next

        Application.Run(New frmMain(MonSwitch))

    End Sub

End Module

' frmMain
    Private isMon As Boolean
    Public Sub New(ByVal isMon As Boolean)
        MyBase.New()

        InitializeComponent()
        Me.isMon = isMon
    End Sub

    Private Sub FormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If isMon = True Then
            ' Make MainForm as invisible
            Me.ShowInTaskbar = False
            Me.Hide()

            ' Put icon in the notification area?
            If (Me.CheckIcon.Checked = True) Then
                Me.NotifyIcon1.Visible = True
            End If
        End If
    End Sub

  • 0

I have done the way you said but now I couldn't yet test it and now I have another problem...

The thing is that now I can't have Dim frmMain As New Form1 in the module declarations, and if I don't have that, how do I hacces the form properties and the form controls properties in some other module functions?

For instance, I have the following function in the module to load some settings from an ini file and set them in Form1:

Public Sub LoadSettings()
        Dim CheckStartup As Integer, CheckIcon As Integer
        Dim FileMon As String, FileRep As String

        ' Get settings from ini file
        FileMon = INISettings.GetString("Files", "FileMonitor", "")
        FileRep = INISettings.GetString("Files", "FileReplacement", "")
        CheckStartup = INISettings.GetInteger("Options", "Startup", 0)
        CheckIcon = INISettings.GetInteger("Options", "ShowIcon", 0)

        ' Set settings in MainForm
        frmMain.CheckStartup.CheckState = CheckStartup
        frmMain.CheckIcon.CheckState = CheckIcon
        frmMain.FileMon.Text = FileMon
        frmMain.FileRep.Text = FileRep
    End Sub

this is now longer working with your code...

And, is this possible? (the code you gave me):

Private Sub FormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
       If isMon = True Then
           ' Make MainForm as invisible
           Me.ShowInTaskbar = False
           Me.Hide()

           ' Put icon in the notification area?
           If (Me.CheckIcon.Checked = True) Then
               Me.NotifyIcon1.Visible = True
           End If
       End If
   End Sub

Make it like this and then create a startmonitor() function:

Private Sub FormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
       If isMon = True Then
           StartMonitor()
       End If
   End Sub

Can't I do it like that?

  • 0

1. Just dimension it in the module. Instantiate it in the Application.Run(). Not very good design though. Globals are not considered good code. Just because you can, doesn't mean you should.

2. You could stick the LoadSettings call in the constructor(after the InitializeComponent), or the Load handler. If you don't have a global(bad anyway) of frmMain, then just pass it as a parameter to LoadSettings, and any other sub/function that needs to read its properties, modifying the signature.

' old signature: public sub LoadSignature()
' new
public sub LoadSignature(frmMain frm) ' assuming frmMain is a class
    ' this is a preferred method anyhow. globals are bad.
end sub

3. Yes, you can put whatever you want in the Load event handler.

  • 0

:s

this is getting very confusing for me... I did not understand your last post and I still can't understand how could I access Form1 properties and controls and such in any module functions. And I also have something like this on sub main (wich is in module1):

frmMain.Text = AppName + " v" + AppVer

frmMain.NotifyIcon.Text = AppName + " v" + AppVer

How could I even pass a parameter in sub new()?? and passing parametr for any other function, did not work. I guess i'll have to deleted the module and code everything in the form...

  • 0

Sorry if I'm confusing you. I think you're missing some fundamental skills that would greatly help you.

I'm simply saying avoid global variables at all costs. It's not that hard to do.

Obviously, I don't have all your code, but here is a module that would do what you want it to without a global.

Module mainMod
    Public Sub Main(ByVal args() As String)

        ' get args first
        Dim MonSwitch As Boolean = False
        For Each s As String In args
            If s = "/monitor" Then
                MonSwitch = True
                Exit For
            End If
        Next

        ' instantiate the frm, passing the MonSwitch as a parameter
        Dim frm As frmMain = New frmMain(MonSwitch)
        frm.Name = Application.ProductName + " v." + Application.ProductVersion
        frm.NotifyIcon.Text = Application.ProductName + " v." + Application.ProductVersion

        ' run it
        Application.Run(frm)
    End Sub

    Public Sub LoadSettings(ByRef frm As frmMain)
        Dim CheckStartup As Integer, CheckIcon As Integer
        Dim FileMon As String, FileRep As String

        ' Get settings from ini file
        FileMon = INISettings.GetString("Files", "FileMonitor", "")
        FileRep = INISettings.GetString("Files", "FileReplacement", "")
        CheckStartup = INISettings.GetInteger("Options", "Startup", 0)
        CheckIcon = INISettings.GetInteger("Options", "ShowIcon", 0)

        ' Set settings in MainForm
        frm.CheckStartup.CheckState = CheckStartup
        frm.CheckIcon.CheckState = CheckIcon
        frm.FileMon.Text = FileMon
        frm.FileRep.Text = FileRep
    End Sub

    Public Sub StartMonitor(ByRef frm As frmMain)
        frm.ShowInTaskbar = False
        frm.Hide()

        ' Put icon in the notifications area?
        ' If (frm.CheckIcon.Checked = True) Then
        frm.NotifyIcon.Visible = True
        ' you could shorten this to just frm.NotifyIcon.Visible = frm.CheckedIcon.Checked
    End Sub
End Module

Here's the my form that calls this stuff in form load. I'm passing a variable to the constructor, and I'm passing a reference to the form itself. Again, I don't have everything you do, but it should illustrate to you what I'm talking about.

Imports System.Runtime.InteropServices
Public Class frmMain
    Inherits System.Windows.Forms.Form

    Private mIsMonitor As Boolean

    ' this is an overloaded constructor
    ' the default constructor is still there in the generated code region
    Public Sub New(ByVal isMonitor As Boolean)
        MyBase.New()
        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        mIsMonitor = isMonitor
    End Sub

    Public Sub FormLoad(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        ' do all form initialization
        LoadSettings(Me)
        If mIsMonitor = True Then
            StartMonitor(Me)
        End If
    End Sub

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        mIsMonitor = False
    End Sub


    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents NotifyIcon As System.Windows.Forms.NotifyIcon
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(frmMain))
        Me.NotifyIcon = New System.Windows.Forms.NotifyIcon(Me.components)
        '
        'NotifyIcon
        '
        Me.NotifyIcon.Icon = CType(resources.GetObject("NotifyIcon.Icon"), System.Drawing.Icon)
        Me.NotifyIcon.Text = "NotifyIcon"
        Me.NotifyIcon.Visible = True
        '
        'frmMain
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 273)
        Me.Name = "frmMain"
        Me.Text = "Main Form"

    End Sub

#End Region


End Class

  • 0

woooww... thanks a lot, I'll try it later as I can't do it right now but I just have 2 questions.

In here:

Module mainMod

Public Sub Main(ByVal args() As String)

where do this args come from? why are there? in my first example (where I wrote how would I get the /monitor parameter) I used a global variable like: Dim CmdArguments As String() = Environment.GetCommandLineArgs()

In your second [ code ] tag after "#Region " Windows Form Designer generated code ""... is there something I need to check or it was some mistake?

thanks once again.

  • 0

From MSDN:

  Quote
Main can also take a String array as an argument. Each string in the array contains one of the command-line arguments used to invoke your program. You can take different actions depending on their values.

It works the same as Environment.GetCommandLineArgs().

The second code tag is an entire form. I just cut and paste the whole thing. You can see that there is another New() sub there without the argument, which has mIsMonitor default to false. So, if you just instantiate the form with empty parens(e.g. frm = new frmMain() ), it'll load normally.

  • 0

Now I have another problem and I think this is easy to fix (at least for you) i'm going to create a new thread for that and hope you still read this :p

this is the following code I have to watch some folder's activity:

Dim Watchfolder As New FileSystemWatcher
        Dim FilePath As String = frmMain.FileMon.Text

        Watchfolder.Path = FilePath.Substring(0, frmMain.FileMon.Text.LastIndexOf("\"))
        Watchfolder.NotifyFilter = Watchfolder.NotifyFilter Or IO.NotifyFilters.Attributes

        AddHandler Watchfolder.Changed, AddressOf DoReplace
        AddHandler Watchfolder.Deleted, AddressOf DoReplace

        Watchfolder.EnableRaisingEvents = True

and then this:

Private Sub DoReplace(ByVal source As Object, ByVal e As FileSystemEventArgs)
    End Sub

Inside DoReplace, I need to get access to some textboxes text in the form and the whole code I just posted is in the module. How can I do it? If I try to add 1 more parameter to DoReplace, I just can't make it work in the line: AddHandler Watchfolder.Deleted, AddressOf DoReplace.

  • 0

Hmm... If you want data from your form, then your form should handle the Changed and Deleted events of the FileSystemWatch, IMO.

This is a design issue for sure. I don't know what else depends on your FileSystemWatch, so I can't give you a definitive answer.

  • 0
  weenur said:
Hmm... If you want data from your form, then your form should handle the Changed and Deleted events of the FileSystemWatch, IMO.

how do I do that?

basically, the filesystemwatcher code is inside the Startmonitor(). what else you need to know so I can try to help me?

  • 0
  Nazgulled said:
can't you (or anybody else) help em anymore? I really wanted to finish this and i'm almost there, just waiting for that part... I could make some gloabls but I didn't want to... I wanted to keep the DoReplace in the module too.

585292678[/snapback]

Is the FileSystemWatch declared(Dim) as a global or inside the StartMonitor?

  • 0
  Nazgulled said:
inside startmonitor() but I'll change it if necessary...

585293383[/snapback]

Yeah, make it public or friend in your module, outside any subs or functions. Then it's as simple as using the AddHandler in your form, like you did in your StartMonitor, in the constructor or the Load event. Just put the handling method in the form so it can access the form's members.

  • 0

the handling method can't be inside the form, it must be inside the startmonitor() wich is in the module, it must be there, because this function (startmonitor()) can be called in the load event with all that code we've been through the previous posts or can be called pressing a butotn and I don't want to have the same code duplicated...

  • 0
  Nazgulled said:
the handling method can't be inside the form, it must be inside the startmonitor() wich is in the module, it must be there, because this function (startmonitor()) can be called in the load event with all that code we've been through the previous posts or can be called pressing a butotn and I don't want to have the same code duplicated...

585293804[/snapback]

Then make a sub/function that takes a string or strings as parameters and have it called from the handler inside the form.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • They did remove the Start button with Windows 8, but everyone had their pitchforks out. That OS had its many issues, but you could work on a desktop environment without the Start. Safe to say not many liked it.
    • I always just assumed that how I start programs is pretty close to how most people do it, which is... 1)Either start a program from desktop icon. or... 2)Windows key (or mouse click on start menu) and when start menu appears type in a little of what program you are trying to find, it will highlight, then press enter (or find it with mouse pointer and click it) is the very basic idea. this is very basic core functionality I would never change since it's quick and to the point and just works and has been this way a long time now. NOTE: I am on Linux Mint 22.1-Xfce (I am using the 'dark' menu since the default light grey is a bit out of place with the rest of Mint's darker look), but the very basics like this are the same as Windows in this regard. I like how Mint tends to pretty much stay the same (minor tweaks from point release to point release that are slight but overall it's pretty much the same) instead of change for the sake of change like Windows does and ends up making some stuff potentially worse as a result. I say screw all of those trends where something has to 'look current' as I am more of the mindset once something looks good enough, which Mint does (along with say Windows 7's core interface and the like), you don't screw with it as if someone does want to mess with it, they can do their own custom tweaks on the side, but the base install should be like that 'old faithful' type of interface that everyone has been familiar with for decades now. so by that standard the 'Start Menu' is still useful. I would NEVER get rid of that core functionality as Win8 pretty much tried that upon release and it made doing VERY basic stuff a chore which is why after I briefly tried Win8 in a VM, I never bothered with that OS again as that was easily Microsoft's biggest mess up with interface changes and I have been using Windows since v3.11 in mid-1990's and that Win8 interface change was by far the biggest mess up from Microsoft (how that made it to the final product is beyond me). I realize they supposedly fixed it in Win 8.1, but by then no one really cared as Win7 was the standard and those moving on from that went to Win10.
    • i click a few things on the start menu, other wise I do still use the run box daily.
    • That article title has a typo, it's supposed to say "Do I even need it?" And... I would not have wasted time writing a full article on a software [or feature] analysis based on exactly 1 user experience.
    • Lots of people use it without having an angsty Gotterdammerung.
  • Recent Achievements

    • Week One Done
      Wayne Robinson earned a badge
      Week One Done
    • One Month Later
      Karan Khanna earned a badge
      One Month Later
    • Week One Done
      Karan Khanna earned a badge
      Week One Done
    • First Post
      MikeK13 earned a badge
      First Post
    • Week One Done
      OHI Accounting earned a badge
      Week One Done
  • Popular Contributors

    1. 1
      +primortal
      679
    2. 2
      ATLien_0
      275
    3. 3
      Michael Scrip
      207
    4. 4
      +FloatingFatMan
      171
    5. 5
      Steven P.
      148
  • Tell a friend

    Love Neowin? Tell a friend!