?
Solved

SetWindowLong in VB.NET

Posted on 2007-08-01
22
Medium Priority
?
2,798 Views
Last Modified: 2013-11-26
I recently attempted to make some conversions from VB6 to VB.NET and have run across a situation.  Previously in VB6, my code was calling SetWindowLong with the following declaration:
   
Public Declare Function SetWindowLong Lib "user32" _
          Alias "SetWindowLongA" ( _
                                   ByVal hWnd As Long, _
                                   ByVal nIndex As Long, _
                                   ByVal dwNewLong As Long) As Long

In trying to convert it to VB.NET, I was having to make calls to SetWindowLong and changing the WindowProc which required the 3rd parameter to use a delegate in VB.NET.  Here is the signature that I ended up with.

    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Form1.d_WindowProc) As Integer

Here is the delegate I ended up with

    Public Delegate Function d_WindowProc(ByVal hWnd As Integer, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

And here is the call that I am making
            lpPrevWndFunc = SetWindowLong(Me.Handle.ToInt32, GWL_WNDPROC, AddressOf WindowProc)

where WindowProc is a public function.  So far so good except for the fact that later on in code (namely when the form is closed) the code trys to set the WindowProc back to what it was previously(which is stored in lpPrevWndFunc which is an Integer).  But now I can't pass an integer to the SetWindowLong Function.  How can I accomplish this??????
0
Comment
Question by:gvector1
  • 10
  • 7
  • 5
22 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 19613781
Can you show us the original VB6 code?

Depending on that code, there are sometimes OTHER .Net approaches that do the equivalent in a completely different way.
0
 

Author Comment

by:gvector1
ID: 19616662
Here is the origional VB6 Code:

Call to SetWindowLong within the Load Routine:
   lpPrevWndFunc = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WindowProc)

The call to SetWindowLong from within the Unload/Close routine:
    SetWindowLong( Me.hWnd, GWL_WNDPROC, lpPrevWndFunc)

WindowProc Routine:
  Public Function WindowProc( _
                           ByVal hWnd As Long, _
                           ByVal msg As Long, _
                           ByVal wParam As Long, _
                           ByVal lParam As Long) As Long
                      ........

The declaration to call SetWindowLong
  Public Declare Function SetWindowLong Lib "user32" _
          Alias "SetWindowLongA" ( _
                                   ByVal hWnd As Long, _
                                   ByVal nIndex As Long, _
                                   ByVal dwNewLong As Long) As Long


0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19617563
Overriding WndProc is significantly easier in VB.NET, then it was with VB6.

  Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    MyBase.WndProc(m)
  End Sub

Bob
0
Get quick recovery of individual SharePoint items

Free tool – Veeam Explorer for Microsoft SharePoint, enables fast, easy restores of SharePoint sites, documents, libraries and lists — all with no agents to manage and no additional licenses to buy.

 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 19617665
By "code", I meant what are you doing in your WindowProc() method?

Sometimes the functionality has been encapsulated into .Net controls already.

If not, Bob has shown that you can "subclass" a form in VB.Net without using APIs.
0
 

Author Comment

by:gvector1
ID: 19618764
Here is the first bit of the WindowProc Method I am using

      Public Function WindowProc(ByVal hWnd As Integer, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
            
            
Select Case msg
      Case Is = MM_MCI_CONTROL ' PSP Device detected
            Select Case HiWord(lParam) '// Get control device type from HIWORD of  Param
                  Case Is = MCICTRL_SRC_FSW
                        Select Case LoWord(lParam)
                              Case Is = MCICTRL_CMD_PLAY_PRESSED
                                    EventMsg = "FSW: play Pressed"
                              Case Is = MCICTRL_CMD_PLAY_RELEASED
                                    EventMsg = "FSW: Play Released"


What I am doing is trying to capture events triggered by a device hooked up to my machine.  It is a Philips Speechmike and I am trying to interface this device from my application.  The people from Philips sent me an old VB6 project showing me how to interact with the device.  Now I am trying to convert it to my current code and create a dll.  Currently I am moving from VB6 to VB.NET, but ultimately I want to get my code into C#.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 19618810
Ok.  It looks like Bob has already given you what is needed then.

Just use "m.Msg", instead of "msg" in your Select Case statement:

Public Class FormXXX

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case MM_MCI_CONTROL
                etc...
        End Select
        MyBase.WndProc(m)
    End Sub

End Class
0
 

Author Comment

by:gvector1
ID: 19620431
I am trying to develop this into a dll of some sort so that I can make use of this device on different forms.  How would you suggest I code it so that I can make use on multiple forms without having to code the entire proc of every form.  Should I write a dll with events, subscribe to the events, and in the WndProc routine of the form make a call to the dll proc and trigger the necessary events that are subscribed to???  Am I on the right track or would you suggest a different approach???
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 19620537
Sounds good in theory...but to be honest, I've never written a DLL so I don't the best way to go about it then.  I think you can use a hidden form in a DLL so you can have an easy WndProc to get to.

Any suggestions Bob?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19620601
I would create a Windows Control Library, where you would create a user control that inherits from UserControl, and provides properties, methods, and events.  Then, you can drop the control on any form and gain the functionality of the control.

Bob
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 19620626
Hmmm...not sure if he wants ONE ~thing~ to be shared across all forms...

...or something he can drop on every form.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19620674
Yeah, Mike, that would be "any form", not a global thing, unless that's the way you want it.

Bob
0
 

Author Comment

by:gvector1
ID: 19620774
That seems to be an approach I may shoot for.  That way any form I want to interface with my speechmike I would just drop the control on my form and make use of the events.  Am I correct in saying that I would have to override every forms WindowProc method to make the necessary call to my control's winProc in order to capture the event generated by my speechmike?
0
 

Author Comment

by:gvector1
ID: 19620917
One more thing.  When creating this as a control, should I just leave the design view alone and blank since the control is actually going to be invisible when used.  I know that some aftermarket controls that follow the same approach sometimes use just an Icon that identifies there control during design time, but then is invisible during run time.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19621429
If you are talking about an invisible component, then it would be better if you inherited from System.ComponentModel.Component.  This places the control down at the bottom of the form in the component container.

Bob
0
 

Author Comment

by:gvector1
ID: 19625073
I would still create Windows Control Library, but change it to inherit from Component???  Everything else should be the same right???
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19625091
Yes, a DLL can have both components and user controls.  It is a little different when inheriting from Component, though, so it should be a fun exercise.

Bob
0
 

Author Comment

by:gvector1
ID: 19625923
Just out of curiosity, is it possible to have my component automatically insert code into the WindowProc of the form I drop it on.  So if I drop this component onto a form, it will insert the necessary code in the form's wndproc routine to try and catch the necessary messages?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19626058
No, but you can implement an IMessageFilter to look at the messages that go to the form:

Using IMessageFilter to create a generic filter for operating system events
http://www.codeproject.com/csharp/IMessageFilterArticle.asp

What kind of messages are you looking for?  What is the end result of all this?  Can this be done more easily?  What kind of things are you trying to do with the form?

Bob
0
 

Author Comment

by:gvector1
ID: 19626194
I am trying to detect MCI events.  Here are a snippet of the custom WindowProc method that detects and reacts to the events:

public void WindowProc(System.Windows.Forms.Message m)
{
      switch (m.Msg)
      {
            // PSP Device detected
            case  MM_MCI_CONTROL:
            // Get control device type from HIWORD of lParam
            switch (HiWord(m.LParam.ToInt32()))
            {
               /// Case statement for SpeechMike
               case  MCICTRL_SRC_MIC:
               switch (LoWord(m.LParam.ToInt32()))
               {
                  case  MCICTRL_CMD_ERROR:
                        ExecuteErrorEvent();
                        break;
                  case  MCICTRL_CMD_RECORD_PRESSED:
                        ExecuteRecordPressedEvent();
                        break;
                  case  MCICTRL_CMD_RECORD_RELEASED:
                        ExecuteRecordReleasedEvent();
                        break;
                               }

That is along the lines of what I was planning on doing.  Have it coded so that I can drop the Component on my form, go through the designer to the events, double-click on the event I want to respond to and type in the code I want to execute when that event happens.  I am sorry if I am annoying you, but you have helped me out greatly and will be awarded the points.
0
 

Author Comment

by:gvector1
ID: 19626264
Interesting article you posted a link to.  It appears that code will capture events at an application level.  I am only needing to capture specific events at a form level.
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 2000 total points
ID: 19626654
You could do something like this:

    Dim filter As New MessageProcessor()
    filter.FormHandle = Me.Handle
    Application.AddMessageFilter(filter)

Public Class MessageProcessor
  Implements IMessageFilter

  Private m_formHandle As IntPtr

  Public Property FormHandle() As IntPtr
    Get
      Return m_formHandle
    End Get
    Set(ByVal value As IntPtr)
      m_formHandle = value
    End Set
  End Property

  Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage

    If m.HWnd = m_formHandle Then
      Select Case m.Msg
        ' PSP Device detected
        Case MM_MCI_CONTROL
          ' Get control device type from HIWORD of lParam
          Select Case HiWord(m.LParam.ToInt32())
            ' Case statement for SpeechMike
            Case MCICTRL_SRC_MIC
              Select Case LoWord(m.LParam.ToInt32())
                Case MCICTRL_CMD_ERROR
                  ExecuteErrorEvent()
                Case MCICTRL_CMD_RECORD_PRESSED
                  ExecuteRecordPressedEvent()
                Case MCICTRL_CMD_RECORD_RELEASED
                  ExecuteRecordReleasedEvent()
              End Select
          End Select
      End Select
    End If
  End Function

Bob
0
 

Author Comment

by:gvector1
ID: 19638563
Thanks for all of the help.  I will end this post and award you the points Bob.  I appreciate all of the help.  I would award more points if allowed as this info was helpful beyond the origional question.

Thanks Again,
Kendal
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Hello there! As a developer I have modified and refactored the unit tests which was written by fellow developers in the past. On the course, I have gone through various misconceptions and technical challenges when it comes to implementation. I would…
Loops Section Overview
Whether it be Exchange Server Crash Issues, Dirty Shutdown Errors or Failed to mount error, Stellar Phoenix Mailbox Exchange Recovery has always got your back. With the help of its easy to understand user interface and 3 simple steps recovery proced…
Suggested Courses
Course of the Month16 days, 10 hours left to enroll

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question