6 Replies - 1054 Views - Last Post: 15 October 2011 - 05:59 PM Rate Topic: -----

#1 JesseLord  Icon User is offline

  • New D.I.C Head

Reputation: 5
  • View blog
  • Posts: 42
  • Joined: 24-May 10

question Macro Application Cleanup

Posted 12 October 2011 - 09:32 PM

Hey guys, as I've been programming I've noticed many times that I could do things better but didn't because I'm not exactly sure how. So I wrote this macro style application and I made two classes:
The First Class (Calls the second class so I can make more the one of them)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace BoydMouseMacro
{
    public partial class frmGetWindow : Form
    {
        //Class variables
        public string windowName;

        //Delegates
        public delegate bool EnumDelegate(IntPtr hWnd, int lParam);

        //Dll import
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "GetWindowText",
        ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);

        [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows",
        ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);

        public frmGetWindow()
        {
            InitializeComponent();
            // When the form is created update the list of open windows.
            listBox1.Items.Clear();
            var newWindowList = new List<string>();

            EnumDelegate filter = delegate(IntPtr hWnd, int lParam)
            {
                StringBuilder strbTitle = new StringBuilder(255);
                int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
                string strTitle = strbTitle.ToString();

                if (IsWindowVisible(hWnd) && string.IsNullOrEmpty(strTitle) == false)
                {
                    newWindowList.Add(strTitle);
                }
                return true;
            };

            if (EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero))
            {
                foreach (var item in newWindowList)
                {
                    //Now we want to add the titles and hwnd's to the
                    listBox1.Items.Add(item);
                    //Console.WriteLine(item);
                }
            }
            listBox1.Update();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();

            var newWindowList = new List<string>();

            EnumDelegate filter = delegate(IntPtr hWnd, int lParam)
            {
                StringBuilder strbTitle = new StringBuilder(255);
                int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
                string strTitle = strbTitle.ToString();

                if (IsWindowVisible(hWnd) && string.IsNullOrEmpty(strTitle) == false)
                {
                    newWindowList.Add(strTitle);
                }
                return true;
            };

            if (EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero))
            {
                foreach (var item in newWindowList)
                {
                    //Now we want to add the titles and hwnd's to the
                    listBox1.Items.Add(item);
                    //Console.WriteLine(item);
                }
            }
            listBox1.Update();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Create a new window and bring it to the front
            RedIncMouseMacro macroApp = new RedIncMouseMacro(listBox1.SelectedItems[0].ToString());
            macroApp.Show();
        }
    }
}



The Second Class (Obviously learning here)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Drawing;
using Microsoft.VisualBasic;
using System.IO;

namespace BoydMouseMacro
{
    public partial class RedIncMouseMacro : Form
    {
        private Button button1 = new Button();
        private Button button2 = new Button();
        private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
        private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
        private const UInt32 MOUSEEVENTF_RIGHTDOWN = 0x0008;
        private const UInt32 MOUSEEVENTF_RIGHTUP = 0x0010;
        private const UInt32 MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        private const UInt32 MOUSEEVENTF_MIDDLEUP = 0x0040;
        private const UInt32 SWP_SHOWWINDOW = 0x0040;
        private const UInt16 TENCOUNTCLICK = 10;
        static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
        static readonly IntPtr HWND_TOP = new IntPtr(0);
        static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
        static readonly string winDir = System.Environment.GetEnvironmentVariable("windir");

        /*
        LEFTDOWN   = 0x00000002,
        LEFTUP     = 0x00000004,
        MIDDLEDOWN = 0x00000020,
        MIDDLEUP   = 0x00000040,
        MOVE       = 0x00000001,
        ABSOLUTE   = 0x00008000,
        RIGHTDOWN  = 0x00000008,
        RIGHTUP    = 0x00000010,
        WHEEL      = 0x00000800,
        XDOWN      = 0x00000080,
        XUP        = 0x00000100
        */

        private List<MACROSTEP> mMacroHolder = new List<MACROSTEP>();
        private bool mCanRecord = false;
        private bool mIsPaused = false;
        private bool mClickThrough = true;
        private int mRecordTimeWait = 250;
        private Rectangle mBoydWindow = new Rectangle();
        private int WorkStatus;
        private POINTAPI p = new POINTAPI();
        private Thread t;

        //The two windows hWnd's so I can switch between them.
        private IntPtr mBoydWindowHandle;
        private IntPtr mMacroWindowhandle;

        //Created Structs for basic Rect structure
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }

        //Created a public struct for a Point
        public struct POINTAPI
        {
            public int x; public int y;
        }

        //Created Struct for Basic MacroStep
        [StructLayout(LayoutKind.Sequential)]
        public struct MACROSTEP
        {
            //In the macro step you can left click right click
            //or push a key with a start time and end time
            public Point mPos;          // Store Left mouse button with coordiante
            public UInt32 leftOrRight;         // Store Right mouse button with coordinate
            public int mTime;        //Time in 1000's
        }

        //Enumeration flags for window position settings
        [Flags]
        public enum SetWindowPosFlags : uint
        {
            // ReSharper disable InconsistentNaming

            /// <summary>
            ///     If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
            /// </summary>
            SWP_ASYNCWINDOWPOS = 0x4000,

            /// <summary>
            ///     Prevents generation of the WM_SYNCPAINT message.
            /// </summary>
            SWP_DEFERERASE = 0x2000,

            /// <summary>
            ///     Draws a frame (defined in the window's class description) around the window.
            /// </summary>
            SWP_DRAWFRAME = 0x0020,

            /// <summary>
            ///     Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
            /// </summary>
            SWP_FRAMECHANGED = 0x0020,

            /// <summary>
            ///     Hides the window.
            /// </summary>
            SWP_HIDEWINDOW = 0x0080,

            /// <summary>
            ///     Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
            /// </summary>
            SWP_NOACTIVATE = 0x0010,

            /// <summary>
            ///     Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
            /// </summary>
            SWP_NOCOPYBITS = 0x0100,

            /// <summary>
            ///     Retains the current position (ignores X and Y parameters).
            /// </summary>
            SWP_NOMOVE = 0x0002,

            /// <summary>
            ///     Does not change the owner window's position in the Z order.
            /// </summary>
            SWP_NOOWNERZORDER = 0x0200,

            /// <summary>
            ///     Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
            /// </summary>
            SWP_NOREDRAW = 0x0008,

            /// <summary>
            ///     Same as the SWP_NOOWNERZORDER flag.
            /// </summary>
            SWP_NOREPOSITION = 0x0200,

            /// <summary>
            ///     Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
            /// </summary>
            SWP_NOSENDCHANGING = 0x0400,

            /// <summary>
            ///     Retains the current size (ignores the cx and cy parameters).
            /// </summary>
            SWP_NOSIZE = 0x0001,

            /// <summary>
            ///     Retains the current Z order (ignores the hWndInsertAfter parameter).
            /// </summary>
            SWP_NOZORDER = 0x0004,

            /// <summary>
            ///     Displays the window.
            /// </summary>
            SWP_SHOWWINDOW = 0x0040,

            // ReSharper restore InconsistentNaming
        }
        
        public delegate void UpdateTextCallback(string text);

        public RedIncMouseMacro(string applicationWindowName)
        {
            InitializeComponent();

            //Setting up our defaults
            button1.Location = new Point(5, 5);
            button1.TabIndex = 0;
            button1.Text = "Clear Current Macro";
            button1.AutoSize = true;
            button1.Click += new EventHandler(button1_Click);
            button2.Location = new Point(5, 35);
            button2.TabIndex = 0;
            button2.Text = "Play Macro";
            button2.AutoSize = true;
            button2.Click += new EventHandler(button2_Click);

            this.Click += new EventHandler(Form1_Click);
            this.DoubleClick += new EventHandler(Form1_DoubleClick);
            this.KeyDown += new KeyEventHandler(Form1_KeyDownCheck);
            this.Controls.Add(button1);
            this.Controls.Add(button2);
            checkBox1.Checked = true; //make the checkbox checked for able to click through.

            textBoxRecord.Text = mRecordTimeWait.ToString();

            //If the window is already running then lets just get its bounds and auto set ourselves up.
            mBoydWindowHandle = FindWindow(null, applicationWindowName);
            
            //Create our temp rectangle for the window
            RECT rct;

            if (!GetWindowRect(new HandleRef(this, mBoydWindowHandle), out rct))
            {
                MessageBox.Show("ERROR No window Specified.");
                //exit the application
                //TODO: write code to exit the application
                return;
            }
            
            mBoydwindow.X = rct.Left;
            mBoydwindow.Y = rct.Top;
            mBoydwindow.Width = rct.Right - rct.Left + 1;
            mBoydwindow.Height = rct.Bottom - rct.Top + 1;

            //move the mBoydWindow to 300 pixels to the right and 150 down from the top
            SetWindowPos(mBoydWindowHandle, HWND_TOP,
                300, 150, mBoydwindow.Width, mBoydwindow.Height,
                SetWindowPosFlags.SWP_SHOWWINDOW);

            //We need to recalculate the rect since we just moved the window.
            if (!GetWindowRect(new HandleRef(this, mBoydWindowHandle), out rct))
            {
                MessageBox.Show("ERROR No window Specified.");
                //exit the application
                //TODO: write code to exit the application
                return;
            }

            mBoydwindow.X = rct.Left;
            mBoydwindow.Y = rct.Top;
            mBoydwindow.Width = rct.Right - rct.Left + 1;
            mBoydwindow.Height = rct.Bottom - rct.Top + 1;

            //Make a windowHandle for this window
            mMacroWindowhandle = this.Handle;

            // Move and stretch the window to overlay the window, Not sure if this is on my system or others.
            SetWindowPos(mMacroWindowhandle, HWND_TOP, mBoydwindow.X - 300,
                 mBoydwindow.Y - 150, mBoydwindow.Width + 300, mBoydwindow.Height + 150,
                 SetWindowPosFlags.SWP_SHOWWINDOW);

            //Set t to a new thread on GetMyCursorPos so it is ready for use
            t = new Thread(new ThreadStart(GetMyCusorPos));

            //Start up the position check
            WorkStatus = 0;
            t.Start();
        }

        //Windows User32.dll built in functions that we need to borrow from in order to make the application work
        [DllImport("USER32.DLL")]
        private static extern void mouse_event(UInt32 dwFlags, UInt32 dx, UInt32 dy, UInt32 dwData, IntPtr dwExtraInfo);

        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassname, string lpWindowName);

        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags windowCode);

        [DllImport("user32.dll")]
        public static extern int GetCursorPos(ref POINTAPI lpPoint);

        //Update the mouse position text
        private void UpdateText(string text)
        {
            textBoxMousePos.Text = text;
        }

        private void GetMyCusorPos()
        {
            if (mBoydWindowHandle != IntPtr.Zero)
            {
                while (WorkStatus == 0)
                {
                    GetCursorPos(ref p);
                    textBoxMousePos.Invoke(new UpdateTextCallback(UpdateText),
                        new object[] { "X:" + p.x.ToString() + " Y:" + p.y.ToString() });

                    //runGuy.BackgroundImage.FrameDimensionsList;
                    Thread.Sleep(80);
                }
            }
        }

        //Clear the current macro!
        private void button1_Click(object sender, EventArgs e)
        {
            //Clear out the macro holder
            mMacroHolder.Clear();

            //Clear the listbox
            listBox1.Items.Clear();

            //Clear the text fields for the different items
            textBoxClick.Text = "";
            textBoxX.Text = "";
            textBoxY.Text = "";
            textBoxWait.Text = "";
        }

        //Send a key to the button when the user double-clicks anywhere on the form
        private void Form1_DoubleClick(object sender, EventArgs e)
        {
            //Prototype for keyboard command additions
            
        }

        //Helper mouse function
        public static void SendClick(Point location)
        {
            Cursor.Position = location;
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new IntPtr());
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new IntPtr());
        }

        public static void SendRightClick(Point location)
        {
            Cursor.Position = location;
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, new IntPtr());
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, new IntPtr());
        }

        public static void SendMiddleClick(Point location)
        {
            Cursor.Position = location;
            mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, new IntPtr());
            mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, new IntPtr());
        }

        private void PlayMacro()
        {
            //Rename the text on the button to notify the user
            button2.Text = "Starting in 5";
            button2.Update();
            Thread.Sleep(500);

            button2.Text = "Starting in 4";
            button2.Update();
            Thread.Sleep(500);

            button2.Text = "Starting in 3";
            button2.Update();
            Thread.Sleep(500);

            button2.Text = "Starting in 2";
            button2.Update();
            Thread.Sleep(500);

            button2.Text = "Starting in 1!!!";
            button2.Update();
            Thread.Sleep(500);

            //Check to make sure that we are not able to continue to record by disableing
            radioButton2.Checked = true;
            mCanRecord = false;

            button2.Text = "Move Mouse to Stop!";
            button2.Update();

            //Verify that the calculator is a running process.
            if (mBoydWindowHandle == IntPtr.Zero)
            {
                MessageBox.Show("The Boyd Application is not currently running");
                return;
            }

            SetForegroundWindow(mBoydWindowHandle);

            //If the count is already at 0 just break
            if (mMacroHolder.Count() == 0)
            {
                button2.Text = "Play Macro";
                return;
            }

            //Lets run the macro and watch the results
            for (int i = 0; i < mMacroHolder.Count(); i++)
            {
                //At this point we know where the mouse should be at all times
                //If the user moved the mouse then they must want to quit the macro.
                if (i > 0)
                {
                    if (Cursor.Position.X != mMacroHolder[i - 1].mPos.X && Cursor.Position.Y != mMacroHolder[i - 1].mPos.Y)
                    {
                        //Rename the text on the button to notify the user
                        button2.Text = "Play Macro";
                        break;
                    }
                }

                //Condition if repeat infinite amount is on
                if (mMacroHolder.Count() == i + 1)
                {
                    //Do the last command before restarting
                    if (mMacroHolder[i].leftOrRight == 1) //false is left true is right
                    {
                        //Right
                        SendRightClick(mMacroHolder[i].mPos);
                    }
                    else
                    {
                        //Left
                        SendClick(mMacroHolder[i].mPos);
                    }
                    Thread.Sleep(mMacroHolder[i].mTime);
                    i = 0;
                }

                //If the macro is paused then just wait.
                while( mIsPaused )
                {
                    button2.Text = "Paused";
                    button2.Update();
                    Thread.Sleep(500);
                }
                //Since its after the cancel check continue with the macro

                //Do the last command before restarting
                if (mMacroHolder[i].leftOrRight == 1) //false is left true is right
                {
                    //Right
                    SendRightClick(mMacroHolder[i].mPos);
                }
                else
                {
                    //Left
                    SendClick(mMacroHolder[i].mPos);
                }
                Thread.Sleep(mMacroHolder[i].mTime);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //Start playing the macro
            PlayMacro();
        }

        private void Form1_Click(object sender, EventArgs e)
        {
            MouseEventArgs fMouseEvent = (MouseEventArgs)e;
            //When the mouse gets clicked on the form record the position for later
            if (mCanRecord)
            {
                //Create the Temporary Macro Step holder
                MACROSTEP tempMacroStep = new MACROSTEP();

                //Do the recording of the mouse position immediatly
                Point tempPoint = new Point(Cursor.Position.X, Cursor.Position.Y);

                //Update the mRecordTimeWait
                mRecordTimeWait = Convert.ToInt32(textBoxRecord.Text);

                //If the mouse is able to click through then lets forward the click onto the window
                if (mClickThrough)
                {
                    SetForegroundWindow(mBoydWindowHandle);
                    Thread.Sleep(mRecordTimeWait);

                    //Ok make a method tree Middle Right does the left side
                    // Right on its own does the right tree
                    //Middle on its own does the

                    if (fMouseEvent.Button.ToString() == "Right")
                    {
                        SendRightClick(tempPoint); //Do the right click
                        tempMacroStep.mPos = tempPoint;
                        tempMacroStep.leftOrRight = 1; //Left is false right is true;
                    }
                    if (fMouseEvent.Button.ToString() == "Left")
                    {
                        SendClick(tempPoint); //Do the left click
                        tempMacroStep.mPos = tempPoint;
                        tempMacroStep.leftOrRight = 0; //Left is false right is true;   
                    }
                    Thread.Sleep(mRecordTimeWait);
                    SetForegroundWindow(mMacroWindowhandle);
                    tempMacroStep.mTime = Convert.ToInt32(Interaction.InputBox("Time Step Between Actions", "1 second is about (1000)", "250"));

                    //Add the Macro Step to the mMacroHolder
                    mMacroHolder.Add(tempMacroStep);

                    //Add the Macro Step to the listBox1
                    string tempString = "LOrR: " + tempMacroStep.leftOrRight.ToString() +
                        " X: " + tempMacroStep.mPos.X +
                        " Y: " + tempMacroStep.mPos.Y +
                        " Wait: " + tempMacroStep.mTime;
                    listBox1.Items.Add(tempString);
                }
                else
                {
                    //Click through is disabled so no need to do the window switching stuff.
                    if (fMouseEvent.Button.ToString() == "Right")
                    {
                        SendRightClick(tempPoint); //Do the right click
                        tempMacroStep.mPos = tempPoint;
                        tempMacroStep.leftOrRight = 1; //Left is false right is true;
                    }
                    if (fMouseEvent.Button.ToString() == "Left")
                    {
                        SendClick(tempPoint); //Do the left click
                        tempMacroStep.mPos = tempPoint;
                        tempMacroStep.leftOrRight = 0; //Left is false right is true;   
                    }
                    tempMacroStep.mTime = Convert.ToInt32(Interaction.InputBox("Time Step Between Actions", "1 second is about (1000)", "250"));

                    //Add the Macro Step to the mMacroHolder
                    mMacroHolder.Add(tempMacroStep);

                    //Update the Macro Step to the listBox1
                    string tempString = "LOrR: " + tempMacroStep.leftOrRight.ToString() +
                        " X: " + tempMacroStep.mPos.X +
                        " Y: " + tempMacroStep.mPos.Y +
                        " Wait: " + tempMacroStep.mTime;
                    listBox1.Items.Add(tempString);
                }
            }
            else
            {
                //I want to check for a middle mouse click that would bring the application forward
                if (fMouseEvent.Button.ToString() == "Middle")
                {
                    //Clicking on this button bring the window up as focus to allow adjustments
                    SetForegroundWindow(mBoydWindowHandle);
                }
            }
        }

        private void Form1_KeyDownCheck(object sender, KeyEventArgs e)
        {
            //Prototype Keyboard combinations are recorded here
            if (e.Alt && e.KeyCode == Keys.Q)
            {
                
            }
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            
            if (radioButton1.Checked == true)
            {
                mCanRecord = true;
            }
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            t = new Thread(new ThreadStart(GetMyCusorPos));
            if (radioButton2.Checked == true)
            {
                mCanRecord = false;
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked == true)
            {
                //Then make the bool for clicking through the form true
                mClickThrough = true;
            }
            else
            {
                //Make the bool for clicking through the form false.
                mClickThrough = false;
            }
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox2.Checked == true)
            {
                //Then the macro pauses at that step
                mIsPaused = true;
            }
            else
            {
                //We don't need to pause anymore so continue
                mIsPaused = false;
            }
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //copy the mMacroHolder values to the textboxes
            textBoxClick.Text = mMacroHolder[listBox1.SelectedIndex].leftOrRight.ToString();
            textBoxX.Text = mMacroHolder[listBox1.SelectedIndex].mPos.X.ToString();
            textBoxY.Text = mMacroHolder[listBox1.SelectedIndex].mPos.Y.ToString();
            textBoxWait.Text = mMacroHolder[listBox1.SelectedIndex].mTime.ToString();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //lets update the mMacroHolder with the values
            MACROSTEP tempMacroStep = new MACROSTEP();
            tempMacroStep.leftOrRight = Convert.ToUInt32(textBoxClick.Text);
            tempMacroStep.mPos.X = Convert.ToInt32(textBoxX.Text);
            tempMacroStep.mPos.Y = Convert.ToInt32(textBoxY.Text);
            tempMacroStep.mTime = Convert.ToInt32(textBoxWait.Text);
            mMacroHolder.Remove(mMacroHolder[listBox1.SelectedIndex]);// remove this step and then add the changed step.
            mMacroHolder.Insert(listBox1.SelectedIndex, tempMacroStep);

            //Update the listbox
            listBox1.Items.Clear();
            for (int i = 0; i < mMacroHolder.Count; i++)
            {
                string tempString = "LOrR: " + mMacroHolder[i].leftOrRight +
                    " X: " + mMacroHolder[i].mPos.X +
                    " Y: " + mMacroHolder[i].mPos.Y +
                    " Wait: " + mMacroHolder[i].mTime;
                listBox1.Items.Add(tempString);
            }
            //If the mMacroHolder has more then one item then select the first item on the list
            if( mMacroHolder.Count > 0)
                listBox1.SetSelected(0, true);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            //Clicking on this button bring the window up as focus to allow adjustments
            SetForegroundWindow(mBoydWindowHandle);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            //if they click this button then they want to modify the step selected
            mMacroHolder.Remove(mMacroHolder[listBox1.SelectedIndex]);

            //Update the list box
            listBox1.Items.Clear();
            for (int i = 0; i < mMacroHolder.Count; i++)
            {
                string tempString = "LOrR: " + mMacroHolder[i].leftOrRight +
                    " X: " + mMacroHolder[i].mPos.X +
                    " Y: " + mMacroHolder[i].mPos.Y +
                    " Wait: " + mMacroHolder[i].mTime;
                listBox1.Items.Add(tempString);
            }
            //If the mMacroHolder has more then one item then select the first item on the list
            if (mMacroHolder.Count > 0)
                listBox1.SetSelected(0, true);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            //Input what is currently in the text boxes to the list at insert point
            MACROSTEP tempMacroStep = new MACROSTEP();
            tempMacroStep.leftOrRight = Convert.ToUInt32(textBoxClick.Text);
            tempMacroStep.mPos.X = Convert.ToInt32(textBoxX.Text);
            tempMacroStep.mPos.Y = Convert.ToInt32(textBoxY.Text);
            tempMacroStep.mTime = Convert.ToInt32(textBoxWait.Text);
            mMacroHolder.Insert(listBox1.SelectedIndex, tempMacroStep);

            //Update the listbox
            listBox1.Items.Clear();
            for (int i = 0; i < mMacroHolder.Count; i++)
            {
                string tempString = "LOrR: " + mMacroHolder[i].leftOrRight +
                    " X: " + mMacroHolder[i].mPos.X +
                    " Y: " + mMacroHolder[i].mPos.Y +
                    " Wait: " + mMacroHolder[i].mTime;
                listBox1.Items.Add(tempString);
            }

            //If the mMacroHolder has more then one item then select the first item on the list
            if (mMacroHolder.Count > 0)
                listBox1.SetSelected(0, true);
        }

        private void RedIncMouseMacro_FormClosing(object sender, FormClosingEventArgs e)
        {
            //Do all cleanup here:
            //Turn off the position check
            WorkStatus = 1;
            if(t.IsAlive)
                t.Abort();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            //Ask for a file name to assoicate with the macro file
            string fInputText = Interaction.InputBox("Macro Save Menu", "Type in a name to assoicate your macro", "NoName");
            StreamWriter writer = new StreamWriter(fInputText + ".txt");
            writer.WriteLine(fInputText);
            for (int i = 0; i < mMacroHolder.Count; i++)
			{
			    writer.WriteLine(mMacroHolder[i].leftOrRight);
                writer.WriteLine(mMacroHolder[i].mPos.X);
                writer.WriteLine(mMacroHolder[i].mPos.Y);
                writer.WriteLine(mMacroHolder[i].mTime);
			}

            //Close out the file
            writer.Close();
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            //We want to load the file with the given file name
            string fInputText = Interaction.InputBox("Macro Load Menu", "Type in a name assoicated with your macro", "NoName");
            fInputText += ".txt"; //Adding the extension

            StreamReader reader = new StreamReader(fInputText);
            reader.ReadLine(); //Get the title of the macro out of the way

            MACROSTEP tempMacroStep = new MACROSTEP();
            try
            {
                do
                {
                    tempMacroStep.leftOrRight = Convert.ToUInt32(reader.ReadLine());
                    tempMacroStep.mPos.X = Convert.ToInt32(reader.ReadLine());
                    tempMacroStep.mPos.Y = Convert.ToInt32(reader.ReadLine());
                    tempMacroStep.mTime = Convert.ToInt32(reader.ReadLine());
                    
                    mMacroHolder.Add(tempMacroStep);
                }
                while (reader.Peek() != -1);
            }
            catch
            {
                //This means that the file is empty
            }
            finally
            {
                reader.Close(); //close out the file when done
            }

            //We are finished loading the file so lets update the list
            //Update the listbox
            listBox1.Items.Clear();
            for (int i = 0; i < mMacroHolder.Count; i++)
            {
                string tempString = "LOrR: " + mMacroHolder[i].leftOrRight +
                    " X: " + mMacroHolder[i].mPos.X +
                    " Y: " + mMacroHolder[i].mPos.Y +
                    " Wait: " + mMacroHolder[i].mTime;
                listBox1.Items.Add(tempString);
            }

            //If the mMacroHolder has more then one item then select the first item on the list
            if (mMacroHolder.Count > 0)
                listBox1.SetSelected(0, true);
        }

        private void panel2_Click(object sender, EventArgs e)
        {
            Form1_Click(sender, e);
        }
    }
}



And I ended up at a point where I'm like, this doesn't look structured. There has to be a better way to do that thread because it keeps crashing when I close the application. I think I'm posting because I'm proud of myself for getting this far but I know that I really need some opinions on what to change to make it flow better and look cleaner. Any help is much appreciated,

Is This A Good Question/Topic? 0
  • +

Replies To: question Macro Application Cleanup

#2 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5509
  • View blog
  • Posts: 11,814
  • Joined: 02-June 10

Re: question Macro Application Cleanup

Posted 13 October 2011 - 06:58 AM

See FAQ #13 for threading tutorials


FAQ (Frequently Asked Questions - Updated Sep 2011

Spoiler



Let me also throw in a couple tips:
  • You have to program as if everything breaks, nothing works, the cyberworld is not perfect, the attached hardware is flakey, the network is slow and unreliable, the harddrive is about to fail, every method will return an error and every user will do their best to break your software. Confirm everything. Range check every value. Make no assumptions or presumptions.

  • Take the extra 3 seconds to rename your controls each time you drag them onto a form. The default names of button1, button2... button54 aren't very helpful. If you rename them right away to something like btnOk, btnCancel, btnSend etc. it helps tremendously when you make the methods for them because they are named after the button by the designer.btnSend_Click(object sender, eventargs e) is a lot easier to maintain than button1_click(object sender, eventargs e)

  • You aren't paying for variable names by the byte. So instead of variables names of a, b, c go ahead and use meaningful names like Index, TimeOut, Row, Column and so on. You should avoid 'T' for the timer. Amongst other things 'T' is commonly used throughout C# for Type and this will lead to problems. There are naming guidelines you should follow so your code confirms to industry standards. It makes life much easier on everyone around you, including those of us here to help. If you start using the standards from the beginning you don't have to retrain yourself later.

  • Try to avoid having work actually take place in GUI control event handlers. It is usually better to have the GUI handler call other methods so those methods can be reused and make the code more readible.
    Spoiler

Was This Post Helpful? 1
  • +
  • -

#3 JesseLord  Icon User is offline

  • New D.I.C Head

Reputation: 5
  • View blog
  • Posts: 42
  • Joined: 24-May 10

Re: question Macro Application Cleanup

Posted 14 October 2011 - 09:13 PM

Hey tlhIn`toq, Thank you for the reference, I apologize for making you submit that quote. I particularly found this article interesting:
http://www.dreaminco...m_notifications

I also went to www.pluralsight-training.net and checked out C# Fundamentals - Part 1
http://www.pluralsig...csharp-generics

For some reason I'm sad that I haven't been able to learn all of this stuff yet. It just seems like so much stuff to learn :) Thank you for your direction. I have placed a + for your help. If you happen to have any other advice please feel free to point me around :) Thank you again!
Was This Post Helpful? 0
  • +
  • -

#4 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5509
  • View blog
  • Posts: 11,814
  • Joined: 02-June 10

Re: question Macro Application Cleanup

Posted 14 October 2011 - 09:53 PM

You seem to be doing some very detailed and old-style tracking of the mouse. It feels very 1980's. What is the actual goal here? The goal of OOP os to not micromanage your objects or you GUI but instead have each item take care of itself. Why do you feel you need to icromanage the mouse?

It doesnt seem like something a beginner trying to learn the language would come up with. It feels more like an assembly language coder trying to move to a modern coding language.
Was This Post Helpful? 1
  • +
  • -

#5 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5509
  • View blog
  • Posts: 11,814
  • Joined: 02-June 10

Re: question Macro Application Cleanup

Posted 14 October 2011 - 10:10 PM

The PlayMacro is just so "brute force" compared to some of the other code.
How about a loop that counts down? Then you can set it for 3 or 30

You are using thread.sleep a lot. Bad choice 99% of the time. NOTHING happens when the thread is asleep: not events, GUI updates, form reactions, zip, nada, nil, zilch.

It looks like you are trying to record and play back all the user actions from another window or application. Is that right? Is the other application one you wrote/are writing? Because if it is there are a lot of ways to record the actions taken without recording all the user events. This is very "QuickKeys" from the 1990's. Which it seems is still in business for modern OSes.
http://startly.com/

At $60 it is cheaper to buy the product unless you can write it in 45 minutes.
Was This Post Helpful? 1
  • +
  • -

#6 JesseLord  Icon User is offline

  • New D.I.C Head

Reputation: 5
  • View blog
  • Posts: 42
  • Joined: 24-May 10

Re: question Macro Application Cleanup

Posted 15 October 2011 - 05:35 PM

View PosttlhIn`toq, on 14 October 2011 - 09:53 PM, said:

You seem to be doing some very detailed and old-style tracking of the mouse. It feels very 1980's. What is the actual goal here? The goal of OOP is to not micromanage your objects or you GUI but instead have each item take care of itself. Why do you feel you need to micromanage the mouse?

It doesn’t seem like something a beginner trying to learn the language would come up with. It feels more like an assembly language coder trying to move to a modern coding language.

"Ok quick forward explanation" At my job I’m a supervisor over a staff of 20+ people and my fellow supervisors and I were sitting there doing automated processes again to make sure reporting was getting done right. (A combination of copying and pasting from an AS/400 screens to Excel and I was at the point where I had done this same click sequence about (150) times and was going crazy. I then made a promise to myself that I'd make a macro for it. I would have just searched for applications that do it, but then I wouldn’t be able to use it at work. Secondly, I'm doing a "Game Software Development" Bachelor’s Degree I wanted to see how far I've gotten. So I made this as kind of a test.
I figured out right away that there are many applications that I use that suck up mouse WM_INPUT requests so I couldn’t have my application listen to those in order to figure out the mouse position and which mouse click happened. So, after much thought I choose an alternate solution. I choose to make a form that overlays the window. I would put transparency on the form where the application would be placed inside the window. I record which mouse button got clicked on the form over the application (Left or Right) and I added to a list I then forward the event onto the application window by making it foreground and then submitting a mouse event(whichever was just recorded). I choose the “GetCursorPos” from the Windows API USER32.DLL as my solution because it was the only thing that seemed to work. I know that it is crude. If you know or can point me in a better direction I would seriously greatly appreciate it.
I figured I’d feel better about an application that just mimicked mouse position moves and clicks then actually trying to open up the application window and figuring out the buttons and submitting events to them.
I absolutely agree with the whole assembly language coder thing. That is one of the main reasons I posted in the first place. It just seems so ugly and I can’t really think of a better way to do it right now so I was hoping to tap into some experience and perhaps get another opinion or two, or more.
Was This Post Helpful? 0
  • +
  • -

#7 JesseLord  Icon User is offline

  • New D.I.C Head

Reputation: 5
  • View blog
  • Posts: 42
  • Joined: 24-May 10

Re: question Macro Application Cleanup

Posted 15 October 2011 - 05:59 PM

View PosttlhIn`toq, on 14 October 2011 - 10:10 PM, said:

The PlayMacro is just so "brute force" compared to some of the other code.
How about a loop that counts down? Then you can set it for 3 or 30

I figured a 2.5 second count down was sufficient for my needs but I agree that it would look nicer with something you can specify.

Quote

You are using thread.sleep a lot. Bad choice 99% of the time. NOTHING happens when the thread is asleep: not events, GUI updates, form reactions, zip, nada, nil, zilch.

I found out really quick that my Pause feature wasn’t exactly the most effective thing because of that :/ I was thinking that I could have a mode were the mouse and current active window would be recorded and restored at the end of each macro action. That way if I wanted to pause the macro I could just hit the pause button and if I wouldn’t lose functionality of my mouse. I felt like it would be a better user experience as well if they weren’t tied up doing the macro because the macro was taking care of itself. But I have no idea what I should use instead to over come that. Do you think the Timer object work work? On a background thread or something?

Quote

It looks like you are trying to record and play back all the user actions from another window or application. Is that right? Is the other application one you wrote/are writing? Because if it is there are a lot of ways to record the actions taken without recording all the user events. This is very "QuickKeys" from the 1990's. Which it seems is still in business for modern OSes.
http://startly.com/
At $60 it is cheaper to buy the product unless you can write it in 45 minutes.

Well, I guess this application is kind of like QuickKeys after reading about it. But I cannot purchase something on the budget to do that so I’m really better off coding it. Secondly, it isn’t a bad learning experience for me I don’t think.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1