2019-04-27 09:23:41 -04:00
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Windows.Forms ;
using System.IO ;
using System.Drawing ;
using System.Diagnostics ;
using Microsoft.Win32 ;
namespace Rebuilder
{
class Rebuilder : Form
{
2019-04-29 00:56:06 -04:00
TableLayoutPanel advanced_grid ;
2019-04-27 09:23:41 -04:00
NumericUpDown turn_speed_control ;
2019-04-28 00:58:17 -04:00
NumericUpDown movement_speed_control ;
2019-04-27 09:23:41 -04:00
CheckBox redirect_saves ;
CheckBox run_fullscreen ;
2019-04-27 11:22:28 -04:00
CheckBox stay_active_when_window_is_defocused ;
2019-04-29 00:56:06 -04:00
CheckBox override_resolution ;
NumericUpDown res_width ;
NumericUpDown res_height ;
2019-04-28 01:12:43 -04:00
Button run_button ;
2019-04-29 10:26:03 -04:00
CheckBox advanced_button ;
2019-04-28 01:12:43 -04:00
Process p = null ;
string run_button_run = "Run" ;
string run_button_kill = "Kill" ;
2019-04-27 09:23:41 -04:00
Rebuilder ( ) {
Text = "Lego Island Rebuilder" ;
MaximizeBox = false ;
2019-04-27 11:32:30 -04:00
Icon = Icon . ExtractAssociatedIcon ( System . Reflection . Assembly . GetExecutingAssembly ( ) . Location ) ;
2019-04-27 09:23:41 -04:00
TableLayoutPanel grid = new TableLayoutPanel ( ) ;
grid . Dock = DockStyle . Fill ;
grid . ColumnCount = 2 ;
grid . AutoSize = true ;
2019-04-29 00:56:06 -04:00
2019-04-27 09:23:41 -04:00
// Create automatic evenly spaced layout
2019-04-29 00:56:06 -04:00
float f = 100f / grid . ColumnCount ;
2019-04-27 09:23:41 -04:00
for ( int i = 0 ; i < grid . ColumnCount ; i + + )
{
grid . ColumnStyles . Add ( new ColumnStyle ( SizeType . Percent , f ) ) ;
}
2019-04-29 00:56:06 -04:00
// Build standard layout
2019-04-27 09:23:41 -04:00
grid . SuspendLayout ( ) ;
int row = 0 ;
2019-04-29 00:56:06 -04:00
2019-04-27 09:23:41 -04:00
Label title = new Label ( ) ;
title . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
title . Text = "Lego Island Rebuilder" ;
title . Font = new Font ( title . Font , FontStyle . Bold ) ;
title . TextAlign = ContentAlignment . MiddleCenter ;
grid . Controls . Add ( title , 0 , row ) ;
grid . SetColumnSpan ( title , 2 ) ;
row + + ;
LinkLabel subtitle = new LinkLabel ( ) ;
subtitle . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
subtitle . Text = "by MattKC (itsmattkc.com)" ;
subtitle . TextAlign = ContentAlignment . MiddleCenter ;
subtitle . LinkClicked + = new System . Windows . Forms . LinkLabelLinkClickedEventHandler ( AuthorLinkClick ) ;
grid . Controls . Add ( subtitle , 0 , row ) ;
grid . SetColumnSpan ( subtitle , 2 ) ;
row + + ;
Label turn_speed_lbl = new Label ( ) ;
turn_speed_lbl . Text = "Turn Speed:" ;
turn_speed_lbl . Anchor = AnchorStyles . Left | AnchorStyles . Bottom ;
grid . Controls . Add ( turn_speed_lbl , 0 , row ) ;
turn_speed_control = new NumericUpDown ( ) ;
turn_speed_control . Minimum = 0 ;
2019-04-29 21:02:24 -04:00
turn_speed_control . Value = 1 ;
turn_speed_control . DecimalPlaces = 2 ;
2019-04-27 09:23:41 -04:00
turn_speed_control . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
grid . Controls . Add ( turn_speed_control , 1 , row ) ;
row + + ;
2019-04-28 00:58:17 -04:00
Label movement_speed_lbl = new Label ( ) ;
movement_speed_lbl . Text = "Movement Speed:" ;
movement_speed_lbl . Anchor = AnchorStyles . Left | AnchorStyles . Bottom ;
grid . Controls . Add ( movement_speed_lbl , 0 , row ) ;
movement_speed_control = new NumericUpDown ( ) ;
movement_speed_control . Minimum = 0 ;
2019-04-29 21:02:24 -04:00
movement_speed_control . Value = 1 ;
movement_speed_control . DecimalPlaces = 2 ;
2019-04-28 00:58:17 -04:00
movement_speed_control . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
grid . Controls . Add ( movement_speed_control , 1 , row ) ;
row + + ;
2019-04-27 09:23:41 -04:00
run_fullscreen = new CheckBox ( ) ;
run_fullscreen . Checked = true ;
run_fullscreen . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
run_fullscreen . Text = "Run in full screen" ;
grid . Controls . Add ( run_fullscreen , 0 , row ) ;
grid . SetColumnSpan ( run_fullscreen , 2 ) ;
row + + ;
2019-04-27 11:22:28 -04:00
stay_active_when_window_is_defocused = new CheckBox ( ) ;
stay_active_when_window_is_defocused . Checked = false ;
stay_active_when_window_is_defocused . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
stay_active_when_window_is_defocused . Text = "Stay active when window is defocused" ;
grid . Controls . Add ( stay_active_when_window_is_defocused , 0 , row ) ;
grid . SetColumnSpan ( stay_active_when_window_is_defocused , 2 ) ;
row + + ;
2019-04-27 09:23:41 -04:00
redirect_saves = new CheckBox ( ) ;
redirect_saves . Checked = true ;
redirect_saves . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
redirect_saves . Text = "Redirect save files to %APPDATA%" ;
grid . Controls . Add ( redirect_saves , 0 , row ) ;
grid . SetColumnSpan ( redirect_saves , 2 ) ;
row + + ;
2019-04-28 01:12:43 -04:00
run_button = new Button ( ) ;
run_button . Text = run_button_run ;
2019-04-27 09:23:41 -04:00
run_button . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
run_button . Click + = new System . EventHandler ( this . Run ) ;
2019-04-29 10:26:03 -04:00
run_button . Font = new Font ( run_button . Font , FontStyle . Bold ) ;
2019-04-27 09:23:41 -04:00
grid . Controls . Add ( run_button , 0 , row ) ;
2019-04-29 10:26:03 -04:00
advanced_button = new CheckBox ( ) ;
2019-04-29 00:56:06 -04:00
advanced_button . Text = "Advanced" ;
2019-04-29 10:26:03 -04:00
advanced_button . TextAlign = ContentAlignment . MiddleCenter ;
advanced_button . Appearance = System . Windows . Forms . Appearance . Button ;
2019-04-29 00:56:06 -04:00
advanced_button . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
2019-04-29 10:26:03 -04:00
advanced_button . CheckedChanged + = new EventHandler ( ToggleAdvanced ) ;
2019-04-29 00:56:06 -04:00
grid . Controls . Add ( advanced_button , 1 , row ) ;
grid . ResumeLayout ( true ) ;
// Build advanced layout
// Create automatic evenly spaced layout
advanced_grid = new TableLayoutPanel ( ) ;
advanced_grid . Visible = false ;
advanced_grid . Dock = DockStyle . Right ;
advanced_grid . ColumnCount = 2 ;
advanced_grid . AutoSize = true ;
f = 100f / advanced_grid . ColumnCount ;
for ( int i = 0 ; i < advanced_grid . ColumnCount ; i + + )
{
advanced_grid . ColumnStyles . Add ( new ColumnStyle ( SizeType . Percent , f ) ) ;
}
advanced_grid . SuspendLayout ( ) ;
row = 0 ;
override_resolution = new CheckBox ( ) ;
override_resolution . Text = "Override Resolution" ;
override_resolution . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
override_resolution . CheckedChanged + = new EventHandler ( ToggleOverrideResolution ) ;
advanced_grid . Controls . Add ( override_resolution , 0 , row ) ;
row + + ;
Label res_width_lbl = new Label ( ) ;
res_width_lbl . Text = "Width:" ;
res_width_lbl . Anchor = AnchorStyles . Left | AnchorStyles . Bottom ;
advanced_grid . Controls . Add ( res_width_lbl , 0 , row ) ;
res_width = new NumericUpDown ( ) ;
res_width . Enabled = false ;
res_width . Minimum = 0 ;
res_width . Maximum = int . MaxValue ;
res_width . Value = 640 ;
res_width . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
advanced_grid . Controls . Add ( res_width , 1 , row ) ;
row + + ;
Label res_height_lbl = new Label ( ) ;
res_height_lbl . Text = "Height:" ;
res_height_lbl . Anchor = AnchorStyles . Left | AnchorStyles . Bottom ;
advanced_grid . Controls . Add ( res_height_lbl , 0 , row ) ;
res_height = new NumericUpDown ( ) ;
res_height . Enabled = false ;
res_height . Minimum = 0 ;
res_height . Maximum = int . MaxValue ;
res_height . Value = 480 ;
res_height . Anchor = AnchorStyles . Left | AnchorStyles . Right ;
advanced_grid . Controls . Add ( res_height , 1 , row ) ;
row + + ;
Label advanced_warning_lbl = new Label ( ) ;
advanced_warning_lbl . Text = "WARNING: These features are experimental and often incomplete. Use at your own risk." ;
advanced_warning_lbl . Anchor = AnchorStyles . Top | AnchorStyles . Bottom | AnchorStyles . Left | AnchorStyles . Right ;
advanced_warning_lbl . Font = new Font ( advanced_warning_lbl . Font , FontStyle . Bold ) ;
advanced_grid . Controls . Add ( advanced_warning_lbl , 0 , row ) ;
advanced_grid . SetColumnSpan ( advanced_warning_lbl , 2 ) ;
advanced_grid . ResumeLayout ( true ) ;
// Set up tooltips
2019-04-27 09:23:41 -04:00
ToolTip tip = new ToolTip ( ) ;
2019-04-28 00:58:17 -04:00
tip . SetToolTip ( turn_speed_control , "Set the turn speed multiplier. Lego Island ties its turn speed to the frame rate which is too fast on modern PCs. Use this value to correct it.\n\n" +
2019-04-29 21:02:24 -04:00
"0.00 = No turning at all\n" +
"0.35 = Recommended for modern PCs\n" +
"1.00 = Lego Island's default" ) ;
2019-04-28 00:58:17 -04:00
tip . SetToolTip ( movement_speed_control , "Set the movement speed multiplier. This value does not affect other racers so it can be used to cheat (or cripple) your chances in races.\n\n" +
2019-04-29 21:02:24 -04:00
"0.00 = No movement at all\n" +
"1.00 = Lego Island's default" ) ;
2019-04-27 11:32:30 -04:00
tip . SetToolTip ( run_fullscreen , "Override the registry check and run Lego Island either full screen or windowed. " +
"Allows you to change modes without administrator privileges and registry editing." ) ;
2019-04-27 12:03:27 -04:00
tip . SetToolTip ( redirect_saves , "Redirect save data to a folder that's writable so games can be saved without administrator privileges.\n\n" +
"Saves will be stored in: " + Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) + "\\LEGO Island" ) ;
2019-04-27 11:32:30 -04:00
tip . SetToolTip ( stay_active_when_window_is_defocused , "Lego Island's default behavior is to pause all operations when defocused. " +
2019-04-27 12:14:33 -04:00
"This setting overrides that behavior and keeps Lego Island active even when unfocused.\n\n" +
"NOTE: This currently only works in windowed mode." ) ;
2019-04-27 09:23:41 -04:00
Controls . Add ( grid ) ;
2019-04-29 00:56:06 -04:00
Controls . Add ( advanced_grid ) ;
2019-04-27 09:23:41 -04:00
AutoSize = true ;
AutoSizeMode = AutoSizeMode . GrowAndShrink ;
ResumeLayout ( true ) ;
CenterToScreen ( ) ;
}
private void Write ( FileStream fs , byte [ ] bytes , long pos = - 1 )
{
if ( pos > - 1 )
{
fs . Position = pos ;
}
fs . Write ( bytes , 0 , bytes . Length ) ;
}
2019-04-27 11:22:28 -04:00
private void WriteByte ( FileStream fs , byte b , long pos = - 1 )
{
if ( pos > - 1 )
{
fs . Position = pos ;
}
fs . WriteByte ( b ) ;
}
2019-04-27 09:23:41 -04:00
private void WriteInt32 ( FileStream fs , Int32 integer , long pos = - 1 )
{
byte [ ] int_bytes = BitConverter . GetBytes ( integer ) ;
Write ( fs , int_bytes , pos ) ;
}
2019-04-29 21:02:24 -04:00
private void WriteFloat ( FileStream fs , float f , long pos = - 1 )
{
byte [ ] f_bytes = BitConverter . GetBytes ( f ) ;
Write ( fs , f_bytes , pos ) ;
}
2019-04-27 09:23:41 -04:00
private void WriteString ( FileStream fs , string s , long pos = - 1 )
{
byte [ ] str_bytes = System . Text . Encoding . ASCII . GetBytes ( s ) ;
Write ( fs , str_bytes , pos ) ;
}
private void Patch ( string dir )
{
2019-04-27 11:22:28 -04:00
using ( FileStream lego1dll = File . Open ( dir + "/LEGO1.DLL" , FileMode . Open , FileAccess . Write ) )
using ( FileStream isleexe = File . Open ( dir + "/ISLE.EXE" , FileMode . Open , FileAccess . Write ) )
2019-04-27 09:23:41 -04:00
{
2019-04-28 00:58:17 -04:00
// Write turn/movement speed hack (this frees up 12 bytes of code)
Write ( lego1dll , new byte [ ] { 0x7E , 0x04 , 0x2B , 0xD1 , 0xEB , 0x0C , 0x89 , 0xC8 , 0xF7 , 0xD8 , 0x39 , 0xD0 , 0x7E , 0x2F , 0x01 , 0xCA , 0x29 , 0xCE , 0x89 , 0x54 , 0x24 , 0x04 , 0xDB , 0x44 , 0x24 , 0x04 , 0x89 , 0x74 , 0x24 , 0x04 , 0xDA , 0x74 , 0x24 , 0x04 , 0x3D , 0xF0 , 0x00 , 0x00 , 0x00 , 0x74 , 0x0A , 0xC7 , 0x44 , 0x24 , 0x04 } , 0x54323 ) ;
2019-04-29 21:02:24 -04:00
WriteFloat ( lego1dll , ( float ) turn_speed_control . Value ) ;
Write ( lego1dll , new byte [ ] { 0xEB , 0x08 , 0xC7 , 0x44 , 0x24 , 0x04 } ) ;
WriteFloat ( lego1dll , ( float ) movement_speed_control . Value ) ;
Write ( lego1dll , new byte [ ] { 0xD8 , 0x4C , 0x24 , 0x04 , 0xD8 , 0x4C , 0x24 , 0x14 , 0xD9 , 0x5C , 0x24 , 0x04 , 0xD9 , 0x44 , 0x24 , 0x04 , 0x5E , 0x83 , 0xC4 , 0x04 , 0xC2 , 0x0C , 0x00 , 0xC7 , 0x44 , 0x24 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0xD9 , 0x44 , 0x24 , 0x04 , 0x5E , 0x83 , 0xC4 , 0x04 , 0xC2 , 0x0C , 0x00 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 } ) ;
2019-04-27 09:23:41 -04:00
if ( redirect_saves . Checked )
{
// Write patch to write saves to "AppData" instead of "Program Files"
2019-04-27 11:22:28 -04:00
Write ( lego1dll , new byte [ ] { 0xE9 , 0x61 , 0x9B , 0x09 , 0x00 } , 0x39300 ) ;
Write ( lego1dll , new byte [ ] { 0x53 , 0xBB , 0x79 , 0x3A , 0x0D , 0x10 , 0x89 , 0x5C , 0x24 , 0x08 , 0x56 , 0x8B , 0x01 , 0x57 , 0xE9 , 0x8C , 0x64 , 0xF6 , 0xFF } , 0xD2E66 ) ;
2019-04-27 09:23:41 -04:00
// New directory to write in (defaults to "%AppData%/LEGO Island")
string new_save_dir = Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) + "\\LEGO Island\\" ;
Directory . CreateDirectory ( new_save_dir ) ;
2019-04-27 11:22:28 -04:00
WriteString ( lego1dll , new_save_dir ) ;
2019-04-27 09:23:41 -04:00
}
2019-04-27 11:22:28 -04:00
if ( stay_active_when_window_is_defocused . Checked )
{
// Remove code that writes focus value to memory, effectively keeping it always true - frees up 3 bytes
Write ( isleexe , new byte [ ] { 0x90 , 0x90 , 0x90 } , 0x1363 ) ;
// Write DirectSound flags to allow audio to play while the window is defocused
WriteByte ( lego1dll , 0x80 , 0xB120B ) ;
WriteByte ( lego1dll , 0x80 , 0x5B96 ) ;
WriteByte ( lego1dll , 0x80 , 0xB1201 ) ;
WriteByte ( lego1dll , 0x80 , 0xADD43 ) ;
}
// This operation skips the registry check so full screen/window mode can be set without entering the registry
2019-04-27 09:23:41 -04:00
if ( run_fullscreen . Checked )
{
// Write all nops since full screen is enabled by default, frees up 13 bytes that were used to call the registry reading function
2019-04-27 11:22:28 -04:00
Write ( isleexe , new byte [ ] { 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 } , 0x1E03 ) ;
2019-04-27 09:23:41 -04:00
}
else
{
// Write 7 bytes to set the full screen value to 0, frees up 7 bytes of code that were used to call the registry reading function
2019-04-27 11:22:28 -04:00
Write ( isleexe , new byte [ ] { 0xC7 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 } , 0x1E03 ) ;
2019-04-27 09:23:41 -04:00
}
2019-04-29 10:26:03 -04:00
// INCOMPLETE: Resolution hack:
if ( override_resolution . Checked )
{
// Changes window size
WriteInt32 ( isleexe , ( Int32 ) res_width . Value , 0xE848 ) ;
WriteInt32 ( isleexe , ( Int32 ) res_height . Value , 0xE84C ) ;
// Changes D3D render size
WriteInt32 ( isleexe , ( Int32 ) res_width . Value - 1 , 0x4D0 ) ;
WriteInt32 ( isleexe , ( Int32 ) res_height . Value - 1 , 0x4D7 ) ;
}
2019-04-27 09:23:41 -04:00
}
}
2019-04-27 11:51:27 -04:00
private bool IsValidDir ( string dir )
{
return ( File . Exists ( dir + "/ISLE.EXE" ) & & File . Exists ( dir + "/LEGO1.DLL" ) ) ;
}
2019-04-29 00:56:06 -04:00
private void ToggleAdvanced ( object sender , EventArgs e )
{
2019-04-29 10:26:03 -04:00
advanced_grid . Visible = advanced_button . Checked ;
2019-04-29 00:56:06 -04:00
CenterToScreen ( ) ;
}
private void ToggleOverrideResolution ( Object sender , EventArgs e )
{
res_width . Enabled = override_resolution . Checked ;
res_height . Enabled = override_resolution . Checked ;
}
2019-04-27 09:23:41 -04:00
private void Run ( object sender , EventArgs e )
{
2019-04-28 01:12:43 -04:00
if ( p ! = null )
{
p . Kill ( ) ;
return ;
}
2019-04-27 09:23:41 -04:00
string temp_path = Path . GetTempPath ( ) + "lirebuild" ;
Directory . CreateDirectory ( temp_path ) ;
2019-04-27 11:51:27 -04:00
string [ ] possible_dirs = {
"C:/Program Files (x86)/Lego Island" ,
"C:/Program Files/Lego Island" ,
"/Program Files (x86)/Lego Island" ,
"/Program Files/Lego Island"
} ;
string dir = "" ;
for ( int i = 0 ; i < possible_dirs . Length ; i + + )
{
if ( IsValidDir ( possible_dirs [ i ] ) )
{
dir = possible_dirs [ i ] ;
break ;
}
}
if ( string . IsNullOrEmpty ( dir ) )
{
using ( OpenFileDialog ofd = new OpenFileDialog ( ) )
{
ofd . Filter = "ISLE.EXE|ISLE.EXE" ;
ofd . Title = "Where is Lego Island installed?" ;
while ( true )
{
if ( ofd . ShowDialog ( ) = = DialogResult . OK )
{
dir = Path . GetDirectoryName ( ofd . FileName ) ;
if ( IsValidDir ( dir ) )
{
break ;
}
else
{
MessageBox . Show (
"This directory does not contain ISLE.EXE and LEGO1.DLL." ,
"Failed to find critical files" ,
MessageBoxButtons . OK ,
MessageBoxIcon . Error
) ;
}
}
else
{
return ;
}
}
}
}
2019-04-27 09:23:41 -04:00
try
{
2019-04-28 00:58:17 -04:00
string [ ] dest_files = Directory . GetFiles ( temp_path ) ;
for ( int i = 0 ; i < dest_files . Length ; i + + )
{
File . Delete ( dest_files [ i ] ) ;
}
string [ ] src_files = Directory . GetFiles ( dir ) ;
for ( int i = 0 ; i < src_files . Length ; i + + )
2019-04-27 23:40:29 -04:00
{
2019-04-28 00:58:17 -04:00
File . Copy ( src_files [ i ] , temp_path + "/" + Path . GetFileName ( src_files [ i ] ) , true ) ;
2019-04-27 23:40:29 -04:00
}
2019-04-27 09:23:41 -04:00
}
catch
{
MessageBox . Show ( "Failed to patch files" , "Error" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
return ;
}
Patch ( temp_path ) ;
// Set new EXE's compatibility mode to 256-colors
2019-04-29 10:26:03 -04:00
using ( RegistryKey key = Registry . CurrentUser . OpenSubKey ( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers" , true ) )
2019-04-27 09:23:41 -04:00
{
key . CreateSubKey ( temp_path + "\\ISLE.EXE" ) ;
2019-04-29 10:26:03 -04:00
if ( run_fullscreen . Checked )
{
2019-05-01 21:42:25 -04:00
key . SetValue ( temp_path + "\\ISLE.EXE" , "DWM8And16BitMitigation" ) ;
2019-04-29 10:26:03 -04:00
}
else
{
2019-05-01 21:42:25 -04:00
key . SetValue ( temp_path + "\\ISLE.EXE" , "DWM8And16BitMitigation 256COLOR" ) ;
2019-04-29 10:26:03 -04:00
}
2019-04-27 09:23:41 -04:00
}
ProcessStartInfo start_info = new ProcessStartInfo ( temp_path + "/ISLE.EXE" ) ;
2019-04-27 11:51:27 -04:00
start_info . WorkingDirectory = dir ;
2019-05-01 21:42:25 -04:00
try
{
p = Process . Start ( start_info ) ;
}
catch
{
p = null ;
return ;
}
2019-04-28 01:12:43 -04:00
p . EnableRaisingEvents = true ;
p . Exited + = new EventHandler ( ProcessExit ) ;
run_button . Text = run_button_kill ;
}
2019-04-27 09:23:41 -04:00
2019-04-28 01:12:43 -04:00
private void ProcessExit ( object sender , EventArgs e )
{
run_button . BeginInvoke ( ( MethodInvoker ) delegate ( ) { run_button . Text = run_button_run ; } ) ;
p = null ;
2019-04-27 09:23:41 -04:00
}
private void AuthorLinkClick ( object sender , System . Windows . Forms . LinkLabelLinkClickedEventArgs e )
{
( ( LinkLabel ) sender ) . LinkVisited = true ;
Process . Start ( "http://www.itsmattkc.com/" ) ;
}
[STAThread]
static void Main ( )
{
Application . EnableVisualStyles ( ) ;
Application . SetCompatibleTextRenderingDefault ( false ) ;
Application . Run ( new Rebuilder ( ) ) ;
}
}
}