• 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

    • Guys, you should find another way to promote your deals... It's the third article in the last months that promote this deal for an upgrade from 10. Considering that upgrade from 10 to 11 is free it's a total non-sense.
    • Store should be a shrine of useful applications, vetted and verified. Easily sorted by publisher. Windows should start with not much installed and have things as options in the store. Not the wild west mess that it is. You could delete 95%+ of the crap on there and no one would notice. They need to add a better UI to the updates, it's awful right now.
    • Obsidian 1.9.2 brings breaking changes, UI improvements and several bug fixes by David Uzondu Obsidian 1.9.2 (Desktop) is now live, bringing some significant updates, especially if you have been using the Bases feature. If you're not familiar with Markdown, it's a simple way to write formatted text using a plain text editor; Obsidian is a free editor that lets you create and link notes using Markdown files stored right on your own computer. Obsidian is free to use, but if you support the project with a Catalyst license, you get access to early builds. Version 1.9.2 is in Early Access right now, so you'll need a Catalyst license to try it out This new version introduces some major breaking changes to Bases, so you'll want to pay attention here. The developers have overhauled the formula syntax and the .base file format itself. If you're using Obsidian Sync or sharing your vault across multiple devices, the team strongly recommends upgrading all your devices at the same time to dodge any annoying sync issues with files using different syntaxes. The new formula syntax in Bases is designed to be more flexible and easier to use, and it should feel familiar if you code in JavaScript. For instance, functions are now object-oriented; instead of writing contains(file.name, "Books"), you would now use file.name.contains("Booksou can also chain functions together, like property.split(' ').sort()[0].lower(). Other highlights include: Property names are no longer wrapped in backticks (`). Instead, to reference properties with spaces or special characters, the syntax is note["Property Name"] There is a new type system which provides greater control when writing formulas. New functions, such as link, date and list for converting a value to a different type. New file properties: file.path, file.links (a list of all internal links in this file), and file.tags (a list of all tags in this file, including frontmatter). Some functions have been replaced by comparison operators. For example, dateBefore(date1, date2) is now date1 < date2. Date modifications are now much simpler. Instead of dateModify(date, string), you can use date + string, for example, date("01/01/2025") + "1 year" For those wondering, the Bases feature was introduced back in Obsidian 1.9.0 as a way to turn notes into structured databases. You can learn more about the updated syntax here. Alongside these syntax changes, the .base file format has been updated for better extensibility, including a new properties section for configurations like displayName. There are some smaller improvements too, like Bases now showing the number of results in the current view and the operator dropdown for filters becoming searchable. Outside of Bases, the update brings fixes for the following: Tags view: Fixed "Show nested tags" showing the full tag name (e.g. #parent/child) File explorer: Fixed "Move folder to..." menu item not showing in context menu. Bases: Fixed view not closing after deleting the file. Bases: Fixed codeblock not rendering when "Indent with tabs" is enabled. On a related note, the creator of Markdown, John Gruber, recently shared his thoughts on rumors about Apple Notes potentially adding Markdown export. While he had reservations about Apple Notes becoming a full-blown Markdown editor, he seemed to think an export option would be useful. If the rumors are true, users will be able to easily export notes from Apple Notes and edit them in editors like Obsidian.
    • 1. DRM is the worst plague, I like my games clean. 2. Third party launchers are an overhead and annoyance.
  • Recent Achievements

    • First Post
      Uranus_enjoyer earned a badge
      First Post
    • Week One Done
      Uranus_enjoyer earned a badge
      Week One Done
    • Week One Done
      jfam earned a badge
      Week One Done
    • First Post
      survivor303 earned a badge
      First Post
    • Week One Done
      CHUNWEI earned a badge
      Week One Done
  • Popular Contributors

    1. 1
      +primortal
      430
    2. 2
      +FloatingFatMan
      239
    3. 3
      snowy owl
      212
    4. 4
      ATLien_0
      211
    5. 5
      Xenon
      157
  • Tell a friend

    Love Neowin? Tell a friend!