1 /*
2 	vfdguisave.c
3 
4 	Virtual Floppy Drive for Windows
5 	Driver control library
6 	Save image GUI utility function
7 
8 	Copyright (c) 2003-2005 Ken Kato
9 */
10 
11 #ifdef __cplusplus
12 #pragma message(__FILE__": Compiled as C++ for testing purpose.")
13 #endif	// __cplusplus
14 
15 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
17 #if !defined(__REACTOS__) || defined(_MSC_VER)
18 #pragma warning(push,3)
19 #endif
20 #include <commdlg.h>
21 #if !defined(__REACTOS__) || defined(_MSC_VER)
22 #pragma warning(pop)
23 #endif
24 
25 #include "vfdtypes.h"
26 #include "vfdapi.h"
27 #include "vfdlib.h"
28 #ifndef __REACTOS__
29 #include "vfdmsg.h"
30 #else
31 #include "vfdmsg_lib.h"
32 #endif
33 #include "vfdguirc.h"
34 
35 //
36 //	local functions
37 //
38 #ifndef __REACTOS__
39 static INT CALLBACK SaveDialogProc(
40 #else
41 static INT_PTR CALLBACK SaveDialogProc(
42 #endif
43 	HWND			hDlg,
44 	UINT			uMsg,
45 	WPARAM			wParam,
46 	LPARAM			lParam);
47 
48 static void OnInit(HWND hDlg, PCSAVE_PARAM pParam);
49 static void OnTarget(HWND hDlg, HWND hEdit);
50 static void OnBrowse(HWND hDlg);
51 static void OnOverwrite(HWND hDlg, HWND hCheck);
52 static void OnTruncate(HWND hDlg, HWND hCheck);
53 static DWORD OnOK(HWND hDlg);
54 
55 //
56 //	Show Save Image dialog box
57 //
58 DWORD WINAPI VfdGuiSave(
59 	HWND			hParent,
60 	ULONG			nDevice)
61 {
62 	SAVE_PARAM		param;
63 	CHAR			path[MAX_PATH];
64 	DWORD			ret;
65 
66 	//	open the source device
67 
68 	param.hDevice = VfdOpenDevice(nDevice);
69 
70 	if (param.hDevice == INVALID_HANDLE_VALUE) {
71 		return GetLastError();
72 	}
73 
74 	//	get current image information
75 
76 	param.ImageName = path;
77 
78 	ret = VfdGetImageInfo(
79 		param.hDevice,
80 		param.ImageName,
81 		&param.DiskType,
82 		&param.MediaType,
83 		&param.MediaFlags,
84 		&param.FileType,
85 		&param.ImageSize);
86 
87 	if (ret == ERROR_SUCCESS) {
88 
89 		//	show dialog box
90 
91 		ret = GuiSaveParam(hParent, &param);
92 	}
93 
94 	//	close the source device
95 
96 	CloseHandle(param.hDevice);
97 
98 	return ret;
99 }
100 
101 DWORD GuiSaveParam(
102 	HWND			hParent,
103 	PCSAVE_PARAM	pParam)
104 {
105 	switch (DialogBoxParam(
106 		g_hDllModule,
107 		MAKEINTRESOURCE(IDD_SAVEDIALOG),
108 		hParent,
109 		SaveDialogProc,
110 		(LPARAM)pParam))
111 	{
112 	case IDOK:
113 		return ERROR_SUCCESS;
114 
115 	case IDCANCEL:
116 		return ERROR_CANCELLED;
117 
118 	default:
119 		return GetLastError();
120 	}
121 }
122 
123 //
124 // The dialog procedure
125 //
126 #ifndef __REACTOS__
127 INT CALLBACK SaveDialogProc(
128 #else
129 INT_PTR CALLBACK SaveDialogProc(
130 #endif
131 	HWND			hDlg,
132 	UINT			uMsg,
133 	WPARAM			wParam,
134 	LPARAM			lParam)
135 {
136 	switch (uMsg) {
137 	case WM_INITDIALOG:
138 		OnInit(hDlg, (PCSAVE_PARAM)lParam);
139 		return TRUE;
140 
141 	case WM_COMMAND:
142 		switch (wParam) {
143 		case MAKELONG(IDC_TARGETFILE, EN_CHANGE):
144 			OnTarget(hDlg, (HWND)lParam);
145 			return TRUE;
146 
147 		case IDC_BROWSE:
148 			OnBrowse(hDlg);
149 			return TRUE;
150 
151 		case IDC_OVERWRITE:
152 			OnOverwrite(hDlg, (HWND)lParam);
153 			return TRUE;
154 
155 		case IDC_TRUNCATE:
156 			OnTruncate(hDlg, (HWND)lParam);
157 			return TRUE;
158 
159 		case IDOK:
160 			if (OnOK(hDlg) == ERROR_SUCCESS) {
161 				EndDialog(hDlg, IDOK);
162 			}
163 			return TRUE;
164 
165 		case IDCANCEL:
166 			EndDialog(hDlg, IDCANCEL);
167 			return TRUE;
168 		}
169 		break;
170 
171 	case WM_CONTEXTMENU:
172 		ShowContextMenu(hDlg, (HWND)wParam, lParam);
173 		break;
174 
175 	case WM_HELP:
176 		{
177 			LPHELPINFO info = (LPHELPINFO)lParam;
178 
179 			if (info->iContextType == HELPINFO_WINDOW) {
180 				ShowHelpWindow(hDlg, info->iCtrlId);
181 			}
182 		}
183 		return TRUE;
184 	}
185 
186 	return FALSE;
187 }
188 
189 //
190 //	Initialize the dialog
191 //
192 void OnInit(
193 	HWND			hDlg,
194 	PCSAVE_PARAM	pParam)
195 {
196 	//	Store parameters
197 
198 #ifndef __REACTOS__
199 	SetWindowLong(hDlg, GWL_USERDATA, (ULONG)pParam);
200 #else
201 	SetWindowLongPtr(hDlg, GWLP_USERDATA, (ULONG_PTR)pParam);
202 #endif
203 
204 	//	clear the target existence flag
205 
206 	SetWindowLong(hDlg, DWL_USER, 0);
207 
208 	// Set dialog window title
209 
210 	SetControlText(hDlg, 0, MSG_SAVE_TITLE);
211 
212 	// Set control captions
213 
214 	SetControlText(hDlg, IDC_IMAGEFILE_LABEL,	MSG_IMAGEFILE_LABEL);
215 	SetControlText(hDlg, IDC_DISKTYPE_LABEL,	MSG_DISKTYPE_LABEL);
216 	SetControlText(hDlg, IDC_MEDIATYPE_LABEL,	MSG_MEDIATYPE_LABEL);
217 	SetControlText(hDlg, IDC_TARGETFILE_LABEL,	MSG_TARGETFILE_LABEL);
218 	SetControlText(hDlg, IDC_IMAGEDESC_LABEL,	MSG_DESCRIPTION_LABEL);
219 	SetControlText(hDlg, IDC_BROWSE,			MSG_BROWSE_BUTTON);
220 	SetControlText(hDlg, IDC_OVERWRITE,			MSG_OVERWRITE_CHECK);
221 	SetControlText(hDlg, IDC_TRUNCATE,			MSG_TRUNCATE_CHECK);
222 	SetControlText(hDlg, IDOK,					MSG_SAVE_BUTTON);
223 	SetControlText(hDlg, IDCANCEL,				MSG_CANCEL_BUTTON);
224 
225 	//	set disk type
226 
227 	if (pParam->DiskType == VFD_DISKTYPE_FILE) {
228 		SetDlgItemText(hDlg, IDC_DISKTYPE, "FILE");
229 	}
230 	else {
231 		SetDlgItemText(hDlg, IDC_DISKTYPE, "RAM");
232 	}
233 
234 	//	display media type
235 
236 	SetDlgItemText(hDlg, IDC_MEDIATYPE,
237 		VfdMediaTypeName(pParam->MediaType));
238 
239 	//	set current image and initial target
240 
241 	if (pParam->ImageName[0]) {
242 		SetDlgItemText(hDlg, IDC_IMAGEFILE, pParam->ImageName);
243 		SetDlgItemText(hDlg, IDC_TARGETFILE, pParam->ImageName);
244 	}
245 	else if (pParam->DiskType != VFD_DISKTYPE_FILE) {
246 		SetDlgItemText(hDlg, IDC_IMAGEFILE, "<RAM>");
247 		OnTarget(hDlg, GetDlgItem(hDlg, IDC_TARGETFILE));
248 	}
249 }
250 
251 //
252 //	Path is changed -- check specified target file
253 //
254 void OnTarget(
255 	HWND			hDlg,
256 	HWND			hEdit)
257 {
258 	PCSAVE_PARAM	param;
259 	CHAR			buf[MAX_PATH];
260 	ULONG			file_size;
261 	VFD_FILETYPE	file_type;
262 	DWORD			file_attr;
263 	DWORD			ret;
264 
265 	//	clear the target existence flag
266 
267 	SetWindowLong(hDlg, DWL_USER, 0);
268 
269 	//	clear the description and hint text
270 
271 	SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, NULL);
272 	SetDlgItemText(hDlg, IDC_IMAGEFILE_HINT, NULL);
273 
274 	//	get the target file name
275 
276 	if (GetWindowText(hEdit, buf, sizeof(buf)) == 0) {
277 
278 		//	target file is blank
279 
280 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
281 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
282 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
283 
284 		return;
285 	}
286 	else {
287 		CHAR full[MAX_PATH];
288 		PSTR file;
289 
290 		//	convert into a full path
291 
292 		if (GetFullPathName(buf, sizeof(full), full, &file)) {
293 			strcpy(buf, full);
294 		}
295 	}
296 
297 	//
298 	//	get the current image info
299 	//
300 #ifndef __REACTOS__
301 	param = (PCSAVE_PARAM)GetWindowLong(hDlg, GWL_USERDATA);
302 #else
303 	param = (PCSAVE_PARAM)GetWindowLongPtr(hDlg, GWLP_USERDATA);
304 #endif
305 
306 	if (_stricmp(param->ImageName, buf) == 0) {
307 
308 		//	target is the current file
309 
310 		char desc[MAX_PATH];
311 
312 		VfdMakeFileDesc(desc, sizeof(desc),
313 			param->FileType, param->ImageSize,
314 			GetFileAttributes(param->ImageName));
315 
316 		SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, desc);
317 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_CURRENT_FILE);
318 
319 		if (param->DiskType == VFD_DISKTYPE_FILE) {
320 
321 			//	cannot overwrite the current FILE disk image
322 
323 			EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
324 			EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
325 			EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
326 			return;
327 		}
328 	}
329 
330 	//
331 	//	check target image file
332 	//
333 	ret = VfdCheckImageFile(
334 		buf, &file_attr, &file_type, &file_size);
335 
336 	if (ret == ERROR_FILE_NOT_FOUND) {
337 		//	file does not exist
338 		SetControlText(hDlg, IDC_IMAGEFILE_DESC, MSG_DESC_NEW_FILE);
339 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
340 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
341 		EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
342 		return;
343 	}
344 	else if (ret != ERROR_SUCCESS) {
345 		SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, SystemMessage(ret));
346 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
347 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
348 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
349 		return;
350 	}
351 
352 	//	set target file description
353 
354 	VfdMakeFileDesc(buf, sizeof(buf),
355 		file_type, file_size, file_attr);
356 
357 	SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, buf);
358 
359 	//	check target file type
360 
361 	if (file_type == VFD_FILETYPE_ZIP) {
362 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_TARGET_IS_ZIP);
363 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
364 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
365 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
366 		return;
367 	}
368 
369 	//	the target is an existing raw file
370 
371 	EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), TRUE);
372 
373 	//	set truncate box
374 
375 	if (file_size > VfdGetMediaSize(param->MediaType)) {
376 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), TRUE);
377 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_SIZE_MISMATCH);
378 	}
379 	else {
380 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
381 	}
382 
383 	//	check overwrite setting
384 
385 	if (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) != BST_CHECKED) {
386 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
387 	}
388 	else {
389 		EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
390 	}
391 
392 	//	target file exists and overwritable
393 
394 	SetWindowLong(hDlg, DWL_USER, 1);
395 }
396 
397 
398 //
399 //	Show save file dialog box
400 //
401 void OnBrowse(
402 	HWND			hDlg)
403 {
404 	OPENFILENAME	ofn;
405 	PSTR			title;
406 	CHAR			file[MAX_PATH];
407 	CHAR			dir[MAX_PATH];
408 	DWORD			len;
409 
410 	title = ModuleMessage(MSG_SAVE_TITLE);
411 
412 	ZeroMemory(&ofn, sizeof(ofn));
413 	ZeroMemory(file, sizeof(file));
414 	ZeroMemory(dir, sizeof(dir));
415 
416 	len = GetDlgItemText(hDlg, IDC_TARGETFILE, file, sizeof(file));
417 
418 	if (len && file[len - 1] == '\\') {
419 		strcpy(dir, file);
420 		ZeroMemory(file, sizeof(file));
421 	}
422 
423 	// Different structure sizes must be used for NT and 2K/XP
424 	ofn.lStructSize = IS_WINDOWS_NT() ?
425 		OPENFILENAME_SIZE_VERSION_400 : sizeof(ofn);
426 
427 	ofn.hwndOwner	= hDlg;
428 	ofn.lpstrFile	= file;
429 	ofn.nMaxFile	= sizeof(file);
430 	ofn.lpstrInitialDir = dir;
431 	ofn.lpstrTitle	= title ? title : "Save Image";
432 	ofn.lpstrFilter	= "*.*\0*.*\0";
433 #ifndef __REACTOS__
434 	ofn.Flags		= OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
435 #else
436 	ofn.Flags		= OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
437 #endif
438 
439 	if (GetSaveFileName(&ofn)) {
440 		SetDlgItemText(hDlg, IDC_TARGETFILE, file);
441 		SetFocus(GetDlgItem(hDlg, IDC_TARGETFILE));
442 	}
443 
444 	if (title) {
445 		LocalFree(title);
446 	}
447 }
448 
449 void OnOverwrite(
450 	HWND			hDlg,
451 	HWND			hCheck)
452 {
453 	if (GetWindowLong(hDlg, DWL_USER)) {
454 		//	the target file exists and overwritable
455 		if (SendMessage(hCheck, BM_GETCHECK, 0, 0) != BST_CHECKED) {
456 			EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
457 		}
458 		else {
459 			EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
460 		}
461 	}
462 }
463 
464 void OnTruncate(
465 	HWND			hDlg,
466 	HWND			hCheck)
467 {
468 	UNREFERENCED_PARAMETER(hDlg);
469 	UNREFERENCED_PARAMETER(hCheck);
470 }
471 
472 //
473 //	Save image
474 //
475 DWORD OnOK(
476 	HWND			hDlg)
477 {
478 	PCSAVE_PARAM	param;
479 	CHAR			path[MAX_PATH];
480 	BOOL			overwrite;
481 	BOOL			truncate;
482 	DWORD			ret;
483 
484 #ifndef __REACTOS__
485 	param = (PCSAVE_PARAM)GetWindowLong(hDlg, GWL_USERDATA);
486 #else
487 	param = (PCSAVE_PARAM)GetWindowLongPtr(hDlg, GWLP_USERDATA);
488 #endif
489 
490 	if (!param) {
491 		return ERROR_INVALID_FUNCTION;
492 	}
493 
494 	//	get the target image name
495 
496 	if (GetDlgItemText(hDlg, IDC_TARGETFILE, path, sizeof(path)) == 0) {
497 		return ERROR_INVALID_FUNCTION;
498 	}
499 
500 	if (GetWindowLong(hDlg, DWL_USER)) {
501 		//	the target file exists and overwritable
502 		overwrite = (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) == BST_CHECKED);
503 		truncate = (IsDlgButtonChecked(hDlg, IDC_TRUNCATE) == BST_CHECKED);
504 	}
505 	else {
506 		overwrite = FALSE;
507 		truncate = TRUE;
508 	}
509 
510 retry:
511 	ret = VfdDismountVolume(param->hDevice, FALSE);
512 
513 	if (ret == ERROR_ACCESS_DENIED) {
514 		PSTR msg = ModuleMessage(MSG_UNMOUNT_CONFIRM);
515 
516 		int reply = MessageBox(
517 			hDlg, msg ? msg : "retry", VFD_MSGBOX_TITLE,
518 			MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE);
519 
520 		if (msg) {
521 			LocalFree(msg);
522 		}
523 
524 		if (reply == IDRETRY) {
525 			goto retry;
526 		}
527 		else if (reply == IDCANCEL) {
528 			return ERROR_CANCELLED;
529 		}
530 		else {
531 			VfdDismountVolume(param->hDevice, TRUE);
532 		}
533 	}
534 	else if (ret != ERROR_SUCCESS) {
535 
536 		MessageBox(hDlg, SystemMessage(ret),
537 			VFD_MSGBOX_TITLE, MB_ICONSTOP);
538 
539 		return ret;
540 	}
541 
542 	ret = VfdSaveImage(param->hDevice, path, overwrite, truncate);
543 
544 	if (ret != ERROR_SUCCESS) {
545 
546 		//	show error message
547 
548 		MessageBox(hDlg, SystemMessage(ret),
549 			VFD_MSGBOX_TITLE, MB_ICONSTOP);
550 	}
551 
552 	return ret;
553 }
554