summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-03-12 02:15:51 +0000
committerPete Batard <pbatard@gmail.com>2010-03-12 02:15:51 +0000
commit73cdd86fe78d5ae53bb3d6989a8bc7a78c51e3bb (patch)
treee8ef38bbc95b4b441a0b1b36b480c58d8788132b
parent53110b64d149ffd63320dcef3a706d94ebd40d10 (diff)
downloadlibusb-73cdd86fe78d5ae53bb3d6989a8bc7a78c51e3bb.tar.gz
pipe communication between installer and other improvementsa166
-rw-r--r--examples/lsusb.c4
-rw-r--r--libusb/os/driver_install.c130
-rw-r--r--libusb/os/driver_install.h3
-rw-r--r--libusb/os/driver_installer.c138
-rw-r--r--libusb/os/windows_usb.h13
5 files changed, 251 insertions, 37 deletions
diff --git a/examples/lsusb.c b/examples/lsusb.c
index 488de4e..3b0495f 100644
--- a/examples/lsusb.c
+++ b/examples/lsusb.c
@@ -55,10 +55,10 @@ main(void)
drv_info = list_driverless();
for (; drv_info != NULL; drv_info = drv_info->next) {
if (create_inf(drv_info, "C:\\test") == 0) {
- install_device("C:\\test");
+ run_installer("C:\\test");
}
}
-
+ update_drivers();
return 0;
r = libusb_init(NULL);
diff --git a/libusb/os/driver_install.c b/libusb/os/driver_install.c
index 3c2cc36..83b7bde 100644
--- a/libusb/os/driver_install.c
+++ b/libusb/os/driver_install.c
@@ -12,6 +12,7 @@
#include "windows_usb.h"
#include "driver_install.h"
+#define INF_NAME "libusb-device.inf"
const char inf[] = "Date = \"03/08/2010\"\n\n" \
"ProviderName = \"libusb 1.0\"\n" \
@@ -122,6 +123,8 @@ static int init_cfgmgr32(void)
DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE);
DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE);
DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDW, TRUE);
+ DLL_LOAD(Cfgmgr32.dll, CM_Locate_DevNode, TRUE);
+ DLL_LOAD(Cfgmgr32.dll, CM_Reenumerate_DevNode, TRUE);
return LIBUSB_SUCCESS;
}
@@ -307,7 +310,7 @@ int extract_dlls(char* path)
fclose(fd);
}
- usbi_dbg("so far, so good");
+ usbi_dbg("successfully extracted files to %s", path);
return 0;
}
@@ -332,7 +335,8 @@ int create_inf(struct driver_info* drv_info, char* path)
extract_dlls(path);
safe_strcpy(filename, MAX_PATH_LENGTH, path);
- safe_strcat(filename, MAX_PATH_LENGTH, "\\libusb_device.inf");
+ safe_strcat(filename, MAX_PATH_LENGTH, "\\");
+ safe_strcat(filename, MAX_PATH_LENGTH, INF_NAME);
fd = fopen(filename, "w");
if (fd == NULL) {
@@ -353,14 +357,41 @@ int create_inf(struct driver_info* drv_info, char* path)
CoCreateGuid(&guid);
fprintf(fd, "DeviceGUID = \"%s\"\n", guid_to_string(guid));
fwrite(inf, sizeof(inf)-1, 1, fd);
+ fclose(fd);
+
+ usbi_dbg("succesfully created %s", filename);
return 0;
}
// TODO: extract driver-installer.exe into the dest dir
-int install_device(char* path)
+int run_installer(char* path)
{
SHELLEXECUTEINFO shExecInfo;
char exename[MAX_PATH_LENGTH];
+ HANDLE handle[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ HANDLE pipe = INVALID_HANDLE_VALUE;
+ OVERLAPPED overlapped;
+ int r, ret;
+ DWORD rd_count;
+ char buffer[256];
+
+
+ // Use a pipe to communicate with our installer
+ pipe = CreateNamedPipe("\\\\.\\pipe\\libusb-installer", PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE, 1, 4096, 4096, 0, NULL);
+ if (pipe == INVALID_HANDLE_VALUE) {
+ usbi_err(NULL, "could not create read pipe: errcode %d", (int)GetLastError());
+ r = -1; goto out;
+ }
+
+ // Set the overlapped for messaging
+ memset(&overlapped, 0, sizeof(OVERLAPPED));
+ handle[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(!handle[0]) {
+ r = -1; goto out;
+ }
+ overlapped.hEvent = handle[0];
+
safe_strcpy(exename, MAX_PATH_LENGTH, path);
safe_strcat(exename, MAX_PATH_LENGTH, "\\driver-installer.exe");
@@ -370,13 +401,100 @@ int install_device(char* path)
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = "runas";
shExecInfo.lpFile = exename;
- shExecInfo.lpParameters = NULL;
+ // if INF_NAME ever has a space, it will be seen as multiple parameters
+ shExecInfo.lpParameters = INF_NAME;
shExecInfo.lpDirectory = path;
- shExecInfo.nShow = SW_MAXIMIZE;
+ shExecInfo.nShow = SW_HIDE;
+ // SW_NORMAL;
shExecInfo.hInstApp = NULL;
ShellExecuteEx(&shExecInfo);
- usbi_dbg("hProcess = %p", shExecInfo.hProcess);
+ if (shExecInfo.hProcess == NULL) {
+ usbi_dbg("Installer did not run");
+ r = -1; goto out;
+ }
+ handle[1] = shExecInfo.hProcess;
+
+ while (1) {
+ if (!ReadFile(pipe, buffer, 256, &rd_count, &overlapped)) {
+ switch(GetLastError()) {
+ case ERROR_BROKEN_PIPE:
+ // The pipe has been ended - wait for installer to finish
+ WaitForSingleObject(handle[1], INFINITE);
+ usbi_dbg("hProcess1 = %p terminated", shExecInfo.hProcess);
+ r = 0; goto out;
+ case ERROR_PIPE_LISTENING:
+ // Wait for installer to open the pipe
+ Sleep(100);
+ continue;
+ case ERROR_IO_PENDING:
+ break;
+ default:
+ usbi_err(NULL, "pipe read message failed: %d", (int)GetLastError());
+ continue;
+ }
+
+ // We have IO_PENDING
+ switch(WaitForMultipleObjects(2, handle, FALSE, INFINITE)) {
+ case WAIT_OBJECT_0: // Pipe event
+ if (!GetOverlappedResult(pipe, &overlapped, &rd_count, FALSE)) {
+ switch(GetLastError()) {
+ case ERROR_BROKEN_PIPE:
+ // The pipe has been ended - wait for installer to finish
+ WaitForSingleObject(handle[1], INFINITE);
+ usbi_dbg("hProcess3 = %p terminated", shExecInfo.hProcess);
+ r = 0; goto out;
+ case ERROR_MORE_DATA:
+ usbi_warn(NULL, "message overflow");
+ break;
+ default:
+ usbi_warn(NULL, "message async read error: %d", (int)GetLastError());
+ break;
+ }
+ } else {
+ usbi_dbg("async: %s", buffer);
+ }
+ break;
+ case WAIT_OBJECT_0+1:
+ usbi_dbg("hProcess2 = %p terminated", shExecInfo.hProcess);
+ r = 0; goto out;
+ default:
+ usbi_dbg("are?");
+ break;
+ }
+ } else {
+ usbi_dbg(" sync: %s", buffer);
+ }
+ }
+out:
+ safe_closehandle(handle[0]);
+ safe_closehandle(handle[1]);
+ safe_closehandle(pipe);
+ return r;
+}
+
+// TODO: use devinst from setupdi and pass it as param to driver-installer.exe
+int update_drivers(void)
+{
+ DEVINST devInst;
+ CONFIGRET status;
+
+ usbi_dbg("updating drivers, please wait...");
+ // Get the root devnode.
+ status = CM_Locate_DevNode(&devInst, NULL, 0);
+ if (status != CR_SUCCESS) {
+ printf("failed to locate root devnode: %x\n", status);
+ return -1;
+ }
+
+ // Needs admin privileges, but even with admin and the
+ // http://support.microsoft.com/kb/259697 doesn't work!!!
+ status = CM_Reenumerate_DevNode(devInst, 0);
+ if (status != CR_SUCCESS) {
+ printf("failed to re-enumerate nodes: %x\n", status);
+ return -1;
+ }
+
return 0;
} \ No newline at end of file
diff --git a/libusb/os/driver_install.h b/libusb/os/driver_install.h
index 81688b3..3a3b6a8 100644
--- a/libusb/os/driver_install.h
+++ b/libusb/os/driver_install.h
@@ -14,7 +14,8 @@ struct driver_info {
struct driver_info *list_driverless(void);
char* guid_to_string(const GUID guid);
int create_inf(struct driver_info* drv_info, char* path);
-int install_device(char* path);
+int run_installer(char* path);
+int update_drivers(void);
diff --git a/libusb/os/driver_installer.c b/libusb/os/driver_installer.c
index 7f58d92..c6f7d63 100644
--- a/libusb/os/driver_installer.c
+++ b/libusb/os/driver_installer.c
@@ -9,67 +9,149 @@
#include <inttypes.h>
#include <direct.h>
#include <api/difxapi.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdarg.h>
-
-#define MAX_PATH_LENGTH 128
+#define INF_NAME "libusb-device.inf"
+#define MAX_PATH_LENGTH 128
+#define safe_strncpy(dst, dst_max, src, count) strncpy(dst, src, min(count, dst_max - 1))
+#define safe_strcpy(dst, dst_max, src) safe_strncpy(dst, dst_max, src, strlen(src)+1)
#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, min(count, dst_max - strlen(dst) - 1))
#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, strlen(src)+1)
+HANDLE pipe = INVALID_HANDLE_VALUE;
+
+// TODO: return a status byte along with the message
+void plog_v(const char *format, va_list args)
+{
+ char buffer[256];
+ int size;
+
+ if (pipe == INVALID_HANDLE_VALUE)
+ return;
+
+ size = vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
+ if (size < 0) {
+ buffer[255] = 0;
+ size = 255;
+ }
+ WriteFile(pipe, buffer, size+1, &size, NULL);
+}
+
+void plog(const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ plog_v(format, args);
+ va_end (args);
+}
+
+void __cdecl log_callback(DIFXAPI_LOG Event, DWORD Error, const TCHAR * pEventDescription, PVOID CallbackContext)
+{
+ if (Error == 0){
+ plog("(%u) %s", Event, pEventDescription);
+ } else {
+ plog("(%u) Error:%u - %s", Event, Error, pEventDescription);
+ }
+}
+
int main(int argc, char** argv)
{
DWORD r;
BOOL reboot_needed;
char path[MAX_PATH_LENGTH];
-// INSTALLERINFO installer_info;
+ char log[MAX_PATH_LENGTH];
+ FILE *fd;
- _getcwd(path, MAX_PATH_LENGTH);
- safe_strcat(path, MAX_PATH_LENGTH, "\\libusb_device.inf");
+ // Connect to the messaging pipe
+ pipe = CreateFile("\\\\.\\pipe\\libusb-installer", GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
+ if (pipe == INVALID_HANDLE_VALUE) {
+ // Try to write on console
+ printf("could not open pipe for writing: errcode %d\n", (int)GetLastError());
+ return -1;
+ }
+ safe_strcpy(log, MAX_PATH_LENGTH, argv[0]);
+ // TODO - seek for terminal '.exe' and change extension if needed
+ safe_strcat(log, MAX_PATH_LENGTH, ".log");
- r = DriverPackagePreinstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR);
+ fd = fopen(log, "w");
+ if (fd == NULL) {
+ plog("could not open logfile");
+ goto out;
+ }
+
+ if (argc >= 2) {
+ plog("got parameter %s", argv[1]);
+ printf("got param %s", argv[1]);
+ }
+
+ // TODO: use GetFullPathName() to get full inf path
+ _getcwd(path, MAX_PATH_LENGTH);
+ safe_strcat(path, MAX_PATH_LENGTH, "\\");
+ safe_strcat(path, MAX_PATH_LENGTH, INF_NAME);
+
+ plog("Installing driver - please wait...");
+ DIFXAPISetLogCallback(log_callback, NULL);
+ // TODO: set app dependency?
+ r = DriverPackageInstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR|DRIVER_PACKAGE_FORCE,
+ NULL, &reboot_needed);
+ DIFXAPISetLogCallback(NULL, NULL);
// Will fail if inf not signed, unless DRIVER_PACKAGE_LEGACY_MODE is specified.
// r = 87 ERROR_INVALID_PARAMETER on path == NULL
// r = 2 ERROR_FILE_NOT_FOUND if no inf in path
// r = 5 ERROR_ACCESS_DENIED if needs admin elevation
- // r = 0xE0000003 ERROR_GENERAL_SYNTAX the syntax of the inf is invalid
+ // r = 0xE0000003 ERROR_GENERAL_SYNTAX the syntax of the inf is invalid or the inf is empty
// r = 0xE0000304 ERROR_INVALID_CATALOG_DATA => no cat
+ // r = 0xE000023F ERROR_NO_AUTHENTICODE_CATALOG => user cancelled on warnings
// r = 0xE0000247 if user decided not to install on warnings
// r = 0x800B0100 ERROR_WRONG_INF_STYLE => missing cat entry in inf
// r = 0xB7 => missing DRIVER_PACKAGE_REPAIR flag
switch(r) {
+ case 0:
+ plog(" completed");
+ plog("reboot %s needed", reboot_needed?"":"not");
+ break;
+ case ERROR_NO_MORE_ITEMS:
+ plog("more recent driver was found (DRIVER_PACKAGE_FORCE option required)");
+ goto out;
+ case ERROR_NO_SUCH_DEVINST:
+ plog("device not detected (DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT needs to be disabled)");
+ goto out;
case ERROR_INVALID_PARAMETER:
- printf("invalid path\n");
- return -1;
+ plog("invalid path");
+ goto out;
case ERROR_FILE_NOT_FOUND:
- printf("unable to find inf file on %s\n", path);
- return -1;
+ plog("unable to find inf file on %s", path);
+ goto out;
case ERROR_ACCESS_DENIED:
- printf("this process needs to be run with administrative privileges\n");
- return -1;
+ plog("this process needs to be run with administrative privileges");
+ goto out;
case ERROR_WRONG_INF_STYLE:
case ERROR_GENERAL_SYNTAX:
- printf("the syntax of the inf is invalid\n");
- return -1;
+ plog("the syntax of the inf is invalid");
+ goto out;
case ERROR_INVALID_CATALOG_DATA:
- printf("unable to locate cat file\n");
- return -1;
+ plog("unable to locate cat file");
+ goto out;
+ case ERROR_NO_AUTHENTICODE_CATALOG:
case ERROR_DRIVER_STORE_ADD_FAILED:
- printf("cancelled by user\n");
- return -1;
+ plog("cancelled by user");
+ goto out;
// TODO: make DRIVER_PACKAGE_REPAIR optional
case ERROR_ALREADY_EXISTS:
- printf("driver already exists\n");
- return -1;
+ plog("driver already exists");
+ goto out;
default:
- printf("unhandled error %X\n", r);
- return -1;
+ plog("unhandled error %X", r);
+ goto out;
}
- // TODO: use
- r = DriverPackageInstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR,
- NULL, &reboot_needed);
- printf("ret = %X\n", r);
-
+out:
+ CloseHandle(pipe);
return 0;
} \ No newline at end of file
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 30560b5..a7aaf7e 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -400,11 +400,24 @@ typedef enum _USB_HUB_NODE {
} USB_HUB_NODE;
/* Cfgmgr32.dll interface */
+typedef CHAR *DEVNODEID_A, *DEVINSTID_A;
+typedef WCHAR *DEVNODEID_W, *DEVINSTID_W;
+
+#ifdef UNICODE
+typedef DEVNODEID_W DEVNODEID;
+typedef DEVINSTID_W DEVINSTID;
+#else
+typedef DEVNODEID_A DEVNODEID;
+typedef DEVINSTID_A DEVINSTID;
+#endif
+
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG));
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDW, (DEVINST, PWCHAR, ULONG, ULONG));
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Locate_DevNode, (PDEVINST, DEVINSTID, ULONG));
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Reenumerate_DevNode, (DEVINST, ULONG));
#ifdef UNICODE
#define CM_Get_Device_ID CM_Get_Device_IDW