Link to home
Start Free TrialLog in
Avatar of gvector1
gvector1

asked on

SetWindowLong in VB.NET

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??????
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

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.
Avatar of gvector1
gvector1

ASKER

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


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
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.
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#.
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
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???
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?
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
Hmmm...not sure if he wants ONE ~thing~ to be shared across all forms...

...or something he can drop on every form.
Yeah, Mike, that would be "any form", not a global thing, unless that's the way you want it.

Bob
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?
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.
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
I would still create Windows Control Library, but change it to inherit from Component???  Everything else should be the same right???
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
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?
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
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.
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.
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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