? setupapi.patch
Index: install.c
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/install.c,v
retrieving revision 1.8
diff -u -r1.8 install.c
--- install.c	11 Sep 2003 02:58:46 -0000	1.8
+++ install.c	20 Feb 2004 03:01:48 -0000
@@ -63,6 +63,9 @@
 static const WCHAR DelReg[]     = {'D','e','l','R','e','g',0};
 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
+static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
+static const WCHAR RunPreSetupCommands[] = {'R','u','n','P','r','e','S','e','t','u','p','C','o','m','m','a','n','d','s',0};
+static const WCHAR RunPostSetupCommands[] = {'R','u','n','P','o','s','t','S','e','t','u','p','C','o','m','m','a','n','d','s',0};
 
 
 /***********************************************************************
@@ -487,6 +490,196 @@
     return TRUE;
 }
 
+/***********************************************************************
+ *            runcmds_callback
+ *
+ * Called once for each command in a RunPre/PostSetupCommands section
+ */
+static BOOL runcmds_callback( HINF hinf, PCWSTR field, void *arg )
+{
+    STARTUPINFOW si;
+    PROCESS_INFORMATION info;
+    INFCONTEXT context;
+    DWORD errorlevel;
+    BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
+
+    TRACE("field '%s'\n", debugstr_w(field));
+
+    memset(&si, 0, sizeof(si));
+    si.cb=sizeof(si);
+    memset(&info, 0, sizeof(info));
+
+    for (; ok; ok = SetupFindNextLine( &context, &context ))
+    {
+        WCHAR buffer[MAX_INF_STRING_LENGTH];
+
+        if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
+            continue;
+
+        TRACE("buffer == %s\n", debugstr_w(buffer));
+ 
+        /* run the app */
+        if(!CreateProcessW(NULL, buffer, NULL, NULL, TRUE, 0L, NULL, NULL,
+                           &si, &info))
+        {
+            TRACE("CreateProcess failed to run cmd of '%s'\n", debugstr_w(buffer));
+        }
+
+        /* wait for completion */
+        WaitForSingleObject (info.hProcess, INFINITE);
+        GetExitCodeProcess (info.hProcess, &errorlevel);
+        if (errorlevel == STILL_ACTIVE) errorlevel = 0;
+
+        CloseHandle(info.hProcess);
+        CloseHandle(info.hThread);
+    }
+    return TRUE;
+}
+
+
+typedef HRESULT (*DLLREGISTER)          (void);
+
+/**
+ * Loads procedure.
+ *
+ * Parameters:
+ * strDll - name of the dll.
+ * procName - name of the procedure to load from dll
+ * pDllHandle - output variable receives handle of the loaded dll.
+ */
+static VOID *LoadProcW(WCHAR* strDll, char* procName, HMODULE* DllHandle)
+{
+    VOID* (*proc)(void);
+
+    *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+    if(!*DllHandle)
+    {
+        TRACE("Dll '%s' not found\n", debugstr_w(strDll));
+        return NULL;
+    }
+    proc = (VOID *) GetProcAddress(*DllHandle, procName);
+    if(!proc)
+    {
+        TRACE("'%s' not implemented in dll '%s'\n", procName, debugstr_w(strDll));
+        FreeLibrary(*DllHandle);
+        return NULL;
+    }
+    return proc;
+}
+
+static int RegisterDll(WCHAR* strDll)
+{
+    HRESULT hr;
+    DLLREGISTER pfRegister;
+    HMODULE DllHandle = NULL;
+
+    pfRegister = LoadProcW(strDll, "DllRegisterServer", &DllHandle);
+
+    if(!pfRegister)
+    {
+        TRACE("coulldn't find procedure '%s' in dll '%s'\n", "DllRegisterServer", debugstr_w(strDll));
+        return -1;
+    }
+
+    hr = pfRegister();
+    if(FAILED(hr))
+    {
+        TRACE("Failed to register dll '%s'\n", debugstr_w(strDll));
+        return -1;
+    }
+
+    TRACE("Successfully registered dll '%s'\n", debugstr_w(strDll));
+
+    if(DllHandle)
+        FreeLibrary(DllHandle);
+    return 0;
+}
+
+
+/***********************************************************************
+ *            registerdlls_callback
+ *
+ * Called once for each dll to be registered/installed
+ *
+ * TODO:
+ *  - use dirid
+ *  - use subdir
+ *  - use the timeout value
+ *  - use the optional argument value
+ */
+static BOOL registerdlls_callback( HINF hinf, PCWSTR field, void *arg )
+{
+    static const WCHAR FLG_REGSVR_DLLREGISTER_W[]  = {'F','L','G','_','R','E','G','S','V','R','_','D','L','L','R','E','G','I','S','T','E','R',0};
+    static const WCHAR FLG_REGSVR_DLLINSTALL_W[]  = {'F','L','G','_','R','E','G','S','V','R','_','D','L','L','I','N','S','T','A','L','L',0};
+    #define FLG_REGSVR_DLLREGISTER    1
+    #define FLG_REGSVR_INSTALL        2
+    INFCONTEXT context;
+    BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
+
+    /* each line is of the format: */
+    /* dirid, subdir, filename, registration flags[, [optional timeout][, argument]] */
+    for (; ok; ok = SetupFindNextLine( &context, &context ))
+    {
+        WCHAR dirid[MAX_INF_STRING_LENGTH];
+        WCHAR subdir[MAX_INF_STRING_LENGTH];
+        WCHAR filename[MAX_INF_STRING_LENGTH];
+        WCHAR regflags[MAX_INF_STRING_LENGTH];
+        BOOL foundRegFlags;
+        WCHAR timeout[MAX_INF_STRING_LENGTH]; /* default is 60 seconds */
+        BOOL foundTimeout;
+        INT timeoutValue;
+        WCHAR argument[MAX_INF_STRING_LENGTH];
+        BOOL foundArgument;
+        INT flags = 0;
+
+        foundRegFlags = foundTimeout = foundArgument = FALSE;
+        timeoutValue = 60; /* 60 seconds default */
+
+        /* get dirid */
+        if(!SetupGetStringFieldW( &context, 1, dirid, sizeof(dirid)/sizeof(WCHAR), NULL ))
+            return FALSE;
+
+        /* get subdir */
+        if (!SetupGetStringFieldW( &context, 2, subdir, sizeof(subdir)/sizeof(WCHAR), NULL ))
+            return FALSE;
+
+        /* get filename */
+        if (!SetupGetStringFieldW( &context, 3, filename, sizeof(filename)/sizeof(WCHAR), NULL ))
+            return FALSE;
+
+        /* get flags */
+        if (SetupGetStringFieldW( &context, 4, regflags, sizeof(regflags)/sizeof(WCHAR), NULL ))
+        {
+            if(!strcmpiW(regflags, FLG_REGSVR_DLLREGISTER_W))
+            {
+                flags = FLG_REGSVR_DLLREGISTER;
+            } else if(!strcmpiW(regflags, FLG_REGSVR_DLLINSTALL_W))
+            {
+                FIXME("FLG_REGSVR_DLLINSTALL unimplemented\n");
+                continue; /* skip over this file, we can't process it at the moment */
+            }
+        }
+
+        /* get timeout */
+        if (SetupGetStringFieldW( &context, 5, timeout, sizeof(timeout)/sizeof(WCHAR), NULL ))
+        {
+            foundTimeout = TRUE;
+            //TODO: atoi the string to timeoutValue
+        }
+
+        /* get argument */
+        if (SetupGetStringFieldW( &context, 6, argument, sizeof(argument)/sizeof(WCHAR), NULL ))
+            foundArgument = TRUE;
+
+        TRACE("dirid '%s' filename '%s' regflags '%s'\n", debugstr_w(dirid),
+              debugstr_w(filename), debugstr_w(regflags));
+
+        if(flags == FLG_REGSVR_DLLREGISTER)
+            RegisterDll(filename);
+    }
+    return TRUE;
+}
+
 
 /***********************************************************************
  *            iterate_section_fields
@@ -501,11 +694,17 @@
     DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
     INFCONTEXT context;
     BOOL ret = FALSE;
+    BOOL ok;
 
-    BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
+    TRACE("hinf %p, section %s, key %s, callback %p, arg %p\n", hinf, debugstr_w(section),
+	  debugstr_w(key), callback, arg);
+
+    ok = SetupFindFirstLineW( hinf, section, key, &context );
+    if(!ok) TRACE("SetupFindFirstLineW() failed to find the first line for section '%s'\n", debugstr_w(section));
     while (ok)
     {
         UINT i, count = SetupGetFieldCount( &context );
+        TRACE("SetupGetFieldCount() returned a count of %d\n", count);
         for (i = 1; i <= count; i++)
         {
             if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
@@ -617,12 +816,23 @@
                                          PSP_FILE_CALLBACK_W callback, PVOID context,
                                          HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
 {
+    TRACE("owner %p, hinf %p, section '%s', flags 0x%x, key_root %p, scr_root '%s', copy_flags 0x%x, callback %p, context %p, devinfo %p, devinfo_data %p\n",
+          owner, hinf, debugstr_w(section), flags, key_root, debugstr_w(src_root), copy_flags, callback, context, devinfo, devinfo_data);
+
+    if(flags & SPINST_ALL)
+    {
+        if(!iterate_section_fields( hinf, section, RunPreSetupCommands, runcmds_callback, NULL))
+            return FALSE;
+    }
+
     if (flags & SPINST_FILES)
     {
         struct files_callback_info info;
         HSPFILEQ queue;
         BOOL ret;
 
+        TRACE("flags & SPINST_FILES\n");
+
         if (!(queue = SetupOpenFileQueue())) return FALSE;
         info.queue      = queue;
         info.src_root   = src_root;
@@ -637,6 +847,7 @@
     }
     if (flags & SPINST_INIFILES)
     {
+        TRACE("flags & SPINST_INIFILES\n");
         if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
             !iterate_section_fields( hinf, section, UpdateIniFields,
                                      update_ini_fields_callback, NULL ))
@@ -644,12 +855,14 @@
     }
     if (flags & SPINST_INI2REG)
     {
+        TRACE("flags & SPINST_INI2REG\n");
         if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
             return FALSE;
     }
 
     if (flags & SPINST_LOGCONFIG)
     {
+        TRACE("flags & SPINST_LOGCONFIG\n");
         if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
             return FALSE;
     }
@@ -658,6 +871,8 @@
     {
         struct registry_callback_info info;
 
+        TRACE("flags & SPINST_REGISTRY\n");
+
         info.default_root = key_root;
         info.delete = TRUE;
         if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
@@ -666,7 +881,132 @@
         if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
             return FALSE;
     }
+
+    if(flags & SPINST_REGSVR)
+    {
+        TRACE("flags & SPINST_REGSVR\n");
+
+        if(!iterate_section_fields( hinf, section, RegisterDlls, registerdlls_callback, NULL))
+	    return FALSE;
+    }
+
+    if(flags & SPINST_ALL)
+    {
+        if(!iterate_section_fields( hinf, section, RunPostSetupCommands, runcmds_callback, NULL))
+            return FALSE;
+    }
+
     if (flags & (SPINST_BITREG|SPINST_REGSVR|SPINST_UNREGSVR|SPINST_PROFILEITEMS|SPINST_COPYINF))
         FIXME( "unsupported flags %x\n", flags );
     return TRUE;
 }
+
+UINT PSP_FILE_CALLBACK(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
+{
+    TRACE("Context: '%p', Notification: '%d', Param1: '%d', Param2: '%d'\n", Context,
+          Notification, Param1, Param2);
+    return 1; //FIXME: what to return??
+}
+
+/***********************************************************************
+ *		InstallHinfSectionW  (SETUPAPI.@)
+ *
+ * NOTE: 'cmdline' is <section> <mode> <path> from
+ *   RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
+ *
+ * TODO: what happens under windows with invalid parameters?
+ *       we ignore all mode parameters at the moment
+ */
+void WINAPI InstallHinfSectionW(HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show)
+{
+    WCHAR buffer[MAX_INF_STRING_LENGTH];
+    WCHAR section[MAX_INF_STRING_LENGTH];
+    WCHAR mode[MAX_INF_STRING_LENGTH];
+    WCHAR path[MAX_INF_STRING_LENGTH]; /* path to the inf file */
+    LPWSTR space;
+    LPWSTR pos;
+    UINT errorLine;
+    HINF hinf;
+    LPSTR msg;
+
+    TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
+
+    strncpyW(buffer, cmdline, sizeof(buffer)/sizeof(WCHAR));
+
+    pos = buffer;
+
+    space = strchrW(pos, ' ');
+    if(space)
+    {
+        *space = 0;
+        strncpyW(section, pos, sizeof(section)/sizeof(WCHAR));
+        pos = space+1;
+    }
+
+    space = strchrW(pos, ' ');
+    if(space)
+    {
+        *space = 0;
+        strncpyW(mode, pos, sizeof(mode)/sizeof(WCHAR));
+        pos = space+1;
+    }
+
+    strncpyW(path, pos, sizeof(path)/sizeof(WCHAR));
+
+    TRACE("section: '%s', mode: '%s', path: '%s'\n", debugstr_w(section),
+	  debugstr_w(mode), debugstr_w(path));
+
+
+    /* open the inf file */
+    hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, &errorLine);
+    if(hinf == INVALID_HANDLE_VALUE)
+    {
+        TRACE("SetupOpenInfFile() failed\n");
+    } else
+    {
+        UNICODE_STRING keyRootW;
+        if(RtlCreateUnicodeStringFromAsciiz(&keyRootW, "\\HKEY_CURRENT_USER"))
+        {
+            /* process the section */
+            if(!SetupInstallFromInfSectionW(hwnd, hinf, section, SPINST_ALL, (HKEY)keyRootW.Buffer, NULL,
+					SP_COPY_FORCE_NOOVERWRITE,
+					(PSP_FILE_CALLBACK_W)PSP_FILE_CALLBACK, 0x0, NULL, NULL))
+            {
+                FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+                               0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
+                ERR("%s\n", msg);
+            }
+
+            RtlFreeUnicodeString(&keyRootW);
+
+            SetupCloseInfFile(hinf);
+        } else
+        {
+            ERR("unable to RtlCreateUnicodeStringFromAsciiz for keyRootW\n");
+        }
+    }
+}
+
+/***********************************************************************
+ *		InstallHinfSectionA  (SETUPAPI.@)
+ */
+void WINAPI InstallHinfSectionA(HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show)
+{
+    UNICODE_STRING cmdlineW;
+
+    FIXME("stub, hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_a(cmdline));
+    if(RtlCreateUnicodeStringFromAsciiz(&cmdlineW, cmdline))
+    {
+      InstallHinfSectionW(hwnd, handle, cmdlineW.Buffer, show);
+      RtlFreeUnicodeString(&cmdlineW);
+    }
+}
+
+/***********************************************************************
+ *		InstallHinfSection  (SETUPAPI.@)
+ */
+void WINAPI InstallHinfSection(HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show)
+{
+    InstallHinfSectionA(hwnd, handle, cmdline, show);
+}
+
Index: parser.c
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/parser.c,v
retrieving revision 1.11
diff -u -r1.11 parser.c
--- parser.c	5 Jan 2004 21:12:22 -0000	1.11
+++ parser.c	20 Feb 2004 03:01:52 -0000
@@ -1033,8 +1033,13 @@
     WCHAR *path, *p;
     UINT len;
 
+    TRACE("name '%s', class '%s', style %ld, error %p\n", debugstr_w(name), debugstr_w(class),
+	  style, error);
+
     if (strchrW( name, '\\' ) || strchrW( name, '/' ))
     {
+        TRACE("trying full path\n");
+
         if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return (HINF)INVALID_HANDLE_VALUE;
         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
         {
@@ -1049,6 +1054,8 @@
         static const WCHAR Inf[]      = {'\\','i','n','f','\\',0};
         static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
 
+        TRACE("trying windows directory\n");
+
         len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12;
         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
         {
@@ -1072,7 +1079,11 @@
     {
         file = parse_file( handle, class, error );
         CloseHandle( handle );
+    } else
+    {
+        TRACE("CreateFileW() failed to open inf file\n");
     }
+
     if (!file)
     {
         HeapFree( GetProcessHeap(), 0, path );
Index: queue.c
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/queue.c,v
retrieving revision 1.9
diff -u -r1.9 queue.c
--- queue.c	27 Sep 2003 02:25:40 -0000	1.9
+++ queue.c	20 Feb 2004 03:01:55 -0000
@@ -427,6 +427,8 @@
 {
     struct file_queue *queue;
 
+    TRACE("\n");
+
     if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
         return (HSPFILEQ)INVALID_HANDLE_VALUE;
     return queue;
@@ -440,6 +442,8 @@
 {
     struct file_queue *queue = handle;
 
+    TRACE("handle %p\n", handle);
+
     free_file_op_queue( &queue->copy_queue );
     free_file_op_queue( &queue->rename_queue );
     free_file_op_queue( &queue->delete_queue );
@@ -887,6 +891,8 @@
 {
     struct callback_WtoA_context ctx;
 
+    TRACE("\n");
+
     ctx.orig_context = context;
     ctx.orig_handler = handler;
     return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
@@ -1082,6 +1088,8 @@
     BOOL result = FALSE;
     FILEPATHS_W paths;
     UINT op_result;
+
+    TRACE("\n");
 
     paths.Source = paths.Target = NULL;
 
Index: setupapi.spec
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/setupapi.spec,v
retrieving revision 1.24
diff -u -r1.24 setupapi.spec
--- setupapi.spec	17 Feb 2004 21:05:44 -0000	1.24
+++ setupapi.spec	20 Feb 2004 03:01:56 -0000
@@ -28,8 +28,8 @@
 @ stub GetVersionInfoFromImage
 @ stub InfIsFromOemLocation
 @ stdcall InstallHinfSection(long long str long)
-@ stub InstallHinfSectionA
-@ stub InstallHinfSectionW
+@ stdcall InstallHinfSectionA(long long str long)
+@ stdcall InstallHinfSectionW(long long wstr long)
 @ stub InstallStop
 @ stub IsUserAdmin
 @ stub LookUpStringInTable
Index: setupx16.h
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/setupx16.h,v
retrieving revision 1.13
diff -u -r1.13 setupx16.h
--- setupx16.h	21 Oct 2003 23:45:43 -0000	1.13
+++ setupx16.h	20 Feb 2004 03:01:57 -0000
@@ -487,6 +487,8 @@
 #define HOW_ALWAYS_PROMPT_REBOOT	2
 #define HOW_SILENT_REBOOT		3
 #define HOW_PROMPT_REBOOT		4
+#define HOW_SET_DEFAULT_PATH_TO_INF     128  /* set the default path to 
+						the location of the inf file */
 
 /****** device installation stuff ******/
 
Index: stubs.c
===================================================================
RCS file: /home/wine/wine/dlls/setupapi/stubs.c,v
retrieving revision 1.18
diff -u -r1.18 stubs.c
--- stubs.c	17 Feb 2004 22:48:25 -0000	1.18
+++ stubs.c	20 Feb 2004 03:01:57 -0000
@@ -189,15 +189,7 @@
 }
 
 /***********************************************************************
- *		InstallHinfSection  (SETUPAPI.@)
- */
-void WINAPI InstallHinfSection(HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show)
-{
-    FIXME("stub, hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_a(cmdline));
-}
-
-/***********************************************************************
- *		SetupGetInfInformationA    (SETUPAPI.@)
+ *             SetupGetInfInformationA    (SETUPAPI.@)
  */
 BOOL WINAPI SetupGetInfInformationA( LPCVOID InfSpec, DWORD SearchControl,
                                      PSP_INF_INFORMATION ReturnBuffer,
@@ -207,3 +199,4 @@
           InfSpec, SearchControl, ReturnBuffer, ReturnBufferSize, RequiredSize );
     return TRUE;
 }
+
