1 // wxGUI.cpp
2 
3 #include "StdAfx.h"
4 
5 // For compilers that support precompilation, includes "wx/wx.h".
6 #include "wx/wxprec.h"
7 
8 #ifdef __BORLANDC__
9     #pragma hdrstop
10 #endif
11 
12 // for all others, include the necessary headers (this file is usually all you
13 // need because it includes almost all "standard" wxWidgets headers)
14 #ifndef WX_PRECOMP
15     #include "wx/wx.h"
16 #endif
17 
18 #define static const
19 #include "../GUI/p7zip_32.xpm"
20 #undef static
21 
22 #undef ACTIVATE_DIALOG_TESTS
23 
24 int Main1(int argc,TCHAR **argv);
25 
26 #include "Windows/Registry.h"
27 using namespace NWindows;
28 using namespace NRegistry;
29 
30 
31 #include "Common/StringConvert.h"
32 #include "Windows/FileDir.h"
33 #include "Windows/Synchronization.h"
34 
35 #include "ExtractRes.h"
36 #include "../Explorer/MyMessages.h"
37 
38 #include "ExtractGUI.h"
39 #include "UpdateGUI.h"
40 #include "BenchmarkDialog.h"
41 #include "../FileManager/RegistryUtils.h"
42 
43 using namespace NWindows;
44 using namespace NFile;
45 
46 #include "../FileManager/ProgramLocation.h"
47 
48 static LPCWSTR kHelpFileName = L"help/";
49 
ShowHelpWindow(HWND hwnd,LPCWSTR topicFile)50 void ShowHelpWindow(HWND hwnd, LPCWSTR topicFile)
51 {
52   UString path;
53   if (!::GetProgramFolderPath(path))
54     return;
55   path += kHelpFileName;
56   path += topicFile;
57   printf("ShowHelpWindow(%p,%ls)=>%ls\n",hwnd,topicFile,(const wchar_t *)path);
58   // HtmlHelp(hwnd, GetSystemString(path), HH_DISPLAY_TOPIC, NULL);
59   wxString path2(path);
60   wxLaunchDefaultBrowser(path2);
61 }
62 
63 ////////////////////////////// TRIES ///////////////////////////////////
64 
65 #ifdef ACTIVATE_DIALOG_TESTS
ErrorMessage(const wchar_t * message)66 static void ErrorMessage(const wchar_t *message)
67 {
68   MessageBox(0,message, wxT("7-Zip GUI"),wxICON_ERROR);
69 }
70 
71 #include "../FileManager/PasswordDialog.h"
72 #include "../FileManager/MessagesDialog.h"
73 #include "../FileManager/OverwriteDialog.h"
74 #include "Windows/Thread.h"
75 
myErrorMsg(const wchar_t * message)76 void myErrorMsg(const wchar_t *message)
77 {
78 	MessageBox(0,message, wxT("Message"),wxICON_ERROR);
79 }
80 
testCMessagesDialog()81 void testCMessagesDialog()
82 {
83 	UStringVector Messages;
84 
85 	Messages.Add(L"message 1");
86 	Messages.Add(L"message 2");
87 	Messages.Add(L"message 3");
88 	Messages.Add(L"message 4");
89 	Messages.Add(L"message 5");
90 	Messages.Add(L"message 6");
91 	Messages.Add(L"message 7");
92 	Messages.Add(L"message 8");
93 	Messages.Add(L"message 9");
94 
95 	CMessagesDialog messagesDialog;
96     messagesDialog.Messages = &Messages;
97    int ret = messagesDialog.Create( 0  ); // ParentWindow
98 
99    	if (ret == IDOK) myErrorMsg(wxT("CMessagesDialog => IDOK"));
100 	else if (ret == IDCANCEL) myErrorMsg(wxT("CMessagesDialog => IDCANCEL"));
101 	else  myErrorMsg(wxT("CMessagesDialog => ?"));
102 
103 }
104 
testCOverwriteDialog()105 void testCOverwriteDialog()
106 {
107 SYSTEMTIME systemTime;
108 GetSystemTime( &systemTime );
109 
110 
111 const wchar_t *existName = L"existName";
112 FILETIME data_existTime;
113 FILETIME *existTime = &data_existTime ;
114 UInt64 data_existSize = 1234;
115 UInt64 *existSize = &data_existSize;
116 const wchar_t *newName = L"newName";
117 FILETIME data_newTime;
118 FILETIME *newTime = &data_newTime;
119 UInt64 data_newSize = 45678;
120 UInt64 *newSize = &data_newSize;
121 Int32 data_answer=0;
122 Int32 *answer = &data_answer;
123 
124 SystemTimeToFileTime( &systemTime , &data_existTime);
125 SystemTimeToFileTime( &systemTime , &data_newTime);
126 
127   COverwriteDialog dialog;
128 
129   dialog.OldFileInfo.Time = *existTime;
130   dialog.OldFileInfo.TimeIsDefined = true; // FIXME : look again at the sample !
131 
132   dialog.OldFileInfo.SizeIsDefined = (existSize != NULL);
133   if (dialog.OldFileInfo.SizeIsDefined)
134     dialog.OldFileInfo.Size = *existSize;
135   dialog.OldFileInfo.Name = existName;
136 
137   if (newTime == 0)
138     dialog.NewFileInfo.TimeIsDefined = false;
139   else
140   {
141     dialog.NewFileInfo.TimeIsDefined = true;
142     dialog.NewFileInfo.Time = *newTime;
143   }
144 
145   dialog.NewFileInfo.SizeIsDefined = (newSize != NULL);
146   if (dialog.NewFileInfo.SizeIsDefined)
147     dialog.NewFileInfo.Size = *newSize;
148   dialog.NewFileInfo.Name = newName;
149 
150   /*
151   NOverwriteDialog::NResult::EEnum writeAnswer =
152     NOverwriteDialog::Execute(oldFileInfo, newFileInfo);
153   */
154   INT_PTR writeAnswer = dialog.Create(NULL); // ParentWindow doesn't work with 7z
155 
156   switch(writeAnswer)
157   {
158   case IDCANCEL: myErrorMsg(wxT("COverwriteDialog => IDCANCEL")); break;
159   case IDNO:     myErrorMsg(wxT("COverwriteDialog => IDNO")); break;
160   case IDC_BUTTON_OVERWRITE_NO_TO_ALL: myErrorMsg(wxT("COverwriteDialog => IDC_BUTTON_OVERWRITE_NO_TO_ALL")); break;
161   case IDC_BUTTON_OVERWRITE_YES_TO_ALL:myErrorMsg(wxT("COverwriteDialog => IDC_BUTTON_OVERWRITE_YES_TO_ALL")); break;
162   case IDC_BUTTON_OVERWRITE_AUTO_RENAME:myErrorMsg(wxT("COverwriteDialog => IDC_BUTTON_OVERWRITE_AUTO_RENAME")); break;
163   case IDYES:  myErrorMsg(wxT("COverwriteDialog => IDYES")); break;
164   default:  myErrorMsg(wxT("COverwriteDialog => default")); break;
165   }
166 }
167 
testCPasswordDialog()168 void testCPasswordDialog()
169 {
170     CPasswordDialog dialog;
171 
172 	int ret = dialog.Create(0);
173 	if (ret == IDOK) {
174     		UString Password = dialog.Password;
175 		UString msg  = wxT("CPasswordDialog => IDOK password=\"");
176 		msg += Password;
177 		msg += wxT("\"");
178 		myErrorMsg(msg);
179 	}
180 	else if (ret == IDCANCEL) myErrorMsg(wxT("CPasswordDialog => IDCANCEL"));
181 	else  myErrorMsg(wxT("CPasswordDialog => ?"));
182 
183 }
184 
185 struct CThreadProgressDialog
186 {
187   CProgressDialog * ProgressDialog;
MyThreadFunctionCThreadProgressDialog188   static THREAD_FUNC_DECL MyThreadFunction(void *param)
189   {
190     ((CThreadProgressDialog *)param)->Result = ((CThreadProgressDialog *)param)->Process();
191     return 0;
192   }
193   HRESULT Result;
ProcessCThreadProgressDialog194   HRESULT Process()
195   {
196 	Sleep(1000);
197 	int total = 1000;
198 
199 	ProgressDialog->ProgressSynch.SetTitleFileName(L"SetTitleFileName");
200 	ProgressDialog->ProgressSynch.SetNumFilesTotal(100);
201 	ProgressDialog->ProgressSynch.SetNumFilesCur(1);
202 	ProgressDialog->ProgressSynch.SetProgress(total, 0);
203 	// ProgressDialog.ProgressSynch.SetRatioInfo(inSize, outSize);
204 	// ProgressDialog.ProgressSynch.SetCurrentFileName(name);
205 
206 	ProgressDialog->ProgressSynch.SetPos(total/10);
207 	ProgressDialog->ProgressSynch.SetCurrentFileName(L"File1");
208 	Sleep(1000);
209 	ProgressDialog->ProgressSynch.SetPos(total/2);
210 	ProgressDialog->ProgressSynch.SetCurrentFileName(L"File2");
211 	Sleep(1000);
212 	ProgressDialog->ProgressSynch.SetPos(total);
213 	ProgressDialog->ProgressSynch.SetCurrentFileName(L"File3");
214 	Sleep(1000);
215 	ProgressDialog->MyClose();
216 	return 0;
217   }
218 };
219 
testCProgressDialog()220 void testCProgressDialog()
221 {
222   CProgressDialog ProgressDialog;
223 
224   CThreadProgressDialog benchmarker;
225   benchmarker.ProgressDialog = &ProgressDialog;
226   NWindows::CThread thread;
227   thread.Create(CThreadProgressDialog::MyThreadFunction, &benchmarker);
228 
229   //  void StartProgressDialog(const UString &title)
230   int ret = ProgressDialog.Create(L"testCProgressDialog", 0);
231 
232 	if (ret == IDOK) myErrorMsg(wxT("CProgressDialog => IDOK"));
233 	else if (ret == IDCANCEL) myErrorMsg(wxT("CProgressDialog => IDCANCEL"));
234 	else  myErrorMsg(wxT("CProgressDialog => ?"));
235 
236 }
237 
testDialog(int num)238 void testDialog(int num)
239 {
240 	NWindows::NControl::CModalDialog dialog;
241 
242 	printf("Generic Dialog(%d)\n",num);
243 	int ret = dialog.Create(num, 0);
244 	if (ret == IDOK) myErrorMsg(wxT("Generic Dialog => IDOK"));
245 	else if (ret == IDCANCEL) myErrorMsg(wxT("Generic Dialog => IDCANCEL"));
246 	else  myErrorMsg(wxT("Generic Dialog => ?"));
247 }
248 
testMessageBox()249 void testMessageBox()
250 {
251 	int ret = MessageBoxW(0, L"test yes/no/cancel",
252             L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION | MB_TASKMODAL);
253 	if (ret == IDYES) myErrorMsg(wxT("MessageBoxW => IDYES"));
254 	else if (ret == IDNO) myErrorMsg(wxT("MessageBoxW => IDNO"));
255 	else if (ret == IDCANCEL) myErrorMsg(wxT("MessageBoxW => IDCANCEL"));
256 	else  myErrorMsg(wxT("MessageBoxW => ?"));
257 }
258 
testRegistry()259 static void testRegistry()
260 {
261 	SaveRegLang(L"fr");
262 
263 	UString langFile;
264 	ReadRegLang(langFile);
265 
266 	printf("testRegistry : -%ls-\n",(const wchar_t *)langFile);
267 }
268 
269 
270 int Main2(int argc,TCHAR **argv);
271 
Main3(int argc,wxChar ** argv)272 int Main3(int argc,wxChar **argv)
273 {
274 	testRegistry();
275 
276 	int num = -1;
277 
278 	if (argc >=2 )
279 	{
280 		num = argv[1][0] - L'0';
281 	}
282 	printf("num=%d\n",num);
283 
284 
285 	switch(num)
286 	{
287 		case 0:
288 		{
289 			TCHAR **argv2 = (TCHAR **)calloc(argc,sizeof(*argv));
290 
291 			argv2[0] = argv[0];
292 			for(int i = 2; i < argc; i++) argv2[i-1] = argv[i];
293 
294 			return Main2(argc-1,argv2);
295 		}
296 	// TODO Benchmark
297 	// TODO CCompressDialog
298 	// TODO CExtractDialog ?
299 		case 1 : testCMessagesDialog();  break;
300 		case 2 : testCOverwriteDialog(); break;
301 	 	case 3 : testCPasswordDialog();  break;
302 		case 4 : testCProgressDialog();  break;
303 		case 5 : testMessageBox();  break;
304 		case 9 :
305 			if (argc >= 3)
306 			{
307 				AString str = GetAnsiString(argv[2]);
308 				int num = atoi((const char*)str);
309 				testDialog(num);
310 			}
311 			else
312 			{
313 				printf("usage : 7zG 9 <windowID>\n");
314 			}
315 		      	break;
316 		default :
317 			printf("usage : 7zG number\n");
318 
319 	};
320 
321 	return 0;
322 }
323 
324 #endif // ACTIVATE_DIALOG_TESTS
325 
326 static const TCHAR *kCUBasePath = TEXT("Software/7-ZIP");
327 static const WCHAR *kLangValueName = L"Lang";
328 
SaveRegLang(const UString & langFile)329 void SaveRegLang(const UString &langFile)
330 {
331   CKey key;
332   key.Create(HKEY_CURRENT_USER, kCUBasePath);
333   key.SetValue(kLangValueName, langFile);
334 }
335 
ReadRegLang(UString & langFile)336 void ReadRegLang(UString &langFile)
337 {
338   langFile.Empty();
339   CKey key;
340   if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS)
341     key.QueryValue(kLangValueName, langFile);
342 }
343 
344 
345 //////////////////////////////////
346 
347 #define NEED_NAME_WINDOWS_TO_UNIX
348 #include "myPrivate.h" // global_use_utf16_conversion
349 
mySplitCommandLineW(int numArguments,TCHAR ** arguments,UStringVector & parts)350 void mySplitCommandLineW(int numArguments, TCHAR  **arguments,UStringVector &parts) {
351 
352   parts.Clear();
353   for(int ind=0;ind < numArguments; ind++) {
354       UString tmp = arguments[ind];
355       // tmp.Trim(); " " is a valid filename ...
356       if (!tmp.IsEmpty()) {
357         parts.Add(tmp);
358 // DEBUG printf("ARG %d : '%ls'\n",ind,(const wchar_t *)tmp);
359       }
360   }
361 }
362 
363 // ----------------------------------------------------------------------------
364 // private classes
365 // ----------------------------------------------------------------------------
366 
367 // Define a new frame type
368 class MyFrame: public wxFrame
369 {
370 public:
371     // ctor
372     MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
373     // virtual ~MyFrame();
374 
375     // operations
WriteText(const wxString & text)376     void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
377 
378 protected:
379     // callbacks
380     void OnWorkerEvent(wxCommandEvent& event);
381 private:
382     // just some place to put our messages in
383     wxTextCtrl *m_txtctrl;
384     DECLARE_EVENT_TABLE()
385 };
386 
387 enum {
388     WORKER_EVENT=100    // this one gets sent from the worker thread
389 };
390 
BEGIN_EVENT_TABLE(MyFrame,wxFrame)391 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
392     EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent)
393     // EVT_IDLE(MyFrame::OnIdle)
394 END_EVENT_TABLE()
395 
396 // My frame constructor
397 MyFrame::MyFrame(wxFrame *frame, const wxString& title,
398                  int x, int y, int w, int h)
399        : wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
400 {
401 	this->SetIcon(wxICON(p7zip_32));
402 
403 #if wxUSE_STATUSBAR
404     CreateStatusBar(2);
405 #endif // wxUSE_STATUSBAR
406 
407     m_txtctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(0, 0), wxTE_MULTILINE | wxTE_READONLY);
408 }
409 
410 void myCreateHandle(int n);
411 wxWindow * g_window=0;
412 
OnWorkerEvent(wxCommandEvent & event)413 void MyFrame::OnWorkerEvent(wxCommandEvent& event)
414 {
415 	int n = event.GetInt();
416 	myCreateHandle(n);
417 }
418 
419 
420 // Define a new application type, each program should derive a class from wxApp
421 class MyApp : public wxApp
422 {
423 public:
424     // override base class virtuals
425     // ----------------------------
426 
427     // this one is called on application startup and is a good place for the app
428     // initialization (doing it here and not in the ctor allows to have an error
429     // return: if OnInit() returns false, the application terminates)
430     virtual bool OnInit();
431 };
432 
433 // Create a new application object: this macro will allow wxWidgets to create
434 // the application object during program execution (it's better than using a
435 // static object for many reasons) and also implements the accessor function
436 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
437 // not wxApp)
438 IMPLEMENT_APP(MyApp)
439 
440 time_t g_T0 = 0;
441 class MyThread : public wxThread
442 {
443 	int _argc;
444 	TCHAR **_argv;
445 public:
MyThread(int argc,TCHAR ** argv)446 	MyThread(int argc,TCHAR **argv): wxThread(),_argc(argc), _argv(argv) {}
447 
448 	// thread execution starts here
Entry()449 	virtual void *Entry()
450 	{
451 #ifdef ACTIVATE_DIALOG_TESTS
452 		int ret = Main3(_argc,_argv);
453 #else
454 		int ret = Main1(_argc,_argv);
455 #endif
456 		exit(ret);
457 	}
458 };
459 
460 // 'Main program' equivalent: the program execution "starts" here
OnInit()461 bool MyApp::OnInit()
462 {
463     // don't parse the command-line options !
464     // : if ( !wxApp::OnInit() ) return false;
465 
466   { // define P7ZIP_HOME_DIR
467     extern void my_windows_split_path(const AString &p_path, AString &dir , AString &base);
468     static char p7zip_home_dir[MAX_PATH];
469 
470     UString fullPath;
471     NDirectory::MyGetFullPathName(wxApp::argv[0], fullPath);
472     AString afullPath = GetAnsiString(fullPath);
473 
474     AString dir,name;
475 
476     my_windows_split_path(afullPath,dir,name);
477 
478     const char *dir2 = nameWindowToUnix((const char *)dir);
479     snprintf(p7zip_home_dir,sizeof(p7zip_home_dir),"P7ZIP_HOME_DIR=%s/",dir2);
480     p7zip_home_dir[sizeof(p7zip_home_dir)-1] = 0;
481     putenv(p7zip_home_dir);
482     // DEBUG printf("putenv(%s)\n",p7zip_home_dir);
483   }
484   global_use_utf16_conversion = 1; // UNICODE !
485 
486   g_T0 = time(0);
487   // DEBUG printf("MAIN Thread : 0x%lx\n",wxThread::GetCurrentId());
488 
489    // Create the main frame window
490     MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("7-zip Main Window"), 50, 50, 450, 340);
491    // Don't Show the frame !
492    // frame->Show(true);
493 
494     SetTopWindow(frame);
495 
496     g_window = frame;
497 
498     MyThread *thread = new MyThread(wxApp::argc,wxApp::argv);
499     thread->Create(); //  != wxTHREAD_NO_ERROR
500     thread->Run();
501 
502   // success: wxApp::OnRun() will be called which will enter the main message
503   // loop and the application will run. If we returned false here, the
504   // application would exit immediately.
505     return true;
506 }
507 
GetTickCount(VOID)508 DWORD WINAPI GetTickCount(VOID) {
509 	static wxStopWatch sw;
510 	return sw.Time();
511 }
512 
513 //////////////////////////////////////////
514 
515 #include "resource.h"
516 #include "ExtractRes.h"
517 
518 static CStringTable g_stringTable[] =
519 {
520   /* resource.rc */
521   /***************/
522 	{ IDS_OPEN_TYPE_ALL_FILES, L"All Files" },
523 	{ IDS_METHOD_STORE, L"Store" },
524 	{ IDS_METHOD_NORMAL, L"Normal" },
525 	{ IDS_METHOD_MAXIMUM, L"Maximum" },
526 	{ IDS_METHOD_FAST, L"Fast" },
527 	{ IDS_METHOD_FASTEST, L"Fastest" },
528 	{ IDS_METHOD_ULTRA, L"Ultra" },
529 	{ IDS_COMPRESS_NON_SOLID, L"Non-solid" },
530 	{ IDS_COMPRESS_SOLID, L"Solid" },
531 
532 	{ IDS_COMPRESS_UPDATE_MODE_ADD, L"Add and replace files" },
533 	{ IDS_COMPRESS_UPDATE_MODE_UPDATE, L"Update and add files" },
534 	{ IDS_COMPRESS_UPDATE_MODE_FRESH, L"Freshen existing files" },
535 	{ IDS_COMPRESS_UPDATE_MODE_SYNCHRONIZE, L"Synchronize files" },
536 	{ IDS_COMPRESS_SET_ARCHIVE_DIALOG_TITLE, L"Browse" },
537 	{ IDS_COMPRESS_INCORRECT_VOLUME_SIZE, L"Incorrect volume size" },
538 	{ IDS_COMPRESS_SPLIT_CONFIRM_MESSAGE, L"Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?" },
539 
540 	{ IDS_PASSWORD_USE_ASCII, L"Use only English letters, numbers and special characters (!, #, $, ...) for password." },
541 	{ IDS_PASSWORD_PASSWORDS_DO_NOT_MATCH, L"Passwords do not match" },
542 	{ IDS_PASSWORD_IS_TOO_LONG, L"Password is too long" },
543 
544 	{ IDS_PROGRESS_COMPRESSING, L"Compressing" },
545 	{ IDS_PROGRESS_TESTING, L"Testing" },
546 	{ IDS_MESSAGE_NO_ERRORS, L"There are no errors" },
547 	{ IDS_FILES_COLON, L"Files:" },
548 	{ IDS_FOLDERS_COLON, L"Folders:" },
549 	{ IDS_SIZE_COLON, L"Size:" },
550 	{ IDS_COMPRESSED_COLON, L"Compressed size:" },
551 	{ IDS_ARCHIVES_COLON, L"Archives:" },
552 
553   /* Extract.rc */
554   /**************/
555 	{ IDS_CANNOT_CREATE_FOLDER , L"Cannot create folder '{0}'"},
556 	{ IDS_OPEN_IS_NOT_SUPORTED_ARCHIVE, L"File is not supported archive."},
557 
558 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_CRC , L"CRC failed in '{0}'. File is broken."},
559 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_DATA_ERROR , L"Data error in '{0}'. File is broken"},
560 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_UNSUPPORTED_METHOD , L"Unsupported compression method for '{0}'."},
561 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_CRC_ENCRYPTED , L"CRC failed in encrypted file '{0}'. Wrong password?"},
562 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED , L"Data error in encrypted file '{0}'. Wrong password?"},
563 
564 	{ IDS_EXTRACT_SET_FOLDER , L"Specify a location for extracted files."},
565 	{ IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_CANNOT_OPEN_FILE, L"Can not open output file '{0}'."},
566 	{ IDS_PROGRESS_EXTRACTING, L"Extracting" },
567 
568 	{ IDS_CANT_OPEN_ARCHIVE , L"Can not open file '{0}' as archive"},
569 	{ IDS_CANT_OPEN_ENCRYPTED_ARCHIVE , L"Can not open encrypted archive '{0}'. Wrong password?"},
570 
571 	{ 0 , 0 }
572 };
573 
574 REGISTER_STRINGTABLE(g_stringTable)
575 
576