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 #ifdef _MSC_VER
18 #pragma warning(push,3)
19 #endif
20 #include <commdlg.h>
21 #ifdef _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 	SetWindowLongPtr(hDlg, GWLP_USERDATA, (ULONG_PTR)pParam);
199 
200 	//	clear the target existence flag
201 
202 	SetWindowLong(hDlg, DWL_USER, 0);
203 
204 	// Set dialog window title
205 
206 	SetControlText(hDlg, 0, MSG_SAVE_TITLE);
207 
208 	// Set control captions
209 
210 	SetControlText(hDlg, IDC_IMAGEFILE_LABEL,	MSG_IMAGEFILE_LABEL);
211 	SetControlText(hDlg, IDC_DISKTYPE_LABEL,	MSG_DISKTYPE_LABEL);
212 	SetControlText(hDlg, IDC_MEDIATYPE_LABEL,	MSG_MEDIATYPE_LABEL);
213 	SetControlText(hDlg, IDC_TARGETFILE_LABEL,	MSG_TARGETFILE_LABEL);
214 	SetControlText(hDlg, IDC_IMAGEDESC_LABEL,	MSG_DESCRIPTION_LABEL);
215 	SetControlText(hDlg, IDC_BROWSE,			MSG_BROWSE_BUTTON);
216 	SetControlText(hDlg, IDC_OVERWRITE,			MSG_OVERWRITE_CHECK);
217 	SetControlText(hDlg, IDC_TRUNCATE,			MSG_TRUNCATE_CHECK);
218 	SetControlText(hDlg, IDOK,					MSG_SAVE_BUTTON);
219 	SetControlText(hDlg, IDCANCEL,				MSG_CANCEL_BUTTON);
220 
221 	//	set disk type
222 
223 	if (pParam->DiskType == VFD_DISKTYPE_FILE) {
224 		SetDlgItemText(hDlg, IDC_DISKTYPE, "FILE");
225 	}
226 	else {
227 		SetDlgItemText(hDlg, IDC_DISKTYPE, "RAM");
228 	}
229 
230 	//	display media type
231 
232 	SetDlgItemText(hDlg, IDC_MEDIATYPE,
233 		VfdMediaTypeName(pParam->MediaType));
234 
235 	//	set current image and initial target
236 
237 	if (pParam->ImageName[0]) {
238 		SetDlgItemText(hDlg, IDC_IMAGEFILE, pParam->ImageName);
239 		SetDlgItemText(hDlg, IDC_TARGETFILE, pParam->ImageName);
240 	}
241 	else if (pParam->DiskType != VFD_DISKTYPE_FILE) {
242 		SetDlgItemText(hDlg, IDC_IMAGEFILE, "<RAM>");
243 		OnTarget(hDlg, GetDlgItem(hDlg, IDC_TARGETFILE));
244 	}
245 }
246 
247 //
248 //	Path is changed -- check specified target file
249 //
250 void OnTarget(
251 	HWND			hDlg,
252 	HWND			hEdit)
253 {
254 	PCSAVE_PARAM	param;
255 	CHAR			buf[MAX_PATH];
256 	ULONG			file_size;
257 	VFD_FILETYPE	file_type;
258 	DWORD			file_attr;
259 	DWORD			ret;
260 
261 	//	clear the target existence flag
262 
263 	SetWindowLong(hDlg, DWL_USER, 0);
264 
265 	//	clear the description and hint text
266 
267 	SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, NULL);
268 	SetDlgItemText(hDlg, IDC_IMAGEFILE_HINT, NULL);
269 
270 	//	get the target file name
271 
272 	if (GetWindowText(hEdit, buf, sizeof(buf)) == 0) {
273 
274 		//	target file is blank
275 
276 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
277 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
278 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
279 
280 		return;
281 	}
282 	else {
283 		CHAR full[MAX_PATH];
284 		PSTR file;
285 
286 		//	convert into a full path
287 
288 		if (GetFullPathName(buf, sizeof(full), full, &file)) {
289 			strcpy(buf, full);
290 		}
291 	}
292 
293 	//
294 	//	get the current image info
295 	//
296 	param = (PCSAVE_PARAM)GetWindowLongPtr(hDlg, GWLP_USERDATA);
297 
298 	if (_stricmp(param->ImageName, buf) == 0) {
299 
300 		//	target is the current file
301 
302 		char desc[MAX_PATH];
303 
304 		VfdMakeFileDesc(desc, sizeof(desc),
305 			param->FileType, param->ImageSize,
306 			GetFileAttributes(param->ImageName));
307 
308 		SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, desc);
309 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_CURRENT_FILE);
310 
311 		if (param->DiskType == VFD_DISKTYPE_FILE) {
312 
313 			//	cannot overwrite the current FILE disk image
314 
315 			EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
316 			EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
317 			EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
318 			return;
319 		}
320 	}
321 
322 	//
323 	//	check target image file
324 	//
325 	ret = VfdCheckImageFile(
326 		buf, &file_attr, &file_type, &file_size);
327 
328 	if (ret == ERROR_FILE_NOT_FOUND) {
329 		//	file does not exist
330 		SetControlText(hDlg, IDC_IMAGEFILE_DESC, MSG_DESC_NEW_FILE);
331 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
332 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
333 		EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
334 		return;
335 	}
336 	else if (ret != ERROR_SUCCESS) {
337 		SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, SystemMessage(ret));
338 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
339 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
340 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
341 		return;
342 	}
343 
344 	//	set target file description
345 
346 	VfdMakeFileDesc(buf, sizeof(buf),
347 		file_type, file_size, file_attr);
348 
349 	SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, buf);
350 
351 	//	check target file type
352 
353 	if (file_type == VFD_FILETYPE_ZIP) {
354 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_TARGET_IS_ZIP);
355 		EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
356 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
357 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
358 		return;
359 	}
360 
361 	//	the target is an existing raw file
362 
363 	EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), TRUE);
364 
365 	//	set truncate box
366 
367 	if (file_size > VfdGetMediaSize(param->MediaType)) {
368 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), TRUE);
369 		SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_SIZE_MISMATCH);
370 	}
371 	else {
372 		EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
373 	}
374 
375 	//	check overwrite setting
376 
377 	if (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) != BST_CHECKED) {
378 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
379 	}
380 	else {
381 		EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
382 	}
383 
384 	//	target file exists and overwritable
385 
386 	SetWindowLong(hDlg, DWL_USER, 1);
387 }
388 
389 
390 //
391 //	Show save file dialog box
392 //
393 void OnBrowse(
394 	HWND			hDlg)
395 {
396 	OPENFILENAME	ofn;
397 	PSTR			title;
398 	CHAR			file[MAX_PATH];
399 	CHAR			dir[MAX_PATH];
400 	DWORD			len;
401 
402 	title = ModuleMessage(MSG_SAVE_TITLE);
403 
404 	ZeroMemory(&ofn, sizeof(ofn));
405 	ZeroMemory(file, sizeof(file));
406 	ZeroMemory(dir, sizeof(dir));
407 
408 	len = GetDlgItemText(hDlg, IDC_TARGETFILE, file, sizeof(file));
409 
410 	if (len && file[len - 1] == '\\') {
411 		strcpy(dir, file);
412 		ZeroMemory(file, sizeof(file));
413 	}
414 
415 	// Different structure sizes must be used for NT and 2K/XP
416 	ofn.lStructSize = IS_WINDOWS_NT() ?
417 		OPENFILENAME_SIZE_VERSION_400 : sizeof(ofn);
418 
419 	ofn.hwndOwner	= hDlg;
420 	ofn.lpstrFile	= file;
421 	ofn.nMaxFile	= sizeof(file);
422 	ofn.lpstrInitialDir = dir;
423 	ofn.lpstrTitle	= title ? title : "Save Image";
424 	ofn.lpstrFilter	= "*.*\0*.*\0";
425 	ofn.Flags		= OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
426 
427 	if (GetSaveFileName(&ofn)) {
428 		SetDlgItemText(hDlg, IDC_TARGETFILE, file);
429 		SetFocus(GetDlgItem(hDlg, IDC_TARGETFILE));
430 	}
431 
432 	if (title) {
433 		LocalFree(title);
434 	}
435 }
436 
437 void OnOverwrite(
438 	HWND			hDlg,
439 	HWND			hCheck)
440 {
441 	if (GetWindowLong(hDlg, DWL_USER)) {
442 		//	the target file exists and overwritable
443 		if (SendMessage(hCheck, BM_GETCHECK, 0, 0) != BST_CHECKED) {
444 			EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
445 		}
446 		else {
447 			EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
448 		}
449 	}
450 }
451 
452 void OnTruncate(
453 	HWND			hDlg,
454 	HWND			hCheck)
455 {
456 	UNREFERENCED_PARAMETER(hDlg);
457 	UNREFERENCED_PARAMETER(hCheck);
458 }
459 
460 //
461 //	Save image
462 //
463 DWORD OnOK(
464 	HWND			hDlg)
465 {
466 	PCSAVE_PARAM	param;
467 	CHAR			path[MAX_PATH];
468 	BOOL			overwrite;
469 	BOOL			truncate;
470 	DWORD			ret;
471 
472 	param = (PCSAVE_PARAM)GetWindowLongPtr(hDlg, GWLP_USERDATA);
473 
474 	if (!param) {
475 		return ERROR_INVALID_FUNCTION;
476 	}
477 
478 	//	get the target image name
479 
480 	if (GetDlgItemText(hDlg, IDC_TARGETFILE, path, sizeof(path)) == 0) {
481 		return ERROR_INVALID_FUNCTION;
482 	}
483 
484 	if (GetWindowLong(hDlg, DWL_USER)) {
485 		//	the target file exists and overwritable
486 		overwrite = (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) == BST_CHECKED);
487 		truncate = (IsDlgButtonChecked(hDlg, IDC_TRUNCATE) == BST_CHECKED);
488 	}
489 	else {
490 		overwrite = FALSE;
491 		truncate = TRUE;
492 	}
493 
494 retry:
495 	ret = VfdDismountVolume(param->hDevice, FALSE);
496 
497 	if (ret == ERROR_ACCESS_DENIED) {
498 		PSTR msg = ModuleMessage(MSG_UNMOUNT_CONFIRM);
499 
500 		int reply = MessageBox(
501 			hDlg, msg ? msg : "retry", VFD_MSGBOX_TITLE,
502 			MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE);
503 
504 		if (msg) {
505 			LocalFree(msg);
506 		}
507 
508 		if (reply == IDRETRY) {
509 			goto retry;
510 		}
511 		else if (reply == IDCANCEL) {
512 			return ERROR_CANCELLED;
513 		}
514 		else {
515 			VfdDismountVolume(param->hDevice, TRUE);
516 		}
517 	}
518 	else if (ret != ERROR_SUCCESS) {
519 
520 		MessageBox(hDlg, SystemMessage(ret),
521 			VFD_MSGBOX_TITLE, MB_ICONSTOP);
522 
523 		return ret;
524 	}
525 
526 	ret = VfdSaveImage(param->hDevice, path, overwrite, truncate);
527 
528 	if (ret != ERROR_SUCCESS) {
529 
530 		//	show error message
531 
532 		MessageBox(hDlg, SystemMessage(ret),
533 			VFD_MSGBOX_TITLE, MB_ICONSTOP);
534 	}
535 
536 	return ret;
537 }
538