Click here to Skip to main content
Email Password   helpLost your password?

Scrolling Around with the RichTextBox Control

Some of you may be saying about now, what the...!???!. Well, please read on. Because I actually had a need to vertically scroll multiple RichTextBox controls at the same time, with only one of the RichTextBoxes scrollbars controlling all three of them. Well that should be easy Right!, Yes and No, at least from what I have found so far.

I would like to say at this point, I welcome all the CP user's Input on this matter as I can get. As I searched around the internet, I found very little information on this matter.

Background

In the RichTextBox (and other controls), the scroll message VSCROLL/HSCROLL and THUMBPOSITION of the scroll bar are not inter-connected as one would expect. On a vertical line change up or down, or a horizontal character scroll right or left, the VSCROLL/HSCROLL messages fire an event and the scrollbar moves, but the new position of the thumb never gets sent. Instead, in the case of the RichTextBox, it fires the event RichTextBox1_VScroll (or _HScroll), but still with no thumb position information. This means in my case, "The Thumb has no Idea what the rest of the hand is doing."

This so far, is what I have come up with to deal with scrolling them. I haven't tried, but I think this will also work with other text controls as I did see some horizontal uses for this, including the following article here on CP.

MFC / C++ List Controls General - Synchronization of scrolling between two list controls By Alexander Khudyakov -

Using the code

It requires the use of two windows API functions, GetScrollPos and PostMessageA, and the infamous NativeWindow Class.

I chose Not to use the NativeWindow class at the last minute to send the GetScrollPos and PostMessageA messages because of a three line, cryptic explanation in the SDK Documentation that said: "Applications should not send these messages directly. Instead, they should use the GetScrollPos function. A window receives this message through its WindowProc function. Applications which implement a custom scroll bar control must respond to these messages for the GetScrollPos function to function properly." How this applies to the NativeWindow class I do not know yet, but I am seeking an answer if anyone knows off hand. My Original Intention was to Use the NativeWindow Class only.

I handled the GetScrollPos and PostMessageA using the RichTextBox VScroll/HScroll events.

    Private Sub RichTextBox1_VScroll( _ 
    ByVal sender As Object, ByVal e As System.EventArgs) _
      Handles RichTextBox1.VScroll
        Dim RTB1Position As Integer
        RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
        PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION +_
           &H10000 * RTB1Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION +_
           &H10000 * RTB1Position, 0)
    End Sub

And the WM_VSCROLL/WM_HSCROLL message's are handled by the NativeWindow Class.

    Public Sub sClass_WindowProcedure( _ 
    ByRef uMsg As Message) Handles sClass1.WindowProcedure, _
      sClass2.WindowProcedure, sClass3.WindowProcedure
        Select Case uMsg.Msg
            Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's

                If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                    'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))

                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                 End If
    '

    ' on to the next RTB.... ect.ect.


Points of Interest

There are a few small glitches to be aware of if you apply this to RichTextBoxes where the vertical line counts or the horizontal character counts are different. The scrollbars will get out of sync and won't resync until the Thumb or line Up event is fired again, sometimes moving it back to the last position in the richtextbox you selected. In the case of the Horizontal scroll it will make the shorter ones visibly "shake". But, this is not a problem in my application of this as all the Vertical line counts and the horizontal character counts are the same.

Also, Don't turn off the scroll bars in the property sheet, hide them under a panel control or something similar. The events won't fire on a disabled scrollbar and a handy "Object Not Set" Message will appear!.

Now, What I was Doing:

Sorry, You won't find the source code for this HexDumper/Editor in my submission. But, I will try to get it up here to CP when I get more of it finished, or in the mean time you could just help me with this one or create your own. It is based on the source code I submitted.

I submitted the one at the top of the page, because it shows both scroll directions and how they interact together.

The Full Code Listing

Option Explicit On 

Imports System
Imports System.IO
Imports System.Data
Imports System.Text
Imports System.Drawing
Imports System.Collections
Imports System.Windows.Forms
Imports System.Windows.Forms.Message
Imports System.Runtime.InteropServices.Marshal

Public Class Form1
    Inherits System.Windows.Forms.Form

    '"Windows Form Designer generated code removed here"


    '===================================================================

    ' for NativeWindow and PostMessageA

    '===================================================================

    Private Const WM_HSCROLL = &H114
    Private Const WM_VSCROLL = &H115
    Private Const WM_MOUSEWHEEL = &H20A
    Private Const WM_COMMAND = &H111
    Private Const WM_USER = &H400
    '===================================================================

    ' for GetScroll and PostMessageA

    '===================================================================

    Private Const SBS_HORZ = 0
    Private Const SBS_VERT = 1
    Private Const SB_THUMBPOSITION = 4
    '===================================================================

    ' for SubClassing

    '===================================================================

    Private WithEvents sClass1 As Subclass
    Private WithEvents sClass2 As Subclass
    Private WithEvents sClass3 As Subclass

    Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
        ' clear the rtb text

        RichTextBox1.Text = ""
        RichTextBox2.Text = ""
        RichTextBox3.Text = ""
        ' setup the sSubclass

        sClass1 = New Subclass(RichTextBox1.Handle)
        sClass2 = New Subclass(RichTextBox2.Handle)
        sClass3 = New Subclass(RichTextBox3.Handle)
        Dim i As Integer
        ' put some formated text in the RichTextBox's

        While i < 100
            RichTextBox1.AppendText(" this is a string " & i & vbCrLf)
            RichTextBox2.AppendText(" this is a string " & i & vbCrLf)
            RichTextBox3.AppendText(" this is a string " & i & vbCrLf)
            If i Mod 4 = 0 Then
                RichTextBox1.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
                RichTextBox2.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
                RichTextBox3.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
            End If
            i += 1
        End While
    End Sub
    Public Sub sClass_WindowProcedure( _ 
    ByRef uMsg As Message) Handles sClass1.WindowProcedure, _
     sClass2.WindowProcedure, sClass3.WindowProcedure
        Select Case uMsg.Msg
            Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's

                If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                    'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))

                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                      uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
            Case WM_HSCROLL ' WM_HSCROLL Message's for RTB's

                If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                    'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))

                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _ 
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
        End Select
    End Sub

    Private Sub RichTextBox1_VScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
        Dim RTB1Position As Integer
        RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
        PostMessageA(RichTextBox2.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
    End Sub
    Private Sub RichTextBox2_VScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox2.VScroll
        Dim RTB2Position As Integer
        RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_VERT)
        PostMessageA(RichTextBox1.Handle, WM_VSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
    End Sub
    Private Sub RichTextBox3_VScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox3.VScroll
        Dim RTB3Position As Integer
        RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_VERT)
        PostMessageA(RichTextBox1.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
        PostMessageA(RichTextBox2.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
    End Sub
    Private Sub RichTextBox1_HScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox1.HScroll
        Dim RTB1Position As Integer
        RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_HORZ)
        PostMessageA(RichTextBox2.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
    End Sub
    Private Sub RichTextBox2_HScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox2.HScroll
        Dim RTB2Position As Integer
        RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_HORZ)
        PostMessageA(RichTextBox1.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
    End Sub

    Private Sub RichTextBox3_HScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox3.HScroll
        Dim RTB3Position As Integer
        RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_HORZ)
        PostMessageA(RichTextBox1.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
        PostMessageA(RichTextBox2.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
    End Sub
    '===================================================================

    ' API Function: GetScrollPos

    '===================================================================

    Private Declare Function GetScrollPos Lib "user32.dll" ( _
        ByVal hWnd As IntPtr, _
        ByVal nBar As Integer) As Integer
    '===================================================================

    ' API Function: PostMessageA

    '===================================================================

    Private Declare Function PostMessageA Lib "user32.dll" ( _
        ByVal hwnd As IntPtr, _
        ByVal wMsg As Integer, _
        ByVal wParam As Integer, _
        ByVal lParam As Integer) As Boolean
    '===================================================================

    ' Temporary Functions for the Debugger

    '===================================================================

    Public Function GetLowWord(ByRef pintValue As Int32) As Int32
        Return pintValue And &HFFFF
    End Function
    Public Function GetLowWord(ByRef pudtValue As IntPtr) As Int32
        Return GetLowWord(pudtValue.ToInt32)
    End Function
    Public Function GetHighWord(ByRef pintValue As Int32) As Int32
        If (pintValue And &H80000000) = &H80000000 Then
            Return ((pintValue And &H7FFF0000) \ &H10000) Or &H8000&
        Else
            Return (pintValue And &HFFFF0000) \ &H10000
        End If
    End Function
    '===================================================================

    ' End Temporary Functions for the Debugger

    '===================================================================

End Class

Public Class Subclass
    '===================================================================

    ' NativeWindow Subclassing

    '===================================================================

    Inherits System.Windows.Forms.NativeWindow
    Public Event WindowProcedure(ByRef uMsg As Message)

    Public Sub New(ByVal pWindowHandle As IntPtr)
        MyBase.AssignHandle(pWindowHandle)
    End Sub

    Protected Overrides Sub WndProc( _
     ByRef uMsg As System.Windows.Forms.Message)
        MyBase.WndProc(uMsg)
        RaiseEvent WindowProcedure(uMsg)
    End Sub

    Public Sub SendWndProc(ByRef uMsg As System.Windows.Forms.Message)
        MyBase.WndProc(uMsg)
    End Sub

End Class

Please, feel free to let me know if I'm re-inventing the wheel here, There might be a better way, And I could use the feedback.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionHow to change this code to Visual C++ Whidbey?
chrisliando
23:26 18 Feb '08  
I am using the Visual C++ 2005 Express Edition (Whidbey) and I have tried to convert the old C++ syntax but I was stucked in this part:

// ===================================================================
// NativeWindow Subclassing
// ===================================================================
__gc class Subclass : public System::Windows::Forms::NativeWindow
{
public:
__delegate void WindowsEventHandler(Object * sender, Message * uMsg);
__event WindowsEventHandler * NativeWindowsEvent;

Subclass(IntPtr pWindowHandle)
{
this->AssignHandle(pWindowHandle);
}

void SendWndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
}

protected: void WndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
if (NativeWindowsEvent != 0)
NativeWindowsEvent(this, uMsg);
}
};

The conversion:

// ===================================================================
// NativeWindow Subclassing
// ===================================================================
ref class Subclass : public System::Windows::Forms::NativeWindow
{
public: delegate void WindowsEventHandler(Object ^sender, Message ^uMsg);
event WindowsEventHandler^ NativeWindowsEvent;

Subclass(IntPtr pWindowHandle) {
this->AssignHandle(pWindowHandle);
}

void SendWndProc( System::Windows::Forms::Message ^uMsg ) {
this->WndProc(uMsg); //__super::WndProc(uMsg);
}

protected: void WndProc( System::Windows::Forms::Message ^uMsg ) {
this->WndProc(uMsg); //__super::WndProc(uMsg);
if ( NativeWindowsEvent != nullptr )
NativeWindowsEvent(this, uMsg);
}
//private: NativeWindowsEvent(Object^ sender, Message ^uMsg);

};

The error was on the bold part:
Error C3918: usage requires 'Project::Subclass::NativeWindowsEvent' to be a data member, see declaration of 'Project::Subclass::NativeWindowsEvent'

How to solve this?

Thank you very much.
Generalvery simple solution
tipiceberg
14:47 18 Dec '07  
A much shorter codeing
http://www.bokebb.com/dev/english/1954/posts/195437353.shtml[^]
GeneralCan you compile and run this code in vs 2005?
followthesun
7:25 4 Jan '07  
Hi, I tried to compile this code in vs 2005 and it does not work.
It seems hangs.

Can you help?

Thanks

Generalprogload, does your solution still work if RichTextBox is replaced with Panel
jgyie2
20:03 22 Aug '06  
Nice work.

I'd like to know if your solution still works when RichTextBoxes are replaced with Panels. E.g. there are 2 panels; each has a picturebox. However Panel doesn't have an Panel.VScroll/HScroll event. Do you have any solution to this issue? Thanks.

David ye
Generallot easier
tom-joad
4:22 24 Mar '06  

Try this solution from mike-obrien:

http://www.codeproject.com/vb/net/RTFSynchronizedScrolling.asp

Works fine for me.

Mike defines a class which does the whole work. This solution is much more flexible than any other i've seen.
You only have to integrate his class (clsRTFScrollSync) in your project and add a new instance of this class to your project:

Private objScrollSync As New clsRTFScrollSync

In the Form_Load event of your form you then have to add the Textboxes to be sychronized:

Private Sub Form1_Load(...)...
objScrollSync.ScrollBarToSync = ScrollBars.Vertical
objScrollSync.AddControl(RichTextBox1)
objScrollSync.AddControl(RichTextBox2)
End Sub

Thats all.

AnswerScrolling Test Code for VB2005
progload
11:31 24 Feb '06  
I haven't checked out all the new messaging system in VB2005 yet, but here is the new test code (based on the old code) that works in VS2005 if any one wants to give it a try.

'-------------------------------------------------------------

Option Explicit On

Imports System
Imports System.IO
Imports System.Data
Imports System.Text
Imports System.Drawing
Imports System.Collections
Imports System.Windows.Forms
Imports System.Windows.Forms.Message
Imports System.Runtime.InteropServices.Marshal

Public Class Form1
      Inherits System.Windows.Forms.Form

#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

      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 RichTextBox1 As System.Windows.Forms.RichTextBox
      Friend WithEvents RichTextBox2 As System.Windows.Forms.RichTextBox
      Friend WithEvents RichTextBox3 As System.Windows.Forms.RichTextBox
      <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.RichTextBox1 = New System.Windows.Forms.RichTextBox
            Me.RichTextBox2 = New System.Windows.Forms.RichTextBox
            Me.RichTextBox3 = New System.Windows.Forms.RichTextBox
            Me.SuspendLayout()
            '
            'RichTextBox1
            '
            Me.RichTextBox1.Location = New System.Drawing.Point(24, 24)
            Me.RichTextBox1.Name = "RichTextBox1"
            Me.RichTextBox1.Size = New System.Drawing.Size(128, 128)
            Me.RichTextBox1.TabIndex = 0
            Me.RichTextBox1.Text = "RichTextBox1"
            Me.RichTextBox1.WordWrap = False
            '
            'RichTextBox2
            '
            Me.RichTextBox2.Location = New System.Drawing.Point(160, 24)
            Me.RichTextBox2.Name = "RichTextBox2"
            Me.RichTextBox2.Size = New System.Drawing.Size(128, 128)
            Me.RichTextBox2.TabIndex = 1
            Me.RichTextBox2.Text = "RichTextBox2"
            Me.RichTextBox2.WordWrap = False
            '
            'RichTextBox3
            '
            Me.RichTextBox3.Location = New System.Drawing.Point(296, 24)
            Me.RichTextBox3.Name = "RichTextBox3"
            Me.RichTextBox3.Size = New System.Drawing.Size(128, 128)
            Me.RichTextBox3.TabIndex = 3
            Me.RichTextBox3.Text = "RichTextBox3"
            Me.RichTextBox3.WordWrap = False
            '
            'Form1
            '
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(448, 174)
            Me.Controls.Add(Me.RichTextBox3)
            Me.Controls.Add(Me.RichTextBox2)
            Me.Controls.Add(Me.RichTextBox1)
            Me.Name = "Form1"
            Me.Text = "Form1"
            Me.ResumeLayout(False)

      End Sub

#End Region
      '===================================================================
      ' for NativeWindow and PostMessageA
      '===================================================================
      Private Const WM_USER As Integer = &H400
      Private Const WM_COMMAND As Integer = &H111

      Private Const WM_HSCROLL As Integer = &H114
      Private Const WM_VSCROLL As Integer = &H115

      Private Const EN_UPDATE As Integer = &H400

      Private Const EM_GETTHUMB As Integer = &HBE

      Private Const SBS_HORZ As Integer = 0
      Private Const SBS_VERT As Integer = 1

      Private Const SB_THUMBPOSITION As Integer = 4
      '===================================================================
      ' for SubClassing
      '===================================================================
      Private WithEvents sClass1 As Subclass
      Private WithEvents sClass2 As Subclass
      Private WithEvents sClass3 As Subclass
      Private WithEvents sClassF As Subclass


      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            ' clear the rtb text
            RichTextBox1.Text = ""
            RichTextBox2.Text = ""
            RichTextBox3.Text = ""
            ' setup the sSubclass
            sClass1 = New Subclass(RichTextBox1.Handle)
            sClass2 = New Subclass(RichTextBox2.Handle)
            sClass3 = New Subclass(RichTextBox3.Handle)
            sClassF = New Subclass(Me.Handle)

            Dim i As Integer
            ' put some formated text in the RichTextBox's
            While i < 100
                  RichTextBox1.AppendText(" this is a string " & i & vbCrLf)
                  RichTextBox2.AppendText(" this is a string " & i & vbCrLf)
                  RichTextBox3.AppendText(" this is a string " & i & vbCrLf)
                  If i Mod 4 = 0 Then
                        RichTextBox1.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
                        RichTextBox2.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
                        RichTextBox3.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
                  End If
                  i += 1
            End While
      End Sub
      Public Sub sClass_WindowProcedure(ByRef uMsg As Message) Handles sClass1.WindowProcedure, sClass2.WindowProcedure, sClass3.WindowProcedure, sClassF.WindowProcedure
            Select Case uMsg.Msg
                  Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's
                        If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                              'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
                              RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass1.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass1.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                        If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                              RemoveHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass2.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass2.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                        If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                              RemoveHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass3.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass3.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                  Case WM_HSCROLL ' WM_HSCROLL Message's for RTB's
                        If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                              'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
                              RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass1.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass1.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                        If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                              RemoveHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass2.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass2.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                        If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                              RemoveHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
                              sClass3.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              sClass3.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
                              AddHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
                        End If
                  Case WM_COMMAND ' Form1 Command messages
                        If uMsg.LParam.Equals(RichTextBox1.Handle) Then
                              'Debug.WriteLine("Low: " & GetLowWord(uMsg.WParam.ToInt32))
                              'Debug.WriteLine("High: " & GetHighWord(uMsg.WParam.ToInt32))
                              Dim rtbUpdate As Integer = GetHighWord(uMsg.WParam.ToInt32)
                              'The EN_UPDATE notification message is sent when an
                              'edit control is about to redraw itself
                              'so we will look for the EN_UPDATE event message
                              If rtbUpdate = EN_UPDATE Then '(1024)
                                    'The EM_GETTHUMB message retrieves the position of the
                                    'scroll box (thumb) in the vertical scroll bar only.
                                    '(TODO: Why there is NO horizontal message I can find.)
                                    Dim msg1 As Message
                                    uMsg.Msg = EM_GETTHUMB
                                    msg1 = Message.Create(RichTextBox1.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero)
                                    ' send message
                                    RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                                    sClass1.SendWndProc(msg1)
                                    AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
                                    'Debug.WriteLine("Msg1.Result :" & msg1.Result.ToInt32)
                                    ' make sure we resend the message to rtb1 in case we're on rtb2 or rtb3
                                    SetScrollPos(RichTextBox1.Handle, SBS_VERT, msg1.Result.ToInt32, True)
                                    SetScrollPos(RichTextBox2.Handle, SBS_VERT, msg1.Result.ToInt32, True)
                                    SetScrollPos(RichTextBox3.Handle, SBS_VERT, msg1.Result.ToInt32, True)
                              End If
                        End If
            End Select
      End Sub

      Private Declare Function GetScrollPos Lib "user32.dll" ( _
            ByVal hWnd As IntPtr, _
            ByVal nBar As Integer) As Integer

      Private Declare Function SetScrollPos Lib "user32.dll" ( _
            ByVal hWnd As IntPtr, _
            ByVal nBar As Integer, _
            ByVal nPos As Integer, _
            ByVal bRedraw As Boolean) As Integer

      Private Declare Function PostMessageA Lib "user32.dll" ( _
            ByVal hwnd As IntPtr, _
            ByVal wMsg As Integer, _
            ByVal wParam As Integer, _
            ByVal lParam As Integer) As Integer

      'HScroll

      Private Sub RichTextBox1_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.HScroll
            If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
            If Me.RichTextBox1.ContainsFocus Then
                  Dim RTB1Position As Integer
                  RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_HORZ)
                  PostMessageA(RichTextBox2.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
                  PostMessageA(RichTextBox3.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
            End If
      End Sub
      Private Sub RichTextBox2_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox2.HScroll
            If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
            If Me.RichTextBox2.ContainsFocus Then
                  Dim RTB2Position As Integer
                  RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_HORZ)
                  PostMessageA(RichTextBox1.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
                  PostMessageA(RichTextBox3.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
            End If
      End Sub
      Private Sub RichTextBox3_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox3.HScroll
            If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
            If Me.RichTextBox3.ContainsFocus Then
                  Dim RTB3Position As Integer
                  RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_HORZ)
                  PostMessageA(RichTextBox1.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
                  PostMessageA(RichTextBox2.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
            End If
      End Sub

      'VScroll

      Private Sub RichTextBox1_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
            If Me.RichTextBox1.ContainsFocus Then
                  Dim RTB1Position As Integer
                  RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
                  PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
                  PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
            End If
      End Sub

      Private Sub RichTextBox2_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox2.VScroll
            If Me.RichTextBox2.ContainsFocus Then
                  Dim RTB2Position As Integer
                  RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_VERT)
                  PostMessageA(RichTextBox1.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
                  PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
            End If
      End Sub

      Private Sub RichTextBox3_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox3.VScroll
            If Me.RichTextBox3.ContainsFocus Then
                  Dim RTB3Position As Integer
                  RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_VERT)
                  PostMessageA(RichTextBox1.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
                  PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
            End If
      End Sub

      '===================================================================
      ' Temporary Functions for the Debugger
      '===================================================================
      Public Function GetLowWord(ByRef pintValue As Int32) As Int32
            Return pintValue And &HFFFF
      End Function
      Public Function GetLowWord(ByRef pudtValue As IntPtr) As Int32
            Return GetLowWord(pudtValue.ToInt32)
      End Function
      Public Function GetHighWord(ByRef pintValue As Int32) As Int32
            If (pintValue And &H80000000) = &H80000000 Then
                  Return ((pintValue And &H7FFF0000) \ &H10000) Or &H8000&
            Else
                  Return (pintValue And &HFFFF0000) \ &H10000
            End If
      End Function
      '===================================================================
      ' End Temporary Functions for the Debugger
      '===================================================================
End Class

Public Class Subclass
      '===================================================================
      ' NativeWindow Subclassing
      '===================================================================
      Inherits System.Windows.Forms.NativeWindow
      Public Event WindowProcedure(ByRef uMsg As Message)

      Public Sub New(ByVal pWindowHandle As IntPtr)
            MyBase.AssignHandle(pWindowHandle)
      End Sub

      Protected Overrides Sub WndProc(ByRef uMsg As System.Windows.Forms.Message)
            MyBase.WndProc(uMsg)
            RaiseEvent WindowProcedure(uMsg)
      End Sub

      Public Sub SendWndProc(ByRef uMsg As System.Windows.Forms.Message)
            MyBase.WndProc(uMsg)
      End Sub

End Class

'-----------------------------------------------------

progload


GeneralRe: C# 2005 Version
RedPhoenix.net
16:08 13 Jun '06  
//---------------------------------------------------------------------
public partial class FormPDetails : Form
{
//-----------------------------------------------------------------
public FormPDetails()
{
InitializeComponent();

sClass1 = new NativeWindowExt(txtHex.Handle);
sClass2 = new NativeWindowExt(txtRaw.Handle);
this.sClass1.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
this.sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
}

// Retrieves the current position of the scroll box (thumb) in the specified scroll bar.
[DllImport("user32.dll")]
private static extern int GetScrollPos(IntPtr hwnd, int nBar);
// Sets the position of the scroll box (thumb) in the specified scroll bar and,
// if requested, redraws the scroll bar to reflect the new position of the scroll box.
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hwnd, int nBar, int nPos, bool bRedraw);
// Places (posts) a message in the message queue associated with the thread that created
// the specified window and then returns without waiting for the thread to process the message.
[DllImport("user32.dll", EntryPoint = "PostMessageA")]
private static extern int PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

const int WM_USER = 0x400;
const int WM_COMMAND = 0x111;
const int WM_HSCROLL = 0x114;
const int WM_VSCROLL = 0x115;
const int EN_UPDATE = 0x400;
const int EM_GETTHUMB = 0xBE;
const int SBS_HORZ = 0x0;
const int SBS_VERT = 0x1;
const int SB_THUMBPOSITION = 4;

private NativeWindowExt sClass1, sClass2;

//-----------------------------------------------------------------
private void txtHex_HScroll(object sender, EventArgs e)
{
if(Control.MouseButtons == MouseButtons.Left)
return;
if(txtHex.ContainsFocus)
{
int iPos = GetScrollPos(txtHex.Handle, SBS_HORZ);
PostMessage(txtRaw.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);
}
}

//-----------------------------------------------------------------
private void txtHex_VScroll(object sender, EventArgs e)
{
if(txtHex.ContainsFocus)
{
int iPos = GetScrollPos(txtHex.Handle, SBS_VERT);
PostMessage(txtRaw.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);
}
}

//-----------------------------------------------------------------
private void txtRaw_HScroll(object sender, EventArgs e)
{
if(Control.MouseButtons == MouseButtons.Left)
return;
if(txtRaw.ContainsFocus)
{
int iPos = GetScrollPos(txtRaw.Handle, SBS_HORZ);
PostMessage(txtHex.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);
}
}

//-----------------------------------------------------------------
private void txtRaw_VScroll(object sender, EventArgs e)
{
if(txtRaw.ContainsFocus)
{
int iPos = GetScrollPos(txtRaw.Handle, SBS_VERT);
PostMessage(txtHex.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);
}
}

//-----------------------------------------------------------------
private int GetLowWord(int pIntValue)
{
return pIntValue & 0xFFFF;
}

//-----------------------------------------------------------------
private int GetLowWord(IntPtr pUdtValue)
{
return GetLowWord((int)pUdtValue.ToInt32());
}

//-----------------------------------------------------------------
private int GetHighWord(int pIntValue)
{
if((pIntValue & 0x80000000) == 0x80000000)
return ((pIntValue & 0x7FFF0000) / 0x10000) | 0x8000;
else return (int)(pIntValue & 0xFFFF0000) / 0x10000;
}

//-----------------------------------------------------------------
public void sClass_WindowProcedure(ref Message uMsg)
{
switch(uMsg.Msg)
{
case WM_VSCROLL:
{
if(uMsg.HWnd.Equals(txtHex.Handle))
{
sClass1.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass1.SendWndProc(Message.Create(txtHex.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));
sClass1.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
}
if(uMsg.HWnd.Equals(txtRaw.Handle))
{
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass2.SendWndProc(Message.Create(txtRaw.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
}
break;
}
case WM_HSCROLL:
{
if(uMsg.HWnd.Equals(txtHex.Handle))
{
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass2.SendWndProc(Message.Create(txtHex.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
}
if(uMsg.HWnd.Equals(txtRaw.Handle))
{
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass2.SendWndProc(Message.Create(txtRaw.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
}
break;
}
case WM_COMMAND:
{
if(uMsg.LParam.Equals(txtRaw.Handle))
{
int rtbUpdate = GetHighWord((int)uMsg.WParam.ToInt32());
if(rtbUpdate == EN_UPDATE)
{
Message msg1;
uMsg.Msg = EM_GETTHUMB;
msg1 = Message.Create(txtRaw.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero);
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass2.SendWndProc(msg1);
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
}
}
else if(uMsg.LParam.Equals(txtHex.Handle))
{
int rtbUpdate = GetHighWord((int)uMsg.WParam.ToInt32());
if(rtbUpdate == EN_UPDATE)
{
Message msg1;
uMsg.Msg = EM_GETTHUMB;
msg1 = Message.Create(txtHex.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero);
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
sClass2.SendWndProc(msg1);
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);
}
}
break;
}
}
}
}

//---------------------------------------------------------------------
public class NativeWindowExt : NativeWindow
{
//-----------------------------------------------------------------
public NativeWindowExt(IntPtr pWindowHandle)
{
this.AssignHandle(pWindowHandle);
}

public event WindowsEventHandler NativeWindowsEvent;
public delegate void WindowsEventHandler(ref Message uMsg);

//-----------------------------------------------------------------
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(NativeWindowsEvent != null)
NativeWindowsEvent(ref m);
}

//-----------------------------------------------------------------
public void SendWndProc(Message uMsg)
{
base.WndProc(ref uMsg);
}
}

NewsA simpler solution...
boneheadIII
6:49 4 Nov '05  
...to the thumb buttons not firing scroll events issue. I found this Code Project article trying to solve the above problem, not necessarily to synch multiple RichTextBoxes. The following link is a good solution for this issue. In case anyone is interested.

http://davidnetfrog.blogspot.com/2005_04_01_davidnetfrog_archive.html[^]
GeneralRe: A simpler solution...
progload
16:32 4 Nov '05  
Thank You,

Yes, I went to visit the blog a bit a go, He did shorten it up a bit in his C# code.

I appreciate it.

Thanks Again,

progload
GeneralMy system shows error on your code
vaibhav tiwari
8:34 25 Oct '05  
Hellow,
I am new for vb.net programing i like your project very much.But when i run your project then i get this message System.ArithmaticExecption occured in System.drawing.dll additionan information overflow and under flow in the arithmatic operation.Plz give me solution.Roll eyes
GeneralCode was originaly written for .Net 1.1
progload
16:28 4 Nov '05  
vaibhav tiwari,

I'm not sure what could cause that problem, unless maybe your using .Net 2.0 or 1.0.

None of this code was written for Version 2.0 or the old 1.0, and at this time I don't have 2.0 or the beta 2.0 .Net installed because I am still working on source projects in .Net 1.1 and I don't Install a Beta anything on a production machine.

I'll be glag to try help you if you can supply more info about that error, and what OS and Version of .Net you are using.

Thank you,

progload
Generalget height of contents?
frumbert
16:32 14 Aug '05  
The RichTextBox control is sometimes quite problematic for ascertaining the contents height. Solutions usually involve looking through each line of text in the control and adding font height of each line. Unfortunately richtext in particular can contain other things such as embedded graphics and spacing and so on that muck up this process.

Before delving into the mucky world of rtf codes, I'd thought there might be a shortcut to calculating the height of the content by looking at the scrollbar values on the control (of course, this would apply to any kind of control). Windows seems to internally know the height of the content so that it can calculate the correct height of the scroll thumb.

I wasn't able to understand all that goes on in your code re how to use user32.dll to read a controls scrolling height. Can you please explain or point me in the right direction for documentation?
GeneralRe: get height of contents?
progload
19:52 15 Aug '05  
frumbert,

Hi,

First thanks for your interest in the code I posted on Code project.

If you are interested in the SubClassing I used, here is a Microsoft HowTo on the subject:

HOW TO: Subclass Windows in Windows Forms by Using Visual Basic .NET

http://support.microsoft.com/default.aspx?scid=kb;en-us;311317[^]

And the Documentation for the RichEditControl May be found here:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols.asp[^]

And the Documentation for the ScrollBars May be found here:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/scrollbars/scrollbars.asp?frame=true[^]

I hope this helps you out,

Progload

Generaldoes not work with VB.net 2005 (2.0 framework)
Matt12344321
9:12 21 Jun '05  
For each of the uMsg.Create expressions I get the following warning: "Access of shared member or nested type through an instance; qualifying expression will not be evaluated."

msg1 = uMsg.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam)

the autocorrect wants to replace uMsg.Create with System.Windows.Forms.Message.Create

I have tried this but it doesn't work. Any ideas? It compiles fine but does not scroll at all.
GeneralRe: does not work with VB.net 2005 (2.0 framework)
progload
16:38 4 Nov '05  
Wow,

Matt I never saw this message posted before, realy sorry I missed it.

None of this code was written for Version 2.0 or the old 1.0, and at this time I don't have 2.0 production or the beta 2.0 .Net installed because I am still working on source projects in .Net 1.1 and I don't Install a Beta anything on a production machine.

When I'm done working on 1.1 production code, I'll go get 2.0 Installed and working and see what's up.

Sorry again,

progload


GeneralC++ Code
yy678
3:17 20 Apr '05  
#pragma once
//==================================================
// Form1.h
//==================================================
namespace TestMultScroll
{
using namespace System;
using namespace System::IO;
using namespace System::Data;
using namespace System::Text;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Runtime::InteropServices;

// ===================================================================
// NativeWindow Subclassing
// ===================================================================
__gc class Subclass : public System::Windows::Forms::NativeWindow
{
public:
__delegate void WindowsEventHandler(Object * sender, Message * uMsg);
__event WindowsEventHandler * NativeWindowsEvent;

Subclass(IntPtr pWindowHandle)
{
this->AssignHandle(pWindowHandle);
}

void SendWndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
}

protected: void WndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
if (NativeWindowsEvent != 0)
NativeWindowsEvent(this, uMsg);
}
};



// ===================================================================
// API Function: GetScrollPos()
// ===================================================================
[DllImport("user32.dll")]
extern int GetScrollPos(IntPtr hWnd, int nBar);
// ===================================================================
// API Function: PostMessageA()
// ===================================================================
[DllImport("user32.dll")]
extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);



///
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
///
public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}

protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}

private:System::ComponentModel::Container * components;
private: Subclass * sClass1 ;
private: Subclass * sClass2 ;
private: Subclass * sClass3 ;

public: System::Windows::Forms::RichTextBox * RichTextBox1 ;
public: System::Windows::Forms::RichTextBox * RichTextBox2 ;
public: System::Windows::Forms::RichTextBox * RichTextBox3 ;

// ===================================================================
// for NativeWindow and PostMessageA
// ===================================================================
__value enum NWConst {
SBS_HORZ = 0,
SBS_VERT = 1,
SB_THUMBPOSITION = 4,
WM_COMMAND = 0x111,
WM_HSCROLL = 0x114,
WM_VSCROLL = 0x115,
WM_MOUSEWHEEL = 0x20A,
WM_USER = 0x400
};


// ===================================================================

/// /// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

private:
void InitializeComponent()
{
this->RichTextBox1 = new System::Windows::Forms::RichTextBox ();
this->RichTextBox2 = new System::Windows::Forms::RichTextBox ();
this->RichTextBox3 = new System::Windows::Forms::RichTextBox ();
this->SuspendLayout();
//
// RichTextBox1
//
this->RichTextBox1->Location = System::Drawing::Point (24, 24);
this->RichTextBox1->Name = "RichTextBox1";
this->RichTextBox1->Size = System::Drawing::Size (128, 128);
this->RichTextBox1->TabIndex = 0;
this->RichTextBox1->Text = "RichTextBox1";
this->RichTextBox1->WordWrap = false;
//
// RichTextBox2
//
this->RichTextBox2->Location = System::Drawing::Point (160, 24);
this->RichTextBox2->Name = "RichTextBox2";
this->RichTextBox2->Size = System::Drawing::Size (128, 128);
this->RichTextBox2->TabIndex = 1;
this->RichTextBox2->Text = "RichTextBox2";
this->RichTextBox2->WordWrap = false;
//
// RichTextBox3
//
this->RichTextBox3->Location = System::Drawing::Point (296, 24);
this->RichTextBox3->Name = "RichTextBox3";
this->RichTextBox3->Size = System::Drawing::Size (128, 128);
this->RichTextBox3->TabIndex = 3;
this->RichTextBox3->Text = "RichTextBox3";
this->RichTextBox3->WordWrap = false;
//
// Form1
//
this->AutoScaleBaseSize = System::Drawing::Size (5, 13);
this->ClientSize = System::Drawing::Size (448, 174);
this->Controls->Add(this->RichTextBox3);
this->Controls->Add(this->RichTextBox2);
this->Controls->Add(this->RichTextBox1);
this->Name = "Form1";
this->Text = "Form1";
this->ResumeLayout(false);
this->Load += new System::EventHandler (this, Form1_Load);

this->RichTextBox1->VScroll += new System::EventHandler (this,RichTextBox1_VScroll);
this->RichTextBox2->VScroll += new System::EventHandler (this,RichTextBox2_VScroll);
this->RichTextBox3->VScroll += new System::EventHandler (this,RichTextBox3_VScroll);
this->RichTextBox1->HScroll += new System::EventHandler (this,RichTextBox1_HScroll);
this->RichTextBox2->HScroll += new System::EventHandler (this,RichTextBox2_HScroll);
this->RichTextBox3->HScroll += new System::EventHandler (this,RichTextBox3_HScroll);

}
void Form1_Load(System::Object * sender, System::EventArgs * e)
{
sClass1 = new Subclass(RichTextBox1->Handle);
sClass2 = new Subclass(RichTextBox2->Handle);
sClass3 = new Subclass(RichTextBox3->Handle);

this->sClass1->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);
this->sClass2->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);
this->sClass3->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);

for (int i = 0; i <= 100; i++)
{
String * msg;
if (i % 4 == 0)
{
msg = String::Format(" this is a longer string to force HScroll {0} \n", __box(i));
RichTextBox1->AppendText(msg);
RichTextBox2->AppendText(msg);
RichTextBox3->AppendText(msg);
}
else
{
msg = String::Format(" this is a string {0} \n", __box(i));
RichTextBox1->AppendText(msg);
RichTextBox2->AppendText(msg);
RichTextBox3->AppendText(msg);
}
}
}


public: void sClass_WindowProcedure(Object * sender, System::Windows::Forms::Message * uMsg)
{
switch (uMsg->Msg)
{
case (WM_VSCROLL):
case (WM_HSCROLL):

if (uMsg->HWnd == RichTextBox1->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox2);
x->Add(RichTextBox3);
ThumbScrollHandler(RichTextBox1, x, uMsg);
}
else if (uMsg->HWnd == RichTextBox2->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox1);
x->Add(RichTextBox3);
ThumbScrollHandler(RichTextBox2, x, uMsg);
}
else if (uMsg->HWnd == RichTextBox3->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox1);
x->Add(RichTextBox2);
ThumbScrollHandler(RichTextBox3, x, uMsg);
}
break;
}
}



private: void ThumbScrollHandler(RichTextBox * sender, ArrayList* receivers, Message * uMsg)
{
sClass2->NativeWindowsEvent -= new Subclass::WindowsEventHandler(this, sClass_WindowProcedure);
for (int i=0; iCount; i++)
{
RichTextBox * rtbox = dynamic_cast(receivers->get_Item(i));
Message msg = Message::Create(rtbox->Handle, uMsg->Msg, uMsg->WParam, uMsg->LParam);
sClass2->SendWndProc(&msg);
}
sClass2->NativeWindowsEvent += new Subclass::WindowsEventHandler(this, sClass_WindowProcedure);
}

private: void RichTextBox1_VScroll(Object * sender, System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox2);
richTextBoxes->Add( RichTextBox3);
VerticalScroll(RichTextBox1, richTextBoxes);
}

private: void RichTextBox2_VScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox3);
VerticalScroll(RichTextBox2, richTextBoxes);
}

private: void RichTextBox3_VScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox2);
VerticalScroll(RichTextBox3, richTextBoxes);
}

private: void RichTextBox1_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox2);
richTextBoxes->Add( RichTextBox3);
HorizontalScroll(RichTextBox1, richTextBoxes);
}

private: void RichTextBox2_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox3);
HorizontalScroll(RichTextBox2, richTextBoxes);
}

private: void RichTextBox3_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox2);
HorizontalScroll(RichTextBox3, richTextBoxes);
}



private: void VerticalScroll(RichTextBox * sender, ArrayList * receivers)
{
int position = GetScrollPos(sender->Handle, SBS_VERT);
for (int i=0; iCount; i++)
{
RichTextBox * rtbox = dynamic_cast(receivers->get_Item(i));
PostMessageA(rtbox->Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}

}

private: void HorizontalScroll(RichTextBox * sender, ArrayList * receivers)
{
int position = GetScrollPos(sender->Handle, SBS_HORZ);
for (int i=0; iCount; i++)
{
RichTextBox * rtbox = dynamic_cast(receivers->get_Item(i));
PostMessageA(rtbox->Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
};
}







//============================================
// Form1.cpp
//============================================

#include "stdafx.h"
#include "Form1.h"
#include
using namespace TestMultScroll;

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
System::Threading::Thread::CurrentThread->ApartmentState = System::Threading::ApartmentState::STA;
Application::Run(new Form1());
return 0;
}


GeneralRe: C++ Code
progload
19:43 20 Apr '05  
yy678,

Thank you for the conversion, good work.

progload
GeneralC# Code - Thanks to theRealCondor
progload
11:17 3 Oct '04  
I noticed Today that theRealCondor has posted a C# version here in the forum.
http://www.codeproject.com/script/comments/forums.asp?forumid=1649&select=912488&df=100&fr=2496.5#xx912488xx

Thanks again, for the work theRealCondor.

progload.

here it is again.

using System;
using System.IO;
using System.Data;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TestMultiScroll
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components = null;
public System.Windows.Forms.RichTextBox RichTextBox1 = null;
public System.Windows.Forms.RichTextBox RichTextBox2 = null;
public System.Windows.Forms.RichTextBox RichTextBox3 = null;

// ===================================================================
// for NativeWindow and PostMessageA
// ===================================================================
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_COMMAND = 0x111;
// ===================================================================
// for GetScroll and PostMessageA
// ===================================================================
private const int WM_USER = 0x400;
private const int SBS_HORZ = 0;
private const int SBS_VERT = 1;
// ===================================================================
// for SubClassing
// ===================================================================
private const int SB_THUMBPOSITION = 4;
private Subclass sClass1 = null;
private Subclass sClass2 = null;
private Subclass sClass3 = null;


public Form1()
{
InitializeComponent();
}

protected void Dispose(bool disposing)
{
if (disposing)
{
if ( !( (components == null)))
{
components.Dispose();
}
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code
private void InitializeComponent()
{
this.RichTextBox1 = new System.Windows.Forms.RichTextBox ();
this.RichTextBox2 = new System.Windows.Forms.RichTextBox ();
this.RichTextBox3 = new System.Windows.Forms.RichTextBox ();
this.SuspendLayout();
//
// RichTextBox1
//
this.RichTextBox1.Location = new System.Drawing.Point (24, 24);
this.RichTextBox1.Name = "RichTextBox1";
this.RichTextBox1.Size = new System.Drawing.Size (128, 128);
this.RichTextBox1.TabIndex = 0;
this.RichTextBox1.Text = "RichTextBox1";
this.RichTextBox1.WordWrap = false;
//
// RichTextBox2
//
this.RichTextBox2.Location = new System.Drawing.Point (160, 24);
this.RichTextBox2.Name = "RichTextBox2";
this.RichTextBox2.Size = new System.Drawing.Size (128, 128);
this.RichTextBox2.TabIndex = 1;
this.RichTextBox2.Text = "RichTextBox2";
this.RichTextBox2.WordWrap = false;
//
// RichTextBox3
//
this.RichTextBox3.Location = new System.Drawing.Point (296, 24);
this.RichTextBox3.Name = "RichTextBox3";
this.RichTextBox3.Size = new System.Drawing.Size (128, 128);
this.RichTextBox3.TabIndex = 3;
this.RichTextBox3.Text = "RichTextBox3";
this.RichTextBox3.WordWrap = false;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size (5, 13);
this.ClientSize = new System.Drawing.Size (448, 174);
this.Controls.Add(this.RichTextBox3);
this.Controls.Add(this.RichTextBox2);
this.Controls.Add(this.RichTextBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.Load += new System.EventHandler (Form1_Load);

this.RichTextBox1.VScroll += new System.EventHandler (RichTextBox1_VScroll);
this.RichTextBox2.VScroll += new System.EventHandler (RichTextBox2_VScroll);
this.RichTextBox3.VScroll += new System.EventHandler (RichTextBox3_VScroll);
this.RichTextBox1.HScroll += new System.EventHandler (RichTextBox1_HScroll);
this.RichTextBox2.HScroll += new System.EventHandler (RichTextBox2_HScroll);
this.RichTextBox3.HScroll += new System.EventHandler (RichTextBox3_HScroll);
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_Load(System.Object sender,System.EventArgs e)
{
sClass1 = new Subclass(RichTextBox1.Handle);
sClass2 = new Subclass(RichTextBox2.Handle);
sClass3 = new Subclass(RichTextBox3.Handle);
this.sClass1.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
this.sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
this.sClass3.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);

for (int i = 0; i <= 100; i++)
{
if (i % 4 == 0)
{
RichTextBox1.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
RichTextBox2.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
RichTextBox3.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
}
else
{
RichTextBox1.AppendText(" this is a string " + i + System.Environment.NewLine);
RichTextBox2.AppendText(" this is a string " + i + System.Environment.NewLine);
RichTextBox3.AppendText(" this is a string " + i + System.Environment.NewLine);
}
}
}

public void sClass_WindowProcedure(ref Message uMsg)
{
switch (uMsg.Msg)
{
case (WM_VSCROLL):
if (uMsg.HWnd.Equals(RichTextBox1.Handle))
{
ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox2.Handle))
{
ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox3.Handle))
{
ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
}
break;
case (WM_HSCROLL):
if (uMsg.HWnd.Equals(RichTextBox1.Handle))
{
ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox2.Handle))
{
ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox3.Handle))
{
ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
}
break;
}
}

private void ThumbScrollHandler(RichTextBox sender, RichTextBox[] receivers, ref Message uMsg)
{
sClass2.NativeWindowsEvent -= new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
foreach (RichTextBox receiver in receivers)
{
Message msg = Message.Create(receiver.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam);
sClass2.SendWndProc(ref msg);
}
sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
}
private void RichTextBox1_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
}

private void RichTextBox2_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
}

private void RichTextBox3_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
}

private void RichTextBox1_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
}

private void RichTextBox2_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
}

private void RichTextBox3_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
}

private void VerticalScroll(RichTextBox sender, RichTextBox[] receivers)
{
int position = GetScrollPos(sender.Handle, SBS_VERT);
foreach (RichTextBox receiver in receivers)
{
PostMessageA(receiver.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}

}
private void HorizontalScroll(RichTextBox sender, RichTextBox[] receivers)
{
int position = GetScrollPos(sender.Handle, SBS_HORZ);
foreach(RichTextBox receiver in receivers)
{
PostMessageA(receiver.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
// ===================================================================
// API Function: GetScrollPos()
// ===================================================================
[DllImport("user32.dll")]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
// ===================================================================
// API Function: PostMessageA()
// ===================================================================
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
}

// ===================================================================
// NativeWindow Subclassing
// ===================================================================
public class Subclass : System.Windows.Forms.NativeWindow
{
public event WindowsEventHandler NativeWindowsEvent;
public delegate void WindowsEventHandler(ref Message uMsg);
public Subclass(IntPtr pWindowHandle):base()
{
base.AssignHandle(pWindowHandle);
}

protected override void WndProc(ref System.Windows.Forms.Message uMsg)
{
base.WndProc(ref uMsg);
if (NativeWindowsEvent != null)
NativeWindowsEvent(ref uMsg);
}

public void SendWndProc(ref System.Windows.Forms.Message uMsg)
{
base.WndProc(ref uMsg);
}
}
}

GeneralUpdate
progload
13:46 13 Aug '04  
I have an addition to the code for making the "thumbs" on the vertical scrollbars sync. I should have a update re-written for the article by the end of the month, but if you need the code, drop me an email.


GeneralMinor Bug : Updation if ScrollBar Thumb
Jay_sh_s
0:25 2 Aug '04  
Hi Progload,

Just found one minor bug, i.e. when I scroll using scroll bar's thumb, the thumb of the active control gets continuously updated, where as other thumb of other controls do not get updated continuously.

Regards,

Jay.
GeneralRe: Minor Bug : Updation if ScrollBar Thumb
progload
9:04 2 Aug '04  
Thanks for the great reponse Jay,

I'll work on getting a C# version of this somtime soon, It will require a re-write as C# uses the NativeWindow class a slightly different way.

Also, the thumb message can be found in the EM_SCROLL messages, I'll track them down and try to add the code for that.

This was designed for use where you Wouldn't see the second and third vertical scroll bars in the UI as shown in the second picture, but I do see your point, the thumbs by themself's do not sync until you let off the mouse button.

Thanks,
ProgLoad

GeneralRequest for C# code for the project
Jay_sh_s
0:04 2 Aug '04  
Hi Progload,

This article will help the guys in syncronising the scrollable controls. I downloaded your project and tested it. It works fine. Great Job!!!!!But I am unable to grasp the details of overriding WndProc since I do not know VB.Net. I would appreciate if you upload the C# version of the code as well.

Regards,
Jay.
AnswerRe: Request for C# code for the project
Behind The Scene
5:00 14 Apr '07  
Learn both languages. That's what I did. As an analogy, when DVD-R and DVD+R came out, manufacturers simply supported both.

ROFLOLMFAO

GeneralAnother Scrolling Reference
progload
21:02 29 Jul '04  
Another Scrolling Reference:

Controlling scrolling with the API
By Matthew Hazlett
Posted 5 Feb 2004
Scrolling with the API.  

http://www.codeproject.com/vb/net/APIScroll.asp


Sorry Matthew, I would have referenced your code,
But I just noticed it today (july 29). When I update the code
I'll put In the reference to yours.

Progload


Last Updated 30 Jul 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010