From: John Tsiombikas Date: Sat, 11 Jan 2020 13:28:28 +0000 (+0200) Subject: it werks! X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=instimg;a=commitdiff_plain;h=4f2abaf24d97f5d6fc253cca51ec87a8a95ab048 it werks! --- diff --git a/src/main.c b/src/main.c index 5f4de5d..3717955 100644 --- a/src/main.c +++ b/src/main.c @@ -1,47 +1,69 @@ #include #include #include +#include #include +#include #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(); @@ -50,10 +72,133 @@ int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst, char *cmdline, int show 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; @@ -86,11 +231,14 @@ static void update_disks(void) } if(wgt_checkbox_checked(ck_usbonly)) { - for(i=0; i= 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); } } @@ -134,3 +327,9 @@ static void ck_usbonly_handler(struct wgt_widget *w) { update_disks(); } + +static int close_action(struct wgt_window *w) +{ + if(w != win) return 0; + return 1; +} \ No newline at end of file diff --git a/src/rawdisk.c b/src/rawdisk.c index 559f61f..ba861dc 100644 --- a/src/rawdisk.c +++ b/src/rawdisk.c @@ -1,16 +1,21 @@ #include #include #include +#include #include #include #include #include #include "rawdisk.h" -/*#define DBG_FAKE_DISKS*/ +#undef DBG_FAKE_DISKS static GUID guid_iface_disk = {0x53f56307, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}}; +#ifndef IOCTL_DISK_UPDATE_PROPERTIES +#define IOCTL_DISK_UPDATE_PROPERTIES CTL_CODE(IOCTL_DISK_BASE,0x0050,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif + int rawdisk_detect(struct rawdisk_device *disks, int max_disks) { int devidx, ifidx, count; @@ -95,3 +100,29 @@ int rawdisk_detect(struct rawdisk_device *disks, int max_disks) return count; } + +int rawdisk_eject(HANDLE hdev) +{ + DWORD sz; + return DeviceIoControl(hdev, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &sz, 0) == 0 ? -1 : 0; +} + +int rawdisk_load(HANDLE hdev) +{ + DWORD sz; + return DeviceIoControl(hdev, IOCTL_STORAGE_LOAD_MEDIA, 0, 0, 0, 0, &sz, 0) == 0 ? -1 : 0; +} + +void rawdisk_refresh(HANDLE hdev) +{ + DWORD sz; + char *buf; + + /* try to rock the boat so hopefully windows will re-read the disk and it'll show up */ + DeviceIoControl(hdev, IOCTL_DISK_UPDATE_PROPERTIES, 0, 0, 0, 0, &sz, 0); + + sz = sizeof(DRIVE_LAYOUT_INFORMATION) + sizeof(PARTITION_INFORMATION) * 32; + buf = alloca(sz); + + DeviceIoControl(hdev, IOCTL_DISK_GET_DRIVE_LAYOUT, 0, 0, buf, sz, &sz, 0); +} \ No newline at end of file diff --git a/src/rawdisk.h b/src/rawdisk.h index 5c843b1..797fb4a 100644 --- a/src/rawdisk.h +++ b/src/rawdisk.h @@ -1,6 +1,8 @@ #ifndef RAWDISK_H_ #define RAWDISK_H_ +#include + struct rawdisk_device { char *name; char *path; @@ -8,4 +10,9 @@ struct rawdisk_device { int rawdisk_detect(struct rawdisk_device *disks, int max_disks); +int rawdisk_eject(HANDLE hdev); +int rawdisk_load(HANDLE hdev); + +void rawdisk_refresh(HANDLE hdev); + #endif /* RAWDISK_H_ */ \ No newline at end of file diff --git a/src/widgets.c b/src/widgets.c index 2d37973..1b97637 100644 --- a/src/widgets.c +++ b/src/widgets.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "widgets.h" struct wgt_window { @@ -12,6 +13,9 @@ struct wgt_window { HDC dc; char cname[32]; struct wgt_widget *wlist; + + int close_quit; + int (*cb_close)(struct wgt_window*); }; struct wgt_widget { @@ -34,6 +38,28 @@ 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; @@ -43,11 +69,11 @@ struct wgt_window *wgt_window(const char *title, int width, int height) 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) { @@ -72,7 +98,7 @@ struct wgt_window *wgt_window(const char *title, int width, int height) 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); @@ -107,10 +133,16 @@ void wgt_destroy_window(struct wgt_window *win) 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); } @@ -120,6 +152,23 @@ void wgt_destroy_widget(struct wgt_widget *w) 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; @@ -150,6 +199,20 @@ struct wgt_rect *wgt_widget_rect(struct wgt_widget *w, struct wgt_rect *rect) 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) { @@ -273,6 +336,7 @@ struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on free(w); return 0; } + SendMessage(w->handle, BM_SETCHECK, on ? BST_CHECKED : BST_UNCHECKED, 0); w->rect.x = x; w->rect.y = y; @@ -361,6 +425,56 @@ struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num 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); @@ -432,6 +546,11 @@ const char *wgt_get_combo_item(struct wgt_widget *w, int idx) 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; @@ -442,8 +561,22 @@ static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, L 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: diff --git a/src/widgets.h b/src/widgets.h index caf4a4e..d170966 100644 --- a/src/widgets.h +++ b/src/widgets.h @@ -16,15 +16,31 @@ struct wgt_rect { 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); @@ -36,6 +52,9 @@ struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on 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); @@ -45,4 +64,6 @@ int wgt_combo_setitems(struct wgt_widget *w, const char **items, int num_items); 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_ */