InvalidOperationException thrown after trying to display a form - vb.net

I have a separate form that needs to display an image then fade out and open the main form. When it gets to the Form1.Show() part it throws InvalidOperationException. Here's my code:
Public Class SPLASH
Public Declare Auto Function AnimateWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal time As Integer, ByVal flags As Integer) As Boolean
Public Enum AnimateStyles
Slide = 262144
Activate = 131072
Blend = 524288
Hide = 65536
Center = 16
HOR_Positive = 1
HOR_Negative = 2
VER_Positive = 4
VER_Negative = 8
End Enum
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AnimateWindow(Me.Handle, 1000, AnimateStyles.HOR_Negative Or AnimateStyles.Blend)
Thread.Sleep(2000)
Form1.Show()
End Sub
End Class
Found no fix online for my problem and I couldn't fix it myself either. I look at the documentation but I think i may need to wait for the AnimateWindow function to be fully over or something but I don't know how.

Found an answer!
I created a function
Private Sub Done(ByVal Sender As Object, ByVal Event As System.EventArgs)
Dim MainForm As New Form1()
MainForm.Show()
End Sub
And added the following code before
Dim pr As New Process
pr.EnableRaisingEvents = True
AddHandler pr.Exited, AddressOf Done
After which I put my usual code.
:)

Related

Basic Key Logger - Code Not Working

Public Class Form1
Dim KeyState
Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Int32) As Boolean
Private Sub LogTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LogTimer.Tick
For I = 1 To 255
KeyState = 0
KeyState = GetAsyncKeyState(I)
If KeyState = True Then
Me.txtLog.Text = Me.txtLog.Text & Chr(I)
End If
Next I
End Sub
End Class
Just a run down:
I am attempting to get the up/down state of every key every tenth of a second(the timer), then add any keys pressed to a textbox.
I honestly cannot see why this code is not working.
Make sure that you actually have the timer being told to start somewhere. In my experience, I've always had to write actual code to tell it start, and the properties in design view always give me trouble.

Send a form to a sub declared in a DLL files

I'm trying to create (finally) my own DLL files to some code that I will use constantly in a new project, I'm using Visual Basic 2010
I created the DLL correctly but I got a problem with a sub have the code Me.Handle
I don't know how to send the "me" to my sub
This is my sub (from an example in msdn)
Sub Start_Detection()
Dim di As New DEV_BROADCAST_DEVICEINTERFACE
di.dbcc_size = CUInt(Marshal.SizeOf(GetType(DEV_BROADCAST_DEVICEINTERFACE)))
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
di.dbcc_reserved = 0
di.dbcc_classguid = Guid.Parse("{88BAE032-5A81-49f0-BC3D-A4FF138216D6}")
di.dbcc_name = Nothing
hDevNotify = RegisterDeviceNotification(Me.Handle, di, DEVICE_NOTIFY_WINDOW_HANDLE)
End Sub
When I put that inside a DLL, I don't know how to send the Me because in the DLL project says that "Me" isn't a member of my DLL project.
If I declare the sub as Sub Start_Detection(ByRef Form) or Sub Start_Detection(ByVal Form) the DLL project works ok, but when I call it from the windows form project a "Null Reference Exception" happen.
Is not possible to send forms as arguments in Visual Basic 2010 ?
Thanks!
Edit: I'm calling the sub in this way
Private Sub Frm_Config_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyDLL.Start_Detection(Me)
End Sub
You might also want to consider using the following naming convention for the parameter
Sub Start_Detection (ByVal sender As System.Object)
or
Sub Start_Detection (ByVal handle As IntPtr)
When your calling the method, pass the handle value to the Class method
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Me.IsHandleCreated Then
RecieveHandle.Start_Detection(Me.Handle)
End If
End Sub
Then once your in the class module, you can do a common trick to confirm the variable has been supplied and don't pass a reference to the whole form via the "Me" (VB) or "This" (C#) variable.
Public Class RecieveHandle
Public Shared Sub Start_Detection(ByVal sender As System.Object)
If sender Is Nothing Then
Throw New ArgumentException("Method requires sender parameter to be supplied")
End If
If Not TypeOf (sender) Is IntPtr Then
Throw New ArgumentException("Method requires a valid pointer (handle) to the form.")
End If
Dim myFormHandle As IntPtr = CType(sender, IntPtr)
Debug.Print(myFormHandle.ToInt64.ToString)
End Sub
End Class
Me belongs to a form not a dll. If you pass the IntPtr you will be fine.
Sub Start_Detection(ptr As IntPtr)
Dim di As New DEV_BROADCAST_DEVICEINTERFACE
di.dbcc_size = CUInt(Marshal.SizeOf(GetType(DEV_BROADCAST_DEVICEINTERFACE)))
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
di.dbcc_reserved = 0
di.dbcc_classguid = Guid.Parse("{88BAE032-5A81-49f0-BC3D-A4FF138216D6}")
di.dbcc_name = Nothing
hDevNotify = RegisterDeviceNotification(ptr, di, DEVICE_NOTIFY_WINDOW_HANDLE)
End Sub
Usage:
Start_Detection(Me.Handle)

Saving textbox name when clicked in order to input text

Hey all i am in need of some help getting my code working correctly like i am needing it to. Below is my code that when the user click on the textbox, it pops up a keyboard where they can click on any letter and it will type that letter into the textbox. Problem being is i can not seem to get the name of the text box to return so that it knows where to send the letters to.
Order in firing is:
TextBox1_MouseDown
keyboardOrPad.runKeyboardOrPad
kbOrPad.keyboardPadType
ClickLetters
Form1.putIntoTextBox
Form1
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
Call keyboardOrPad.runKeyboardOrPad("SHOW") 'Just shows the keyboard
Call kbOrPad.keyboardPadType("PAD", TextBox1)
End Sub
Public Sub putIntoTextBox(ByRef what2Put As String, ByRef whatBox As TextBox)
whatBox.Text = what2Put '<-- has error Object reference not set to an instance of an object. for the whatBox.text
End Sub
kbOrPad class
Dim theBoxName As TextBox = Nothing
Public Sub keyboardPadType(ByRef whatType As String, ByRef boxName As TextBox)
theBoxName = boxName '<-- shows nothing here
Dim intX As Short = 1
If whatType = "PAD" Then
Do Until intX = 30
Dim theButton() As Control = Controls.Find("Button" & intX, True)
theButton(0).Enabled = False
intX += 1
Loop
ElseIf whatType = "KEYB" Then
End If
End Sub
Private Sub ClickLetters(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim btn As Button = CType(sender, Button)
If btn.Text = "Backspace" Then
Else
Call Form1.putIntoTextBox(btn.Text, theBoxName) 'theBoxName taken from keyboardPadType
End If
End Sub
Some visuals for you:
Pastebin code: http://pastebin.com/4ReEnJB0
make sure that theBoxName is a Module scoped variable, then I would populate it like this giving you the flexibility of implementing a shared TextBox MouseDown Handler:
Private Sub TextBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
Dim tb As TextBox = CType(sender, TextBox)
Call keyboardPadType("PAD", tb)
End Sub
Try something like this
Public Class Form1
Dim myKborPad As New kbOrPad
Private Sub TextBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
Dim tb As TextBox = CType(sender, TextBox)
Call myKborPad.keyboardPadType("PAD", tb)
End Sub
Edit Based on your PasteBin code.
I noticed you already have an instance of your keyboardPadType declared in your Module, use that instead of what I said earlier. That code should look like:
remove:
Dim myKborPad As New kbOrPad
and use the theKbOrPad that you created in your module like this:
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
Dim tb As TextBox = CType(sender, TextBox)
Call keyboardOrPad.runKeyboardOrPad("SHOW")
Call theKbOrPad.keyboardPadType("PAD", tb)
'Call kbOrPad.keyboardPadType("PAD", tb)
End Sub
Also about the current error your are getting, you are trying to use the default instance of your Form1 , it isn't the actual Form that you are running, you can code around this by making the method you are trying to use as shared. Like this:
Public Shared Sub putIntoTextBox(ByRef what2Put As String, ByRef whatBox As TextBox)
whatBox.Text = what2Put
End Sub
But however I would actually prefer to put it into your Module like this
Public Sub putIntoTextBox(ByRef what2Put As String, ByRef whatBox As TextBox)
whatBox.Text = what2Put
End Sub
and call it like this
Call putIntoTextBox(btn.Text, theBoxName)
after making above changes your code worked.
First, you should replace the ByRef with ByVal (anytime you don't know whether you should use one or the other, use ByVal).
Secondly, I believe you don't need the method, putIntoTextBox, I think you should be able to do that directly (might be threading problems that prevent it, but I don't think that's likely based on your description). You don't show where Form1 is set (or even if it is), and that's another potential problem.
Finally, the better way to call back into the other class is to use a delegate/lambada.
(I know, no code, but you don't provide enough context for a working response, so I'm just giving text).

VB.NET example code for calling other exe to act like as MDI child form? is it possible?

ok here is the scenario.
1. i've create a project that has 1 form named form1.exe
2. i've also create a project that has 1 MDI form.
in this MDI Form. i'would like to call "form1.exe" act like / behave like MDI Form child.
i've tried using this code :
Public Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndParent As IntPtr) As IntPtr
End Function
Private Sub ShowNewForm(ByVal sender As Object, ByVal e As EventArgs) Handles NewToolStripMenuItem.Click, NewToolStripButton.Click, NewWindowToolStripMenuItem.Click
Dim myProcess As Process = New Process()
myProcess.StartInfo.FileName = "D:\tesVB.exe"
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
myProcess.Start()
myProcess.WaitForInputIdle()
SetParent(myProcess.MainWindowHandle, Me.Handle)
myProcess.WaitForExit()
End Sub
Above code is worked but that new child form(form1.exe) doesn't act like it should be! When i maximized or minimized it. it don't act like MDI Child Form.
Can anyone give me another better example code ? thx before.
hahaha.... found it my self. hope this solution would be good for others.
Private Sub ShowNewForm(ByVal sender As Object, ByVal e As EventArgs) Handles NewToolStripMenuItem.Click, NewToolStripButton.Click, NewWindowToolStripMenuItem.Click
Dim eAssembly As System.Reflection.Assembly = System.Reflection.Assembly.LoadFrom("D:\form1.exe")
Dim eForm As Form = eAssembly.CreateInstance("form1.Form1", True)
Me.AddOwnedForm(eForm)
eForm.MdiParent = Me
eForm.Show()
End Sub
Private Sub ShowNewForm(ByVal sender As Object, ByVal e As EventArgs) Handles NewToolStripMenuItem.Click, NewToolStripButton.Click, NewWindowToolStripMenuItem.Click
Dim eAssembly As System.Reflection.Assembly = System.Reflection.Assembly.LoadFrom("D:\form1.exe")
Dim eForm As Form = eAssembly.CreateInstance("form1.Form1", True)
Me.AddOwnedForm(eForm)
eForm.MdiParent = Me
eForm.Show()
End Sub
Runtime error
eform is a form and eAssembly.CreateInstance("form1.Form1", True) returns an object

Creating a progress bar that runs on another thread, while keeping calculation in main thread

Preface: I know this is an unusual/improper way to do this. I can do this with a "real" ShowDialog(), background worker/thread, and so on. I'm not looking for help doing it that way; I am trying to do specifically what I describe here, even if it is ugly. If this is impossible for X reason, please let me know though.
I have created a fancy progress dialog for some of our long running operations. I need to have this dialog shown on a new thread while having processing continue on the calling (UI in most cases) thread.
This has 3 real requirements:
Prevent user interaction with the calling form (similar to ShowDialog(this))
Keep the progress dialog above the main window (it can fall behind now)
Allow the main thread to continue processing
What I have looks like this (and works just fine so far, as far as running goes, except for those issues above):
Using ... ShowNewProgressDialogOnNewThread() ...
Logic
UpdateProgress() //static
Logic
UpdateProgress() //static, uses Invoke() to call dialog
...
End Using // destroys the form, etc
I have tried a few ways to do this:
ShowDialog() on BackgroundWorker / Thread
Action.BeginInvoke() which calls a function
ProgressForm.BeginInvoke(... method that calls ShowDialog... )
Wrapping main form in a class that implements IWin32Window so it can be called cross-threaded and passed to ShowDialog() - this one failed somewhere later one, but at least causes ShowDialog() to not barf immediately.
Any clues or wisdom on how to make this work?
Solution (For Now)
The call to EnableWindow is what did what I was looking for.
I do not experience any crashes at all
Changed to use ManualResetEvent
I set TopMost, because I couldn't always guarantee the form would end up on top otherwise. Perhaps there is a better way.
My progress form is like a splash screen (no sizing, no toolbar, etc), perhaps that accounts for the lack of crashes (mentioned in answer)
Here is another thread on the EnableWindow topic (didn't reference for this fix, tho)
Getting the progress window consistently displayed on top of the (dead) form is the difficult requirement. This is normally handled by using the Form.Show(owner) overload. It causes trouble in your case, WF isn't going to appreciate the owner form belonging to another thread. That can be worked around by P/Invoking SetWindowLong() to set the owner.
But now a new problem emerges, the progress window goes belly-up as soon as it tries to send a message to its owner. Somewhat surprisingly, this problem kinda disappears when you use Invoke() instead of BeginInvoke() to update progress. Kinda, you can still trip the problem by moving the mouse over the border of the disabled owner. Realistically, you'll have to use TopMost to nail down the Z-order. More realistically, Windows just doesn't support what you are trying to do. You know the real fix, it is at the top of your question.
Here's some code to experiment with. It assumes you progress form is called dlgProgress:
Imports System.Threading
Public Class ShowProgress
Implements IDisposable
Private Delegate Sub UpdateProgressDelegate(ByVal pct As Integer)
Private mOwnerHandle As IntPtr
Private mOwnerRect As Rectangle
Private mProgress As dlgProgress
Private mInterlock As ManualResetEvent
Public Sub New(ByVal owner As Form)
Debug.Assert(owner.Created)
mOwnerHandle = owner.Handle
mOwnerRect = owner.Bounds
mInterlock = New ManualResetEvent(False)
Dim t As Thread = New Thread(AddressOf dlgStart)
t.SetApartmentState(ApartmentState.STA)
t.Start()
mInterlock.WaitOne()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
mProgress.BeginInvoke(New MethodInvoker(AddressOf dlgClose))
End Sub
Public Sub UpdateProgress(ByVal pct As Integer)
mProgress.Invoke(New UpdateProgressDelegate(AddressOf dlgUpdate), pct)
End Sub
Private Sub dlgStart()
mProgress = New dlgProgress
mProgress.StartPosition = FormStartPosition.Manual
mProgress.ShowInTaskbar = False
AddHandler mProgress.Load, AddressOf dlgLoad
AddHandler mProgress.FormClosing, AddressOf dlgClosing
EnableWindow(mOwnerHandle, False)
SetWindowLong(mProgress.Handle, -8, mOwnerHandle)
Application.Run(mProgress)
End Sub
Private Sub dlgLoad(ByVal sender As Object, ByVal e As EventArgs)
mProgress.Location = New Point( _
mOwnerRect.Left + (mOwnerRect.Width - mProgress.Width) \ 2, _
mOwnerRect.Top + (mOwnerRect.Height - mProgress.Height) \ 2)
mInterlock.Set()
End Sub
Private Sub dlgUpdate(ByVal pct As Integer)
mProgress.ProgressBar1.Value = pct
End Sub
Private Sub dlgClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
EnableWindow(mOwnerHandle, True)
End Sub
Private Sub dlgClose()
mProgress.Close()
mProgress = Nothing
End Sub
'--- P/Invoke
Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr
If IntPtr.Size = 4 Then
Return SetWindowLongPtr32(hWnd, nIndex, dwNewLong)
Else
Return SetWindowLongPtr64(hWnd, nIndex, dwNewLong)
End If
End Function
Private Declare Function EnableWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal enabled As Boolean) As Boolean
Private Declare Function SetWindowLongPtr32 Lib "user32.dll" Alias "SetWindowLongW" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr
Private Declare Function SetWindowLongPtr64 Lib "user32.dll" Alias "SetWindowLongW" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr
End Class
Sample usage:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Using dlg As New ShowProgress(Me)
For ix As Integer = 1 To 100
dlg.UpdateProgress(ix)
System.Threading.Thread.Sleep(50)
Next
End Using
End Sub
I know it's a bit dirty but can't you just do the work in the dialog??
I mean something like
Dialog.MyShowDialog(callback);
and do all the work in callback as well as the UI update.
That way you'll retain the ShowDialog behaivour while allowing different code to be called.
I wrote a blog post on this topic a while ago (dealing with splash forms, but the idea is the same). The code is in C#, but I will try to convert it an post it here (coming...).