CRAW now runs on Windows 7 too - the problem was that Windows 7 has moved some functi...
[craw.git] / craw / arguments.cpp
blob8e22e3db0070fec76671b5c52b241c8569d8cf5d
1 #include <windows.h>
2 #include <cstring>
3 #include <ail/arguments.hpp>
4 #include "arguments.hpp"
5 #include "utility.hpp"
6 #include "patch.hpp"
8 bool
9 console_output,
10 incremental_window_title,
11 verbose,
12 use_custom_keys,
13 prompt_mode,
14 patch_system_modules,
15 do_not_hide_window;
17 std::string
18 window_title,
19 classic_key,
20 expansion_key,
21 d2_arguments,
22 python_script,
23 hide_modules_file,
24 bncache_directory,
25 socks;
27 bool use_socks;
28 std::string socks_server;
29 ushort socks_port;
31 char * command_line_arguments;
33 std::string key_string(std::string const & key)
35 if(key.empty())
36 return "Key has not been specified";
37 else
38 return "A custom key has been specified";
41 char * patched_GetCommandLineA()
43 return command_line_arguments;
46 bool install_command_line_patch(string_vector const & parsed_arguments)
48 OSVERSIONINFOEX version;
49 ZeroMemory(&version, sizeof(OSVERSIONINFOEX));
50 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
51 if(!GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&version)))
53 last_error("GetVersionEx failed");
54 return false;
56 std::string kernel;
57 if(version.dwMajorVersion == 6 && version.dwMinorVersion == 1 && version.wProductType == VER_NT_WORKSTATION)
59 kernel = "kernelbase.dll";
60 if(verbose)
61 write_line("Windows 7 detected, using module " + kernel + " for the commandline patch");
63 else
65 kernel = "kernel32.dll";
66 if(verbose)
67 write_line("Pre Windows 7 OS detected, using module " + kernel + " for the commandline patch");
70 void * address;
71 if(!procedure_lookup(kernel.c_str(), "GetCommandLineA", address))
73 error("Unable to look up the address for the command line patch");
74 return false;
77 std::string new_arguments = "\"" + parsed_arguments[0] + "\" " + d2_arguments;
78 command_line_arguments = new char[new_arguments.size() + 1];
79 std::strcpy(command_line_arguments, new_arguments.c_str());
81 char * byte_pointer = reinterpret_cast<char *>(address);
82 uchar first_byte = *reinterpret_cast<uchar *>(byte_pointer);
83 if(first_byte == 0xa1)
85 char * & string_pointer = **reinterpret_cast<char ***>(byte_pointer + 1);
86 string_pointer = command_line_arguments;
88 if(verbose)
89 write_line("Successfully installed the command line patch");
91 return true;
93 else
95 error("The format of your kernel32.dll!GetCommandlineA is unknown to the patcher: " + ail::hex_string_8(first_byte));
96 return false;
100 bool get_arguments(string_vector & output)
102 std::string input = GetCommandLine();
103 for(std::size_t i = 0; i < input.size(); i++)
105 std::size_t
106 start,
107 end;
109 char current_char = input[i];
110 if(current_char == '"')
112 start = i + 1;
113 end = input.find('"', start);
114 if(end == std::string::npos)
116 error("Invalid commandline detected (check your quotes)");
117 return false;
120 else
122 start = i;
123 end = input.find(' ', start);
124 if(end == std::string::npos)
125 end = input.size();
128 std::string argument = input.substr(start, end - start);
129 output.push_back(argument);
130 i = end + 1;
133 return true;
136 void process_command_line()
138 ail::argument_parser argument_parser;
140 argument_parser.flag("console_output", console_output).default_flag(true);
141 argument_parser.flag("incremental_window_title", incremental_window_title).default_flag(false);
142 argument_parser.flag("verbose", verbose).default_flag(false);
143 argument_parser.flag("prompt", prompt_mode).default_flag(false);
144 argument_parser.flag("patch_system_modules", patch_system_modules).default_flag(true);
145 argument_parser.flag("do_not_hide_window", do_not_hide_window).default_flag(false);
147 argument_parser.string("window_title", window_title).default_string("Diablo II");
148 argument_parser.string("classic_key", classic_key);
149 argument_parser.string("expansion_key", expansion_key);
150 argument_parser.string("d2_arguments", d2_arguments).default_string("-w");
151 argument_parser.string("python_script", python_script);
152 argument_parser.string("hide_modules_file", hide_modules_file);
153 argument_parser.string("bncache_directory", bncache_directory);
154 argument_parser.string("socks", socks);
156 string_vector arguments;
157 if(!get_arguments(arguments))
159 exit_process();
160 return;
165 argument_parser.parse(arguments);
167 if(verbose)
169 write_line("Window title: " + window_title);
170 write_line("Classic key: " + key_string(classic_key));
171 write_line("Expansion key: " + key_string(expansion_key));
174 use_custom_keys = !classic_key.empty() && !expansion_key.empty();
176 if(verbose)
178 if(use_custom_keys)
179 write_line("Using the specified custom keys");
180 else
181 write_line("Not using a custom pair of keys");
184 install_command_line_patch(arguments);
186 catch(ail::exception & exception)
188 error("Argument parser error: " + exception.get_message());
191 use_socks = false;
192 if(!socks.empty())
194 string_vector tokens = ail::tokenise(socks, ":");
195 if(tokens.size() != 2)
197 error("Invalid SOCKS5 server address specified, should be \"host:port\", encountered \"" + socks + "\"");
198 exit_process();
199 return;
202 socks_server = tokens[0];
203 std::string const & socks_port_string = tokens[1];
204 if(!ail::string_to_number(socks_port_string, socks_port))
206 error("Invalid SOCKS5 server port specified: " + socks_port_string);
207 exit_process();
208 return;
210 use_socks = true;