|
Hi,
I don't think multi-threading is involved; however shaking your Form will create new objects, possibly causing the GC to run and remove a delegate that is still in use as you have stored it in unmanaged memory (SetWindowLong) so the CG cannot work out it is still in use. This is not the right way to handle this.
I do have similar functionality implemented in C#, without using any shell hooks: Windows will always broadcast Windows messages whenever a device gets added or removed, there is no need to subscribe to anything; all it takes is overriding WndProc and checking for such messages.
This is the heart of the matter (the constant values are 0x0219, 0x8000, 0x8004):
protected override void WndProc(ref Message m) {
if (m.Msg==LPWIN_Constants.WM_DEVICECHANGE) {
int wParam=(int)m.WParam;
int lParam=(int)m.LParam;
if (xpanel!=null) {
if (wParam==LPWIN_Constants.DBT_DEVICEARRIVAL) xpanel.DeviceAdded();
else if (wParam==LPWIN_Constants.DBT_DEVICEREMOVECOMPLETE) xpanel.DeviceRemoved();
}
}
}
|
|
|
|
|
"I do have similar functionality implemented in C#, without using any shell hooks" Yeah you are right. I used shell hooks to monitor processes or forms. Here is my simplyfied code:
Public Class HOOK_RMV_DEVICE
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Integer, _
ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As WndProc) As Integer
Private Shadows Delegate Function WndProc(ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const GWL_WNDPROC = -4
Private IsHooked As Boolean, lpPrevWndProc As Integer, WindowHandler As Integer
'
Private Const wMsg_REMOVABLE_DEVICE = 537
Private Const wParam_REMOVABLE_DEVICE_INSERTED = 32768
Private Const wParam_REMOVABLE_DEVICE_REMOVED = 32772
Public Function Hook() As Boolean
If IsHooked Then
Return False
Else
lpPrevWndProc = SetWindowLong(WindowHandler, GWL_WNDPROC, AddressOf WindowProc)
IsHooked = True
Return True
End If
End Function
Public Sub Unhook()
Dim temp As Long
temp = SetWindowLong(WindowHandler, GWL_WNDPROC, lpPrevWndProc)
IsHooked = False
End Sub
Function WindowProc(ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Dim e As New ShellHookEventArgs
e.hWnd = hWnd
e.wMsg = wMsg
e.wParam = wParam
e.lParam = lParam
e.REMOVABLE_DEVICE_INFO = ShellHookEventArgs.REMOVABLE_DEVICE.NONE
If wMsg = wMsg_REMOVABLE_DEVICE Then
If wParam = wParam_REMOVABLE_DEVICE_INSERTED Then
e.REMOVABLE_DEVICE_INFO = ShellHookEventArgs.REMOVABLE_DEVICE.INSERTED
RaiseEvent Removable_Device(Me, e)
ElseIf wParam = wParam_REMOVABLE_DEVICE_REMOVED Then
e.REMOVABLE_DEVICE_INFO = ShellHookEventArgs.REMOVABLE_DEVICE.REMOVED
RaiseEvent Removable_Device(Me, e)
End If
Else
'e.TempMsg = "hwnd=" & hWnd & ", wmsg=" & wMsg & ", wparam= " & wParam & ", lparam=" & lParam
'RaiseEvent Removable_Device(Me, e)
End If
WindowProc = CallWindowProc(lpPrevWndProc, hWnd, wMsg, wParam, lParam)
End Function
Public Event Removable_Device(ByVal sender As Object, ByVal e As ShellHookEventArgs)
Class ShellHookEventArgs
Inherits System.EventArgs
Public Enum REMOVABLE_DEVICE
NONE = 0
INSERTED = 1
REMOVED = 2
End Enum
Public hWnd, wMsg, wParam, lParam As Integer
Public REMOVABLE_DEVICE_INFO As REMOVABLE_DEVICE
Friend TempMsg As String
End Class
Public Sub New(ByVal WindowHandler As Integer)
Me.WindowHandler = WindowHandler
End Sub
Public Sub New()
Dim tmp As New Form
WindowHandler = tmp.Handle
End Sub
End Class This Codes also create that same error. Can you plz give some solution more than you gave before? I'm not a good programmer and very week in C#. I need something details.
|
|
|
|
|
The code I gave earlier is all there is to it. You should remove your P/Invoke stuff, the SetWindowLong calls, etc. However, you are missing the Overrides keyword that makes your windowproc replace the default one for your Form. Look at the documentation for Overrides, and search some examples. I don't have any VB code around right now.
|
|
|
|
|
Thanks I got it I forget add this line:
MyBase.WndProc(m)
It gives all my solution.
|
|
|
|
|
you're welcome.
|
|
|
|
|
hi friends.
i am writting a share and unshare program and i use this code for share a folder
Private Sub Sharing()
Try
Dim managementClass As New ManagementClass("Win32_Share")
Dim inParams As ManagementBaseObject = managementClass.GetMethodParameters("Create")
inParams("Description") = fname
inParams("Name") = fname
inParams("Path") = fpath
inParams("Type") = &H0
Dim outParams As ManagementBaseObject = managementClass.InvokeMethod("Create", inParams, Nothing)
If Convert.ToUInt32(outParams.Properties("ReturnValue").Value) <> 0 Then
chkShare.Checked = True
End If '
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
this works successfully but now i dont know how i can unshare a folder... help me please
M.Alizadeh
|
|
|
|
|
You already know how to call the Create method on the Win32_Share class, so what's so hard about calling its Delete method?
All you do is a WMI search for Win32_Share object with the Name you want, then call its Delete method.
You may want to consult the documentation on Win32_Share[^]for more.
|
|
|
|
|
thanks for your answer
i searched many articles but i dont know how use Delete Method of the Win32_Share Class
when i use this cose:
Dim dir As String = fpath
Directory.CreateDirectory(dir)
'Create a ManagementClass Object
Dim managementClass As New ManagementClass("Win32_Share")
' Create ManagementBaseObjects for in and out parameters
Dim inParams As ManagementBaseObject = managementClass.GetMethodParameters("Delete")
Dim outParams As ManagementBaseObject
' Set the input parameters
inParams("Description") = fname
inParams("Name") = fname
inParams("Path") = dir
inParams("Type") = &H0
' Invoke the method on the ManagementClass object
outParams = managementClass.InvokeMethod("Create", inParams, Nothing)
'Confirm that the operation is successful
If CUInt(outParams.Properties("ReturnValue").Value) <> 0 Then
Throw New Exception("Unable to share the directory.")
End If
MessageBox.Show("Folder share deleted")
in this line: "inParams("Description") = fname" it has a error:Object reference not set to an instance of an object.
fname is not null and has value
M.Alizadeh
|
|
|
|
|
mehrnoosh wrote: i searched many articles but i dont know how use Delete Method of the Win32_Share Class
Try the documentation on MSDN. It's always a good place to start.
Win32-Share[^] and Delete method[^]
Alan.
|
|
|
|
|
You didn't bother reading the documentation in the link I gave you in my last post, did you?
There are no parameters to pass to the Delete method, so why are you calling GetMethodParameters?? What are you trying to set parameters?? Why are you still calling InvokeMethod on the Create method??
I already told you you need to SEARCH for a Win32_Share object with the NAME you want. You then call the Delete method on that instance.
mehrnoosh wrote: in this line: "inParams("Description") = fname" it has a error:Object reference not set to an instance of an object.
Of course it errors! Why would you set a Description on an object you're trying to delete?!
It's obvious that you don't have any idea what a single line of this code does or how it relates to the idea of creating a Share let alone deleting one. Having said that, I have to ask if you know how to do a WMI search for an object?
|
|
|
|
|
Hi,
I create a MDI Parent form with a treeview control, each time user click tree node, a form related to this node will be opened as Module (not moduless), so mutiple child form can co-exist together, but how the MDI parent know if a child form is closed by user and then set the child form object to Nothing?
For example, I have parent form called frmMDIParent, and two child forms called frmChildForm1 and frmChildForm2.
public class frmMDIParent
Dim frmChild1 as frmChildForm1
Dim frmChild2 as frmChildForm2
private sub frmMDIParent_Load()
if frmChild1 is nothing then
frmChild1 = new frmChildForm1
frmChild1.MDIParent = Me
end if
if frmChild2 is nothing then
frmChild2 = new frmChildForm2
frmChild2.MDIParent = Me
end if
end sub
end class
if user click tree node1, then frmChild1.Show()
if user click tree node 2, then frmChild2.Show()
But when user close fromChild1, this form will be removed form parent's MDIChildren collection, but the frmChild object is still there, do we need to set it to Nothing when child from is closed? how? how the MDI parent can detect child form is closed?
Thanks!
|
|
|
|
|
They're still there because you're still holding on to a reference to the child form in your global class-scoped variables.
Normally, you'd just handle the item click in the TreeView, create a child form instance, set it up as an MdiChild, Show it and be done. But, your code is holding onto a reference that Mdi doesn't manage, so...
Either don't hold on to the reference or you'll have to subscribe to the child form's Closing event and handle it in there.
|
|
|
|
|
Dave,
Thanks for your reply.
Do you think it is necessary to create a class scope reference to child form? or just create a local referece when user click tree node, add set it as MDI child and show it? which way is better?
If we use local reference and user click tree node 1, the first child form is created and shown, how about if user click tree node 1 again? do we need to loop through all child form to check if the first child form in the collection or not, if yes, activate it, otherwise, create it, am I right?
|
|
|
|
|
Andraw Tang wrote: Do you think it is necessary to create a class scope reference to child form?
Generally, no. If your application, data model design, form code is written completely encapsulating what they are responsible for, then you normally wouldn't need a class-level variable holding a reference at all and the problem your looking at wouldn't exist at all.
Andraw Tang wrote: or just create a local referece when user click tree node, add set it as MDI child and show it? which way is better?
This is what i just told you in the last post.
Andraw Tang wrote: If we use local reference and user click tree node 1, the first child form is created and shown, how about if user click tree node 1 again?
I'd probably code it so that I'm searching the MdiChildren for the existance of a form that is working on the node in question. Of course, that would mean that the child forms are exposing a property that shows which node it's working on.
In all, I have no idea what your application is doing nor it's requirements, but you normally don't see an MDI environment hanging off a treeview. Normally, you'd only work on one item in the treeview at a time.
|
|
|
|
|
Dave,
Thanks for your detailed expaination.
My application will collect hundreds input data from user, these data is divided to several categories, each categroy has dozens of data, that's why I want to use tree view, and each node represent a category of data, and the reason I use MDI is because all these data are related together, so when user input data to a form, he can look at data in other form for reference.
After user input all the required data, we will prepare input files for a software to run calculation.
This project is now in design stage, so all the comments are very important to me.
If you have any suggestion for my case, please feel free to tell me, I am very appreciate your help.
|
|
|
|
|
Andraw Tang wrote: reason I use MDI is because all these data are related together, so when user input data to a form, he can look at data in other form for reference.
It seems very cumbersome to switch back ansd forth between two forms just so you can enter data in one of them. If the data was that important to the second form, I would probably look into including that data on the new form in some form of making it so you don't have to reference another form. This could also be a sing that your data model is a bit too ... unorganized and cumbersome. When I design a layout, the user should have everything they need on a form so that decisions can be made to other options on the form.
|
|
|
|
|
Dave,
That's a good idea that each time only on form displayed.
I am also think about that if multiple child form opened together, user input data to one form, doesn't save it then switch to other form, it will cause mess.
Do you think it is good to open the child form as moduless, then either cancel form or fill in all data in the form when click OK?
|
|
|
|
|
Sorry, child form cannot be opened as moduless.
In this case, how about if user just fill in some data in a form, he didn't save it, then click other tree node?
|
|
|
|
|
First, are you just showing the child form in the tree node click event?
Because if you set it to nothing and then call frmChild1.Show() you'll get a null reference error.
You really shouldn't initialize the forms when the form is loaded, but do it when the tree node is clicked.
Then, when you create the child node, you need to hook the form closed event.
Personally, I wouldn't define the children forms to begin with, but would use a Dictionary to store them as you create them.
But, the code would look like:
frmChild1 = New frmChildForm1
AddHandler frmChild1.FormClosed, AddressOf ChildFormClosed
End Sub
Private Sub ChildFormClosed(ByVal sender as System.Object, ByVal e as System.Windows.Forms.FormClosedEventArgs)
CType(sender, Form).Dispose
If TypeOf sender Is frmChildForm1 Then
frmChild1 = Nothing
End If
End Sub
Again, that's not the way I would do it, but that's the way it looks like you want to.
|
|
|
|
|
William,
Thanks, it works fine.
But if you have better way, would please share with us.
|
|
|
|
|
I think you'll say the following code is better solution of your problem:
Private Sub TreeView1_NodeMouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeNodeMouseClickEventArgs) Handles TreeView1.NodeMouseClick
Select Case e.Node.Text
Case "Node0"
Dim frm As New Form1
frm.Name = "Form1"
frm.MdiParent = Me
Dim OldForm = System.Windows.Forms.Application.OpenForms(frm.Name)
If IsNothing(OldForm) Then
OldForm = frm
End If
If Not OldForm.Visible Then
frm.Show()
Else
OldForm.Show()
OldForm.Focus()
End If
Case "Node1"
Dim frm As New Form2
frm.Name = "Form2"
frm.MdiParent = Me
frm.Show()
Case Else
MsgBox("None")
End Select
End Sub
Use <pre lang="vb"> Visual Basic Code Here.</pre>
|
|
|
|
|
In my company we use an instrument that connects to our laptops via a USB-to-Serial bridge (the instrument only communications via RS232). Now, I have figured out how to communication with the instrument from a laptop, however I am trying to figure out how to communicate with it from a PPC (most of the employees have the iPaq but some have newer PDAs that run Windows Mobile).
Below is the sample code of how my laptop software communications with the instrument. Any idea on how to do this from the PPC would be greatly appreciated.
Dim SerialPort As SerialPort = New SerialPort(COMPort, 9600, Parity.None, 8, StopBits.One)
Dim ACK(1) As Byte
Public ENQ() As Byte = {&H5}
Public BEGIN() As Byte = {&H54}
Public DataBuffer(4096) As Byte
Dim SerialPortOK As Boolean = False
SerialPort.Open()
SerialPort.Write(ENQ, 0, ENQ.Length)
Threading.Thread.Sleep(2000)
If SerialPort.BytesToRead Then
SerialPort.Read(ACK, 0, 1)
If ACK(0) = &H6 Then
SerialPortOK = True
Else
MsgBox("The instrument returned an unexpected result. Please check the instrument and try again.", MsgBoxStyle.Exclamation + MsgBoxStyle.OkOnly, "Invalid Response")
SerialPort.Close()
End If
Else
MsgBox("The instrument did not respond. Please check that it is connected and set to download mode.", MsgBoxStyle.Exclamation + MsgBoxStyle.OkOnly, "No Response")
SerialPort.Close()
End If
If SerialPortOK Then
Download = New clsDownloadInstrument(FolderName, txtDownload.Text.Trim, InstrumentNumber, SerialPort)
Me.Enabled = False
Download.BeginDownload()
End If
|
|
|
|
|
I can probably help you on this, do the ppc's? have a serial port, and which version of Visual Studio are using?
Phil
Software Developer
http://www.yorkshirehumberit.co.uk
|
|
|
|
|
I'm using visual studio 2008. The PDA has a USB (Not serial) port on the bottom. I'm connecting the USB cable for the PDA to a ATEN USB-to-Serial Bridge, which is then connected to the instrument.
|
|
|
|
|
does the pda recognise the USB Bridge as a serial port in its device manager?
Phil
Software Developer
http://www.yorkshirehumberit.co.uk
|
|
|
|
|