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