It looks like the Problem is that every time I hit the 'Recompile All' button in HB all my variables get cleared and get assigned to new values on the stack/heap and a new thread gets created while I lose track of the old thread that keeps on running. I tried to run thread.abort(); in my plugin's finalizer but it doesn't look like it gets executed.
I tried different things, nothing worked, ran out of ideas.
Trying to make my plugin fool proof.
If anyone wants to look at my code and help me out I would appreciate it. I'm pretty new to C# and never ever played with threads before.
keyPollThread is the name of the thread and it executes ThreadLoop()
Plugin_Thread is the main plugin thread. I use it only to check if HB is running and exit the loop in ThreadLoop() if it isn't
I tried different things, nothing worked, ran out of ideas.
Trying to make my plugin fool proof.
If anyone wants to look at my code and help me out I would appreciate it. I'm pretty new to C# and never ever played with threads before.
keyPollThread is the name of the thread and it executes ThreadLoop()
Plugin_Thread is the main plugin thread. I use it only to check if HB is running and exit the loop in ThreadLoop() if it isn't
Code:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Diagnostics;
//using Microsoft.Aspnet.Snapin;
using System.Threading;
using Styx.Plugins.PluginClass;
using Styx.Logic.BehaviorTree;
using Styx.Helpers;
using Styx.WoWInternals;
namespace HighVoltz
{
public partial class FormHB_Toggle : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
///
true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.KeyBindButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// KeyBindButton
//
this.KeyBindButton.BackColor = System.Drawing.SystemColors.Control;
this.KeyBindButton.Location = new System.Drawing.Point(7, 12);
this.KeyBindButton.Name = "KeyBindButton";
this.KeyBindButton.Size = new System.Drawing.Size(175, 25);
this.KeyBindButton.TabIndex = 0;
this.KeyBindButton.Text = "Click to set Keybind";
this.KeyBindButton.UseVisualStyleBackColor = false;
this.KeyBindButton.Click += new System.EventHandler(this.KeyBindButton_Click);
this.KeyBindButton.KeyDown += new System.Windows.Forms.KeyEventHandler(this.KeyBindButton_KeyDown);
//
// FormHB_Toggle
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(194, 47);
this.Controls.Add(this.KeyBindButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormHB_Toggle";
this.Text = "Key Binding";
this.Load += new System.EventHandler(this.FormHB_Toggle_Load);
this.Shown += new System.EventHandler(this.FormHB_Toggle_Shown);
this.ResumeLayout(false);
}
#endregion
private bool keyBindMode = false;
private System.Windows.Forms.Button KeyBindButton;
public FormHB_Toggle()
{
InitializeComponent();
}
private void FormHB_Toggle_Load(object sender, EventArgs e)
{
}
private void KeyBindButton_Click(object sender, EventArgs e)
{
if (!keyBindMode)
{
KeyBindButton.BackColor = System.Drawing.SystemColors.GradientInactiveCaption;
KeyBindButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
KeyBindButton.Text = "Press key combination";
keyBindMode = true;
}
}
private void KeyBindButton_KeyDown(object sender, KeyEventArgs e)
{
// return if not changing keybinds.
if (!keyBindMode) return;
// convert modifier keys to string to be displayed on button
string keybindstring = (e.Shift ? "Shift " : "") + (e.Control ? "Ctrl " : "") + (e.Alt ? "Alt " : "");
KeyBindButton.Text = keybindstring;
if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey || e.KeyCode == Keys.Menu)
{
return;
}
// display numbers in button text correctly.
if (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)
{
keybindstring += e.KeyValue - 48;
}
else
{
keybindstring += e.KeyCode.ToString();
}
KeyBindButton.Text = keybindstring;
KeyBindButton.FlatStyle = System.Windows.Forms.FlatStyle.Standard;
KeyBindButton.BackColor = System.Drawing.SystemColors.Control;
keyBindMode = false;
HB_Toggle.SetKeyBind(e.KeyData);
}
private void FormHB_Toggle_Shown(object sender, EventArgs e)
{
// everything here has to do with displaying the current keybind on the button.
System.Windows.Forms.Keys vKey = HighVoltz.Properties.Settings.Default.Keybind;
if (vKey == 0)
{
KeyBindButton.Text = "Click to set Keybind";
}
else
{
// extract modifier keys
string keybindstring = ((vKey & Keys.Shift) != 0 ? "Shift " : "") + ((vKey & Keys.Control) != 0 ? "Ctrl " : "") + ((vKey & Keys.Alt) != 0 ? "Alt " : "");
// Shift = 0x00010000, Ctrl= 0x00020000, Alt = 0x00040000
// remove modifer bits
vKey ^= (Keys.Shift & vKey) | (Keys.Control & vKey) | (Keys.Alt & vKey);
// display numbers in button text correctly.
switch (vKey)
{
case Keys.D0:
keybindstring += "0";
break;
case Keys.D1:
keybindstring += "1";
break;
case Keys.D2:
keybindstring += "2";
break;
case Keys.D3:
keybindstring += "3";
break;
case Keys.D4:
keybindstring += "4";
break;
case Keys.D5:
keybindstring += "5";
break;
case Keys.D6:
keybindstring += "6";
break;
case Keys.D7:
keybindstring += "7";
break;
case Keys.D8:
keybindstring += "8";
break;
case Keys.D9:
keybindstring += "9";
break;
default:
keybindstring += vKey.ToString();
break;
}
KeyBindButton.Text = keybindstring;
}
}
}
public class KeyBindClass
{
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
private System.Windows.Forms.Keys _keyBind;
// these modifer bools are true if our keybind uses them. otherwise false.
private bool _shiftkey = false;
private bool _ctrlkey = false;
private bool _altkey = false;
public KeyBindClass()
{
Logging.Write("KeyBindClass(): ", "");
_keyBind = new System.Windows.Forms.Keys();
Logging.Write("-KeyBindClass(): ", "");
}
~KeyBindClass()
{
// never gets called?!?!?
Logging.Write("-finalizer(): ", "");
}
public KeyBindClass(System.Windows.Forms.Keys k)
{ // k holds both modifer and key so we need to extract the modifer
_shiftkey = (k & Keys.Shift) != 0 ? true : false;
_ctrlkey = (k & Keys.Control) != 0 ? true : false;
_altkey = (k & Keys.Alt) != 0 ? true : false;
// now we remove the modifer flags from k and assign it to _keybind.
_keyBind = (Keys.Shift & k) | (Keys.Control & k) | (Keys.Alt & k);
}
public System.Windows.Forms.Keys KeyBind
{
get { return _keyBind; }
set
{ // check for modifer flags
_shiftkey = (value & Keys.Shift) != 0 ? true : false;
_ctrlkey = (value & Keys.Control) != 0 ? true : false;
_altkey = (value & Keys.Alt) != 0 ? true : false;
// remove modifer bits
value ^= (Keys.Shift & value) | (Keys.Control & value) | (Keys.Alt & value);
_keyBind = value;
}
}
public static bool IsKeyDown(System.Windows.Forms.Keys vKey)
{
return (GetAsyncKeyState(vKey) != 0);
}
public bool PollKeys()
{ // checks button status and returns true if our beybind is pressed.
if (IsKeyDown(_keyBind) && (!(_shiftkey ^ IsKeyDown(Keys.ShiftKey))) &&
(!(_ctrlkey ^ IsKeyDown(Keys.ControlKey))) && (!(_altkey ^ IsKeyDown(Keys.Menu))))
{
return true;
}
return false;
}
}
public class HB_Toggle : HBPlugin
{
private readonly FormHB_Toggle _configForm = new FormHB_Toggle();
public override string Name { get { return "HB Toggle"; } }
public override string Author { get { return "HighVoltz"; } }
private readonly Version _version = new Version(1, 0);
public override Version Version { get { return _version; } }
public override string ButtonText { get { return "KeyBinding"; } }
public override bool WantButton { get { return true; } }
private static KeyBindClass _keyBind = new KeyBindClass();
private static bool _initalized = false;
// making a new thread because pulse() doesn't get called when bot is paused and it doesn't get called frequently
// enough to get acurrate key readings. thread terminates when HB terminates.
Thread keyPollThread = new Thread(new ThreadStart(ThreadLoop));
private static Thread Plugin_Thread = Thread.CurrentThread;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
private static IntPtr _wowHandle = ObjectManager.WoWProcess.MainWindowHandle;
// contains info about this plugin, used to determine if this plugin is enabled from my thread loop.
static private Styx.Plugins.PluginContainer myPlugin;
public HB_Toggle()
{
Logging.Write("_initalized:{0} ", _initalized);
}
~HB_Toggle()
{
// this never gets called?!?!?
// Logging.Write("in finalizer: _initalized:{0} ", _initalized);
Logging.Write("Aborting previous key poll thread : ", "");
keyPollThread.Abort();
// Logging.Write("Aborted previous key thread : ", "");
}
public override void OnButtonPress()
{
_configForm.ShowDialog();
}
public override void Pulse()
{
// run this once the program starts.
if (!_initalized)
{
Logging.Write("loadSettings: ", "");
loadSettings();
_initalized = true;
Logging.Write("Getting Plugin: ", "");
for (int i = 0; i < Styx.Plugins.PluginManager.Plugins.Count(); i++)
{
myPlugin = Styx.Plugins.PluginManager.Plugins[i];
if (myPlugin.Plugin.PluginName == "HB Toggle")
break;
}
Logging.Write("Starting Thread: ", "");
if (keyPollThread.IsAlive)
{
Logging.Write("Thread is still alive!: ", "");
}
keyPollThread.Start();
Logging.Write("Thread Started: ", "");
}
}
// this is being run in a new thread
public static void ThreadLoop()
{
//PluginContainer plug = Styx.Plugins.PluginManager.Plugins[1];
bool toggleControl = false;
// exit loop when main thread terminates.
while (Plugin_Thread.IsAlive && _initalized)
{
// if keybind is pressed and our wow window is the currently active window then toggle HB
IntPtr fgWinHwnd = GetForegroundWindow();
if (_keyBind.PollKeys() && !toggleControl && (_wowHandle == fgWinHwnd) && myPlugin.Enabled)
{
toggleControl = true;
Toggle();
}
else
{
toggleControl = false;
}
// Yield the rest of the time slice.
Thread.Sleep(75);
}
Logging.Write("Thread Terminated","");
}
private static void Toggle()
{
if (TreeRoot.IsRunning)
{
Logging.Write("Honorbuddy: {0}", "Off");
// MoveStop not working.
// WoWMovement.MoveStop();
TreeRoot.Stop();
Styx.Lua.DoString("UIErrorsFrame:AddMessage(\"HonorBuddy: OFF\", 1.0, 0.0, 0.0)");
//run UIErrorsFrame:AddMessage("HonorBuddy: ON")
}
else
{
Logging.Write("Honorbuddy: {0}", "On");
Styx.Lua.DoString("UIErrorsFrame:AddMessage(\"HonorBuddy: ON\", 0.1, 1.0, 0.1)");
TreeRoot.Start();
}
}
public static void SetKeyBind(System.Windows.Forms.Keys vKey)
{
_keyBind.KeyBind = vKey;
SaveKeybind(vKey);
}
private static void SaveKeybind(System.Windows.Forms.Keys vKey)
{
HighVoltz.Properties.Settings.Default.Keybind = vKey;
HighVoltz.Properties.Settings.Default.Save();
}
private static void loadSettings()
{
_keyBind.KeyBind = HighVoltz.Properties.Settings.Default.Keybind;
}
}
}
Last edited: