#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
+#include <malloc.h>
#include <windows.h>
+#include <winioctl.h>
#include "widgets.h"
#include "rawdisk.h"
+#define IMG_FNAME "disk.img"
+
+static int instimg(const char *devpath);
+static void update_disks(void);
+static void onclick(struct wgt_widget *w);
+static void onmodify(struct wgt_widget *w);
+static void ck_usbonly_handler(struct wgt_widget *w);
+
+
static struct wgt_window *win;
-static struct wgt_widget *lb_instto, *bn_inst, *bn_cancel, *cb_devs, *ck_usbonly;
+static struct wgt_widget *lb_instto, *bn_inst, *bn_cancel, *cb_devs, *ck_usbonly, *bn_cancel_inst;
static struct rawdisk_device rawdev[64];
static const char *items[64];
static int num_rawdev;
-
-static void update_disks(void);
-static void onclick(struct wgt_widget *w);
-static void onmodify(struct wgt_widget *w);
-static void ck_usbonly_handler(struct wgt_widget *w);
+static FILE *imgfile;
+static long imgfile_size;
+static const char *err_noimg_fmt =
+ "Failed to open 256boss disk image: " IMG_FNAME "\n"
+ "%s\n"
+ "\n"
+ "Please run this installer from the 256boss distribution directory";
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst, char *cmdline, int showcmd)
{
int x, y;
MSG msg;
+ char *msgbuf, *errmsg;
+ if(!(imgfile = fopen(IMG_FNAME, "rb"))) {
+ errmsg = strerror(errno);
+ msgbuf = alloca(strlen(err_noimg_fmt) + strlen(errmsg) + 1);
+ sprintf(msgbuf, err_noimg_fmt, errmsg);
+ MessageBox(0, msgbuf, "Missing disk image!", MB_OK | MB_ICONSTOP | MB_APPLMODAL);
+ return 1;
+ }
+ fseek(imgfile, 0, SEEK_END);
+ imgfile_size = ftell(imgfile);
- if(!(win = wgt_window("256boss USB stick installer", 400, 300))) {
+ if(!(win = wgt_window("256boss USB stick installer", 420, 170))) {
+ fclose(imgfile);
return 1;
}
- lb_instto = wgt_label(win, "Install to device:", 10, 10);
+ lb_instto = wgt_label(win, "Install to device:", 10, 20);
x = wgt_xpos_after(lb_instto, WGT_AUTO);
- cb_devs = wgt_combo(win, items, num_rawdev, 0, x, 10, 200, WGT_AUTO, onmodify);
+ cb_devs = wgt_combo(win, items, num_rawdev, 0, x, 20, 270, WGT_AUTO, onmodify);
y = wgt_ypos_after(cb_devs, 16);
ck_usbonly = wgt_checkbox(win, "only show USB devices", 1, x, y,
WGT_AUTO, WGT_AUTO, ck_usbonly_handler);
- y = wgt_ypos_after(ck_usbonly, 16);
- bn_inst = wgt_button(win, "Install", 10, y, WGT_AUTO, WGT_AUTO, onclick);
-
- x = wgt_xpos_after(bn_inst, WGT_AUTO);
- bn_cancel = wgt_button(win, "Cancel", x, y, WGT_AUTO, WGT_AUTO, onclick);
+ y = wgt_ypos_after(ck_usbonly, 32);
+ bn_inst = wgt_button(win, "Install", 70, y, 100, WGT_AUTO, onclick);
+ bn_cancel = wgt_button(win, "Cancel", 230, y, 100, WGT_AUTO, onclick);
update_disks();
DispatchMessage(&msg);
}
- wgt_destroy_window(win);
+ fclose(imgfile);
+ wgt_free_window(win);
return 0;
}
+#define WIN_XPAD 10
+#define WIN_YPAD 10
+#define MIN_BS (4 * 1024 * 1024)
+
+static int instimg(const char *devpath)
+{
+ MSG msg;
+ HANDLE hdev;
+ DWORD wrcount;
+ DISK_GEOMETRY geom;
+ int width, max_width, height, y, sz, blksz = 512, status = -1;
+ char *blkbuf;
+ struct wgt_window *win_inst;
+ struct wgt_widget *w, *pbar, *ptext;
+ struct wgt_rect *rect;
+ long num_blk_done, total_blk;
+ int progr;
+
+ if(!(hdev = CreateFile(devpath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0))) {
+ return -1;
+ }
+
+ if(rawdisk_eject(hdev) == 0) {
+ rawdisk_load(hdev);
+ }
+
+ if(DeviceIoControl(hdev, IOCTL_DISK_GET_DRIVE_GEOMETRY, 0, 0, &geom, sizeof geom, &wrcount, 0)) {
+ blksz = geom.BytesPerSector;
+ }
+
+ while(blksz < MIN_BS) blksz <<= 1;
+
+ num_blk_done = 0;
+ total_blk = (imgfile_size + blksz - 1) / blksz;
+
+ if(!(blkbuf = malloc(blksz))) {
+ CloseHandle(hdev);
+ return -1;
+ }
+
+ max_width = 0;
+
+ win_inst = wgt_window("Installing ...", 320, 140);
+ wgt_quit_on_close(win_inst, 0);
+
+ y = WIN_YPAD;
+ sprintf(blkbuf, "Device sector size: %d bytes", (int)geom.BytesPerSector);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ sprintf(blkbuf, "Copying in blocks of: %d bytes", blksz);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ sprintf(blkbuf, "Image size: %ld bytes (%ld blocks)", imgfile_size, total_blk);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ ptext = wgt_label(win_inst, "-/- (0%)", WIN_XPAD, y);
+
+ y = wgt_ypos_after(ptext, 8);
+ pbar = wgt_progbar(win_inst, WIN_XPAD, y, width - WIN_XPAD * 2, WGT_AUTO, 0);
+ if((width = wgt_xpos_after(pbar, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(pbar, 8);
+ bn_cancel_inst = wgt_button(win_inst, "Cancel", 100, y, WGT_AUTO, WGT_AUTO, onclick);
+ rect = wgt_widget_rect(bn_cancel_inst, 0);
+ wgt_move_widget(bn_cancel_inst, WIN_XPAD + (width - rect->width) / 2, rect->y);
+
+ height = wgt_ypos_after(bn_cancel_inst, WIN_YPAD);
+
+ max_width += GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
+ height += GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);
+ wgt_resize_window(win_inst, max_width, height);
+
+ /* go through any pending messages once first, to allow the window to get drawn correctly */
+ while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if(msg.message == WM_CLOSE || msg.message == WM_DESTROY) {
+ goto end;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ rewind(imgfile);
+ while((sz = fread(blkbuf, 1, blksz, imgfile)) > 0) {
+ if(sz < blksz) {
+ memset(blkbuf + sz, 0, blksz - sz);
+ }
+ SetFilePointer(hdev, num_blk_done * blksz, 0, FILE_BEGIN);
+ WriteFile(hdev, blkbuf, blksz, &wrcount, 0);
+
+ num_blk_done++;
+ progr = num_blk_done * 100 / total_blk;
+ sprintf(blkbuf, "%ld/%ld (%d%%)", num_blk_done, total_blk, progr);
+ wgt_set_text(ptext, blkbuf);
+ wgt_set_progress(pbar, progr);
+
+ while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if(msg.message == WM_CLOSE || msg.message == WM_DESTROY) {
+ goto end;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ rawdisk_refresh(hdev);
+
+ status = 0;
+end:
+ wgt_free_window(win_inst);
+
+ free(blkbuf);
+ CloseHandle(hdev);
+ return status;
+}
+
static int isusbdev(struct rawdisk_device *dev)
{
char *ptr = dev->path;
}
if(wgt_checkbox_checked(ck_usbonly)) {
- for(i=0; i<num_rawdev; i++) {
+ i = 0;
+ while(i < num_rawdev) {
if(!isusbdev(rawdev + i)) {
free(rawdev[i].name);
free(rawdev[i].path);
rawdev[i] = rawdev[--num_rawdev];
+ } else {
+ i++;
}
}
}
}
}
+static const char *verify_fmt = \
+ "You are about to install 256boss to: %s\n"
+ "\n"
+ "Device path:\n"
+ "%s\n"
+ "\n"
+ "Any existing data in the selected device will be lost!\n"
+ "Please verify you have selected the intended device.\n"
+ "\n"
+ "Are you certain you wish to proceed with the installation?\n";
+
+static const char *success_str = \
+ "Installation complete!\n"
+ "\n"
+ "If the 256boss partition doesn't show up immediately,\n"
+ "please eject and re-attach the device\n";
+
static void onclick(struct wgt_widget *w)
{
+ int sel, len;
+ unsigned int flags;
+ char *msgbuf;
+ static int inst_running;
+
if(w == bn_inst) {
- MessageBox(0, "clicked", "clicked", MB_OK);
+ if(inst_running) return;
+
+ sel = wgt_combo_selected(cb_devs);
+ if(sel < 0 || sel >= num_rawdev) {
+ return;
+ }
+
+ len = strlen(verify_fmt) + strlen(rawdev[sel].name) + strlen(rawdev[sel].path);
+ msgbuf = alloca(len + 1);
+ sprintf(msgbuf, verify_fmt, rawdev[sel].name, rawdev[sel].path);
+
+ flags = MB_YESNO | MB_ICONWARNING | MB_APPLMODAL | MB_SETFOREGROUND;
+ if(MessageBox(0, msgbuf, "Proceed with installation?", flags) == IDYES) {
+ inst_running = 1;
+ if(instimg(rawdev[sel].path) == -1) {
+ MessageBox(0, "Installation failed", 0, MB_OK | MB_ICONSTOP | MB_APPLMODAL | MB_SETFOREGROUND);
+ } else {
+ MessageBox(0, success_str, "Done", MB_OK | MB_ICONASTERISK | MB_APPLMODAL | MB_SETFOREGROUND);
+ }
+ inst_running = 0;
+ }
+
} else if(w == bn_cancel) {
PostQuitMessage(0);
- } else if(w == ck_usbonly) {
- update_disks();
+
+ } else if(w == bn_cancel_inst) {
+ struct wgt_window *win = wgt_widget_window(w);
+ PostMessage(wgt_window_handle(win), WM_CLOSE, 0, 0);
}
}
{
update_disks();
}
+
+static int close_action(struct wgt_window *w)
+{
+ if(w != win) return 0;
+ return 1;
+}
\ No newline at end of file
#include <string.h>
#include <assert.h>
#include <windows.h>
+#include <commctrl.h>
#include "widgets.h"
struct wgt_window {
HDC dc;
char cname[32];
struct wgt_widget *wlist;
+
+ int close_quit;
+ int (*cb_close)(struct wgt_window*);
};
struct wgt_widget {
static LRESULT WINAPI event_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle);
+
+void *wgt_window_handle(struct wgt_window *win)
+{
+ return win->handle;
+}
+
+void *wgt_widget_handle(struct wgt_widget *w)
+{
+ return w->handle;
+}
+
+unsigned int wgt_window_xid(struct wgt_window *win)
+{
+ return 0;
+}
+
+unsigned int wgt_widget_xid(struct wgt_widget *w)
+{
+ return 0;
+}
+
+
struct wgt_window *wgt_window(const char *title, int width, int height)
{
struct wgt_window *win;
DWORD err;
RECT rect;
- if(!(win = malloc(sizeof *win))) {
+ if(!(win = calloc(1, sizeof *win))) {
fprintf(stderr, "wgl_create_window: failed to allocate window structure\n");
return 0;
}
- win->wlist = 0;
+ win->close_quit = 1; /* by default quit when the window closes */
tlen = strlen(title);
if(tlen > sizeof win->cname - 10) {
return 0;
}
- if(!(win->handle = CreateWindow(win->cname, title, WS_OVERLAPPEDWINDOW,
+ if(!(win->handle = CreateWindow(win->cname, title, WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, hinst, 0))) {
fprintf(stderr, "wgt_create_window: failed to create window\n");
UnregisterClass(title, hinst);
free(w);
}
- ReleaseDC(win->handle, win->dc);
- DestroyWindow(win->handle);
- UnregisterClass(win->cname, GetModuleHandle(0));
+ if(win->handle) {
+ ReleaseDC(win->handle, win->dc);
+ DestroyWindow(win->handle);
+ UnregisterClass(win->cname, GetModuleHandle(0));
+ }
+}
+void wgt_free_window(struct wgt_window *win)
+{
+ wgt_destroy_window(win);
free(win);
}
free(w->itemlist);
}
+void wgt_resize_window(struct wgt_window *win, int width, int height)
+{
+ MoveWindow(win->handle, win->rect.x, win->rect.y, width, height, TRUE);
+ win->rect.width = width;
+ win->rect.height = height;
+}
+
+void wgt_quit_on_close(struct wgt_window *win, int quit)
+{
+ win->close_quit = quit;
+}
+
+void wgt_close_action(struct wgt_window *win, int (*func)(struct wgt_window*))
+{
+ win->cb_close = func;
+}
+
void wgt_enable_widget(struct wgt_widget *w)
{
w->disabled = 0;
return &w->rect;
}
+void wgt_move_widget(struct wgt_widget *w, int x, int y)
+{
+ MoveWindow(w->handle, x, y, w->rect.width, w->rect.height, TRUE);
+ w->rect.x = x;
+ w->rect.y = y;
+}
+
+void wgt_resize_widget(struct wgt_widget *w, int width, int height)
+{
+ MoveWindow(w->handle, w->rect.x, w->rect.y, width, height, TRUE);
+ w->rect.width = width;
+ w->rect.height = height;
+}
+
int wgt_xpos_after(struct wgt_widget *w, int pad)
{
if(pad == WGT_AUTO) {
free(w);
return 0;
}
+ SendMessage(w->handle, BM_SETCHECK, on ? BST_CHECKED : BST_UNCHECKED, 0);
w->rect.x = x;
w->rect.y = y;
return w;
}
+struct wgt_widget *wgt_progbar(struct wgt_window *win, int x, int y, int width, int height, int p)
+{
+ struct wgt_widget *w;
+ INITCOMMONCONTROLSEX commctrl;
+
+ commctrl.dwSize = sizeof commctrl;
+ commctrl.dwICC = ICC_PROGRESS_CLASS;
+ InitCommonControlsEx(&commctrl);
+
+ if(!(w = calloc(1, sizeof *w))) {
+ fprintf(stderr, "wgt_progbar: failed to allocate widget structure\n");
+ return 0;
+ }
+ w->win = win;
+
+ if(height < 0) {
+ height = GetSystemMetrics(SM_CYVSCROLL);
+ }
+
+ if(!(w->handle = CreateWindow(PROGRESS_CLASS, 0, WS_CHILD | WS_VISIBLE, x, y,
+ width, height, win->handle, 0, GetModuleHandle(0), 0))) {
+ fprintf(stderr, "wgt_progbar: failed to create window\n");
+ free(w);
+ return 0;
+ }
+
+ /*
+ SendMessage(w->handle, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
+ SendMessage(w->handle, PBM_SETSTEP, 1, 0);
+ */
+ SendMessage(w->handle, PBM_SETPOS, p, 0);
+
+ w->rect.x = x;
+ w->rect.y = y;
+ w->rect.width = width;
+ w->rect.height = height;
+
+ w->next = win->wlist;
+ win->wlist = w;
+ return w;
+}
+
+void wgt_set_text(struct wgt_widget *w, const char *text)
+{
+ SendMessage(w->handle, WM_SETTEXT, 0, (long)text);
+
+ w->rect.width = wgt_string_size(w->win, text, 0);
+ MoveWindow(w->handle, w->rect.x, w->rect.y, w->rect.width, w->rect.height, TRUE);
+}
+
void wgt_checkbox_check(struct wgt_widget *w)
{
SendMessage(w->handle, BM_SETCHECK, BST_CHECKED, 0);
return w->itemlist[idx];
}
+void wgt_set_progress(struct wgt_widget *w, int p)
+{
+ SendMessage(w->handle, PBM_SETPOS, p, 0);
+}
+
static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
{
int ncode;
switch(msg) {
case WM_CLOSE:
+ if(!win->cb_close || win->cb_close(win)) {
+ if(win) {
+ int quit = win->close_quit;
+ wgt_destroy_window(win);
+ memset(win, 0, sizeof *win);
+ win->close_quit = quit;
+ } else {
+ DestroyWindow(wnd);
+ }
+ }
+ break;
+
case WM_DESTROY:
- PostQuitMessage(0);
+ if(win && win->close_quit) {
+ PostQuitMessage(0);
+ }
break;
case WM_COMMAND:
typedef void (*wgt_callback)(struct wgt_widget*);
+/* returns {win32: HWND, !win32: 0} */
+void *wgt_window_handle(struct wgt_window *win);
+void *wgt_widget_handle(struct wgt_widget *w);
+/* returns {UNIX: Window, !UNIX: 0} */
+unsigned int wgt_window_xid(struct wgt_window *win);
+unsigned int wgt_widget_xid(struct wgt_widget *w);
+
+
struct wgt_window *wgt_window(const char *title, int width, int height);
void wgt_destroy_window(struct wgt_window *win);
+void wgt_free_window(struct wgt_window *win); /* destroy and then free(win) */
void wgt_destroy_widget(struct wgt_widget *w);
+void wgt_resize_window(struct wgt_window *win, int width, int height);
+
+void wgt_quit_on_close(struct wgt_window *win, int quit);
+void wgt_close_action(struct wgt_window *win, int (*func)(struct wgt_window*));
+
void wgt_enable_widget(struct wgt_widget *w);
void wgt_disable_widget(struct wgt_widget *w);
int wgt_widget_enabled(struct wgt_widget *w);
struct wgt_window *wgt_widget_window(struct wgt_widget *w);
struct wgt_rect *wgt_widget_rect(struct wgt_widget *w, struct wgt_rect *rect);
+void wgt_move_widget(struct wgt_widget *w, int x, int y);
+void wgt_resize_widget(struct wgt_widget *w, int width, int height);
int wgt_xpos_after(struct wgt_widget *w, int pad);
int wgt_ypos_after(struct wgt_widget *w, int pad);
int wgt_string_size(struct wgt_window *win, const char *s, struct wgt_rect *rect);
int x, int y, int width, int height, wgt_callback modfunc);
struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num_items,
int sel, int x, int y, int width, int height, wgt_callback modfunc);
+struct wgt_widget *wgt_progbar(struct wgt_window *win, int x, int y, int width, int height, int p);
+
+void wgt_set_text(struct wgt_widget *w, const char *text);
void wgt_checkbox_check(struct wgt_widget *w);
void wgt_checkbox_uncheck(struct wgt_widget *w);
int wgt_combo_selected(struct wgt_widget *w);
const char *wgt_get_combo_item(struct wgt_widget *w, int idx);
+void wgt_set_progress(struct wgt_widget *w, int p);
+
#endif /* WIDGETS_H_ */