Synchronized scrolling for two Richtextboxes (C#) - c#

I'm in need of some help.
Currently I am working on a Script Editor in C# and I have two rich text boxes: programTextBox, where the whole text is and linesTextBox which counts and shows the number of lines.
I want them to scroll at the same time. I have done some search and I actually found some code which works, but if has a few problems. Here is the code:
public enum ScrollBarType : uint
{
SbHorz = 0,
SbVert = 1,
SbCtl = 2,
SbBoth = 3
}
public enum Message : uint
{
WM_VSCROLL = 0x0115
}
public enum ScrollBarCommands : uint
{
SB_THUMBPOSITION = 4
}
[DllImport("User32.dll")]
public extern static int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("User32.dll")]
public extern static int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
...
private void programTextBox_VScroll(object sender, EventArgs e)
{
int nPos = GetScrollPos(programTextBox.Handle, (int)ScrollBarType.SbVert);
nPos <<= 16;
uint wParam = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)nPos;
SendMessage(linesTextBox.Handle, (int)Message.WM_VSCROLL, new IntPtr(wParam), new IntPtr(0));
}
It works. Kind of. And you may ask: "What's the problem?". Well:
1) My program crashes when the total number of lines becomes about 2500. I get an overflow error.
2) If I move up and down by using the scrollbar instead of the mouse wheel, then my second rich text box (linesTextBox) will not follow the first one unless I release the scrollbar.

If an application scrolls the content of the window, it must also reset the position of the scroll box by using the SetScrollPos function
Have a look at this :
https://msdn.microsoft.com/en-in/library/aa926329.aspx
Also WM_VSCROLL message carries only 16 bits of scroll box position data this could be the reason u should try GetScrollInfo because it has 32 bits of scroll box pos data. This might give solution to both of your problems . Hope this helps...

Related

Looking to force Alt + Enter full screen and a forced zoom (Ctrl + Scroll) Inside of a console application in C#

Essentially cannot find and answer to this question, or if it is even possible.
I have a game I am creating for a class, and it simply looks better when forced full screen and when the zoom is set to a particular size. I was wonder if I could recreate this without the player being necessary to change it themselves.
ALT + ENTER Full screen
And
CTRL + Scroll wheel zoom
For a literal answer to your question on how to:
Send keys to go Fullscreen, and
Send a Ctrl+MouseWheel
You want some help from the Win32 interop to send keyboard & mouse messages to your console window.
using System.Runtime.InteropServices;
public class Win32
{
public const int VK_F11 = 0x7A;
public const int SW_MAXIMIZE = 3;
public const uint WM_KEYDOWN = 0x100;
public const uint WM_MOUSEWHEEL = 0x20A;
public const uint WHEEL_DELTA = 120;
public const uint MK_CONTROL = 0x00008 << 16;
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
As reference the magic numbers are from:
Virtual Keys (VK_*)
Window input messages (WM_*)
Mousewheel params (WHEEL_DELTA & MK_*)
and the ShowWindow params (SW_*)
You could then simply send your keypress and mousewheel like so:
using static Win32;
// Get window handle of the console
var hwnd = GetConsoleWindow();
// Go fullscreen by sending the F11 keydown message.
PostMessage(hwnd, WM_KEYDOWN, (IntPtr)VK_F11, IntPtr.Zero);
// Or maximize the window instead. Your users may not know how to get out of fullscreen...
/// ShowWindow(hwnd, SW_MAXIMIZE);
// Send mouse wheel message.
// MK_CONTROL: Holds the Ctrl key. WHEEL_DELTA: Positive=Up, Negative=Down.
PostMessage(hwnd, WM_MOUSEWHEEL, (IntPtr)(MK_CONTROL | WHEEL_DELTA), IntPtr.Zero);
Alternatively, as #JeremyLakerman mentioned in a comment to your question, you could set the console font to a larger size; which is a lot better, but also a bit more involved than sending Ctrl+MouseWheel.

Virtual ListView with artifacts in short list for Windows 8 and higher

I have a ListView in a Winform User Control. The VirtualMode is true and the VirtualListSize is 200. When there are less items in the ListView than visible rows, I get weird characters below the (real) items. These "artifacts" appear when the software is run on Windows 8, 10 or Windows Server 2012, but not on Windows 7.
Does anyone know what could be causing these "artifacts"? I added a character "A" "B", etc. to the Title of all the places where ListViewItems are created. So I know that none of the code in this user control is creating them. I added a sample solution that shows the problem below.
Sometimes they appear as chinese characters, sometimes just a random letter and character combination. Usually they are not longer than 4 characters.
[Update] It does not occur on the latest Version of Windows 10.
[Update2] I was able to reproduce the problem on a small sample solution. Find the zip file here.
I ended up assigning the number of visible lines of the ListView to the VirtualListSize property, whenever the number of items in the ListView changed.
I used the following class to determine the number of visible lines in the ListView:
public static class ListViewSizer
{
const UInt32 LVM_FIRST = 0x1000;
const UInt32 LVM_GETHEADER = (LVM_FIRST + 31);
private static int GetHeaderHeight(ListView listView)
{
Rect rect = new Rect();
IntPtr hwnd = SendMessage((IntPtr)listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
if (hwnd != null)
{
if (GetWindowRect(new System.Runtime.InteropServices.HandleRef(null, hwnd), out rect))
{
return rect.Bottom - rect.Top;
}
}
return -1;
}
public static int GetLastVisibleLine(ListView listView)
{
int firstVisibleIndex = listView.TopItem.Index;
int heightOfFirstItem = listView.GetItemRect(firstVisibleIndex, ItemBoundsPortion.Entire).Height;
// assuming each item has the same height (I think this is true for list view and details view)
const int DefaultVisibleLines = 11;
int visibleLines = heightOfFirstItem != 0 ? (int)Math.Ceiling((decimal)((listView.Height - GetHeaderHeight(listView)) / heightOfFirstItem)) : DefaultVisibleLines;
int lastVisibleIndexInDetailsMode = firstVisibleIndex + visibleLines;
return lastVisibleIndexInDetailsMode;
}
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool GetWindowRect(System.Runtime.InteropServices.HandleRef hwnd, out Rect lpRect);
[Serializable, System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
I know this is a bit of a hack. The artifacts would still be there, but you just can't see them anymore, because the ListView always has as many lines as can be displayed. This is the best I could come up with without changing the control.

How do I change the tab stop length for a textbox in visual studio?

I am making a code editor program for an old pocket PC I have, and I want to be able to change the size of the \t character in a multi-line textbox.
I have looked for a really long time and I found this EM_SETTABSTOPS which I am not entirely sure how to use that but I think it is what I need to use. Is this even possible to do?
In your form class code:
private const UInt32 EM_SETTABSTOPS = 0x00CB;
private const int unitsPerCharacter = 4;
[DllImport("CoreDll.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref IntPtr lParam);
then add a function
public static void SetTextBoxTabStopLength(TextBox tb, int tabSizeInCharacters)
{
// 1 means all tab stops are the the same length
// This means lParam must point to a single integer that contains the desired tab length
const uint regularLength = 1;
// A dialog unit is 1/4 of the average character width
int length = tabSizeInCharacters * unitsPerCharacter;
// Pass the length pointer by reference, essentially passing a pointer to the desired length
IntPtr lengthPointer = new IntPtr(length);
SendMessage(tb.Handle, EM_SETTABSTOPS, (IntPtr)regularLength, ref lengthPointer);
}
Then, after InitializeComponents(), call the function with your multiline textbox.
Source: http://www.pinvoke.net/default.aspx/user32.sendmessage

Virtual mouse click c#

I have an multithreaded application that needs to be able to preform multiple mouse click at the same time.
I have an IntPtr intptr to a process on which i need to send a mouse click to.
I have tried to find this information on the web and there are some examples which i have tried. But I have not got any of them to work.
As I understand the correct way to solv my issue is to use the function
SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
hWnd is the IntPtr to the process.
Msg is the wanted action, which I want a left click, int WM_LBUTTONDBLCLK = 0x0203;
IntPtr wParam is of no intrest to this problem ( as I understand)
And the coordinates to the click is in lParam.
I construct lParam like,
Int32 word = MakeLParam(x, y);
private int MakeLParam(int LoWord, int HiWord)
{
return ((HiWord << 16) | (LoWord & 0xffff));
}
But as you might understand, I cant get this to work.
My first question is, the coordinates are they within the window of this process or are
the absolut screen coordinates?
And my second question, what am I doing wrong?
I was trying to simulate mouse clicks in C# just recently, I wrote this little helper class to do the trick:
public static class SimInput
{
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo);
[Flags]
public enum MouseEventFlags : uint
{
Move = 0x0001,
LeftDown = 0x0002,
LeftUp = 0x0004,
RightDown = 0x0008,
RightUp = 0x0010,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
Absolute = 0x8000
}
public static void MouseEvent(MouseEventFlags e, uint x, uint y)
{
mouse_event((uint)e, x, y, 0, UIntPtr.Zero);
}
public static void LeftClick(Point p)
{
LeftClick((double)p.X, (double)p.Y);
}
public static void LeftClick(double x, double y)
{
var scr = Screen.PrimaryScreen.Bounds;
MouseEvent(MouseEventFlags.LeftDown | MouseEventFlags.LeftUp | MouseEventFlags.Move | MouseEventFlags.Absolute,
(uint)Math.Round(x / scr.Width * 65535),
(uint)Math.Round(y / scr.Height * 65535));
}
public static void LeftClick(int x, int y)
{
LeftClick((double)x, (double)y);
}
}
The coordinates are a fraction of 65535, which is a bit odd, but this class will handle that for you.
I'm not 100% sure I understand what you're trying to accomplish. But if you want to simulate mouse input then I'd recommend using the SendInput API.
You can provide an array of inputs to be inserted into the input stream.
See also: PInvoke reference
I don't understand why anyone would want to send multiple mouse clicks simultaneously. If it's to test your GUI, it's the wrong test. No one can physically click something multiple times in the same time space.
But going back to your question, using SendMessage won't help you, because it is basically a blocking call. Even if you tried to use PostMessage, you won't be able to accomplish simultaneous clicks, because the message queue is getting pumped from the UI thread and has messages popped off and handled sequentially.
I used this code to click left button in handle
public static void MouseLeftClick(Point p, int handle = 0)
{
//build coordinates
int coordinates = p.X | (p.Y << 16);
//send left button down
SendMessage(handle, 0x201, 0x1, coordinates);
//send left button up
SendMessage(handle, 0x202, 0x1, coordinates);
}
If you set no handle with calling - then it sends click to Desktop, so coordinates should be for whole screen, if you will set handle, then message will be sent to handle's window and you should set coordinates for window.
How about just using VirtualMouse? I use it in C# and it works great.
public partial class Form1 : Form
{
private VirtualMouse vm = new VirtualMouse();
public Form1()
{
InitializeComponent();
}
private void MouseClickHere(Point myPoint)
{
vm.ClickIt(myPoint, 150);
}
private void Clicker()
{
MouseClickHere(new Point(250,350));
}
}

Progress Bar in Setup Application

I have created a custom action for my setup project and have successfully implemented a form that displays a progress bar for a download step in my install (I'm using a WebClient in my custom action code). So I have two questions that relate to each other.
Is there any way to show a download progress bar in the main setup window rather than creating a separate form that I display as I have done? I would prefer this.
If not, then what can I do to cause my form to display in front of the actual setup window when I call form.ShowDialog()? I've also called BringToFront() on it which doesn't work either. It's there, but it's always behind the main setup window. Seems there has to be some way to get the correct z-order.
Thanks for your help.
So I gave up on the idea of integrating the progress bar into the actual installer screen, but it's just plain ridiculous what it takes to get the Windows Form to display on top. I have to get a handle to the installer Window and send it to the background because bringing the progress bar window forward simply won't work. I've moved to Mac development now so coming back to this is just frustrating. I remember thinking C# .NET was pretty cool. It's got NOTHING on Cocoa/Objective-C.
It's infuriating having a method called BringToFront() that simply ignores you. Why do I have to drop down to Windows API code to do something as fundamental to a GUI as managing the the Z-Order? Z-Order? Seriously?
In case you're wondering, here's what I ended up doing (via google):
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern bool SetWindowPos(
IntPtr hWnd, // window handle
IntPtr hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags); // window positioning flags
public const uint SWP_NOSIZE = 0x1;
public const uint SWP_NOMOVE = 0x2;
public const uint SWP_SHOWWINDOW = 0x40;
public const uint SWP_NOACTIVATE = 0x10;
[DllImport("user32.dll", EntryPoint = "GetWindow")]
public static extern IntPtr GetWindow(
IntPtr hWnd,
uint wCmd);
public const uint GW_HWNDFIRST = 0;
public const uint GW_HWNDLAST = 1;
public const uint GW_HWNDNEXT = 2;
public const uint GW_HWNDPREV = 3;
public static void ControlSendToBack(IntPtr control)
{
bool s = SetWindowPos(
control,
GetWindow(control, GW_HWNDLAST),
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
I get a handle to the installer window and then call ControlSendToBack() on it. It works, but it sends it to the very back. I tried another method that would just send it back one position, but this wouldn't work either. Windows programming--as good as it was in 1995. Cool.
Another way of doing this is to use a BackgroundWorker. You let the Background Worker handle the downloading of the file so it doesn't prevent the UI being updated.
See this link on donnetperls

Categories