2 * Setupapi install routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "setupapi_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
25 /* info passed to callback functions dealing with files */
26 struct files_callback_info
34 /* info passed to callback functions dealing with the registry */
35 struct registry_callback_info
41 /* info passed to callback functions dealing with registering dlls */
42 struct register_dll_info
44 PSP_FILE_CALLBACK_W callback
;
45 PVOID callback_context
;
49 typedef BOOL (*iterate_fields_func
)( HINF hinf
, PCWSTR field
, void *arg
);
51 /* Unicode constants */
52 static const WCHAR CopyFiles
[] = {'C','o','p','y','F','i','l','e','s',0};
53 static const WCHAR DelFiles
[] = {'D','e','l','F','i','l','e','s',0};
54 static const WCHAR RenFiles
[] = {'R','e','n','F','i','l','e','s',0};
55 static const WCHAR Ini2Reg
[] = {'I','n','i','2','R','e','g',0};
56 static const WCHAR LogConf
[] = {'L','o','g','C','o','n','f',0};
57 static const WCHAR AddReg
[] = {'A','d','d','R','e','g',0};
58 static const WCHAR DelReg
[] = {'D','e','l','R','e','g',0};
59 static const WCHAR BitReg
[] = {'B','i','t','R','e','g',0};
60 static const WCHAR UpdateInis
[] = {'U','p','d','a','t','e','I','n','i','s',0};
61 static const WCHAR CopyINF
[] = {'C','o','p','y','I','N','F',0};
62 static const WCHAR UpdateIniFields
[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
63 static const WCHAR RegisterDlls
[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
64 static const WCHAR UnregisterDlls
[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
65 static const WCHAR ProfileItems
[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
68 /***********************************************************************
71 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
73 static WCHAR
*get_field_string( INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
74 WCHAR
*static_buffer
, DWORD
*size
)
78 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
79 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
81 /* now grow the buffer */
82 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
83 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
*sizeof(WCHAR
) ))) return NULL
;
85 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
87 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
92 /***********************************************************************
95 * Called once for each CopyFiles entry in a given section.
97 static BOOL
copy_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
99 struct files_callback_info
*info
= arg
;
101 if (field
[0] == '@') /* special case: copy single file */
102 SetupQueueDefaultCopyW( info
->queue
, info
->layout
, info
->src_root
, NULL
, field
, info
->copy_flags
);
104 SetupQueueCopySectionW( info
->queue
, info
->src_root
, info
->layout
, hinf
, field
, info
->copy_flags
);
109 /***********************************************************************
110 * delete_files_callback
112 * Called once for each DelFiles entry in a given section.
114 static BOOL
delete_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
116 struct files_callback_info
*info
= arg
;
117 SetupQueueDeleteSectionW( info
->queue
, hinf
, 0, field
);
122 /***********************************************************************
123 * rename_files_callback
125 * Called once for each RenFiles entry in a given section.
127 static BOOL
rename_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
129 struct files_callback_info
*info
= arg
;
130 SetupQueueRenameSectionW( info
->queue
, hinf
, 0, field
);
135 /***********************************************************************
138 * Retrieve the registry root key from its name.
140 static HKEY
get_root_key( const WCHAR
*name
, HKEY def_root
)
142 static const WCHAR HKCR
[] = {'H','K','C','R',0};
143 static const WCHAR HKCU
[] = {'H','K','C','U',0};
144 static const WCHAR HKLM
[] = {'H','K','L','M',0};
145 static const WCHAR HKU
[] = {'H','K','U',0};
146 static const WCHAR HKR
[] = {'H','K','R',0};
148 if (!strcmpiW( name
, HKCR
)) return HKEY_CLASSES_ROOT
;
149 if (!strcmpiW( name
, HKCU
)) return HKEY_CURRENT_USER
;
150 if (!strcmpiW( name
, HKLM
)) return HKEY_LOCAL_MACHINE
;
151 if (!strcmpiW( name
, HKU
)) return HKEY_USERS
;
152 if (!strcmpiW( name
, HKR
)) return def_root
;
157 /***********************************************************************
158 * append_multi_sz_value
160 * Append a multisz string to a multisz registry value.
162 static void append_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*strings
,
165 DWORD size
, type
, total
;
168 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
169 if (type
!= REG_MULTI_SZ
) return;
171 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
172 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
174 /* compare each string against all the existing ones */
178 int len
= strlenW(strings
) + 1;
180 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
181 if (!strcmpiW( p
, strings
)) break;
183 if (!*p
) /* not found, need to append it */
185 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
193 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
194 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
197 HeapFree( GetProcessHeap(), 0, buffer
);
201 /***********************************************************************
202 * delete_multi_sz_value
204 * Remove a string from a multisz registry value.
206 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
209 WCHAR
*buffer
, *src
, *dst
;
211 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
212 if (type
!= REG_MULTI_SZ
) return;
213 /* allocate double the size, one for value before and one for after */
214 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
215 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
220 int len
= strlenW(src
) + 1;
221 if (strcmpiW( src
, string
))
223 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
229 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
231 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
232 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
233 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
236 HeapFree( GetProcessHeap(), 0, buffer
);
240 /***********************************************************************
243 * Perform an add/delete registry operation depending on the flags.
245 static BOOL
do_reg_operation( HKEY hkey
, const WCHAR
*value
, INFCONTEXT
*context
, INT flags
)
249 if (flags
& (FLG_ADDREG_DELREG_BIT
| FLG_ADDREG_DELVAL
)) /* deletion */
251 if (*value
&& !(flags
& FLG_DELREG_KEYONLY_COMMON
))
253 if ((flags
& FLG_DELREG_MULTI_SZ_DELSTRING
) == FLG_DELREG_MULTI_SZ_DELSTRING
)
257 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
) || !size
) return TRUE
;
258 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
259 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
260 delete_multi_sz_value( hkey
, value
, str
);
261 HeapFree( GetProcessHeap(), 0, str
);
263 else RegDeleteValueW( hkey
, value
);
265 else RegDeleteKeyW( hkey
, NULL
);
269 if (flags
& (FLG_ADDREG_KEYONLY
|FLG_ADDREG_KEYONLY_COMMON
)) return TRUE
;
271 if (flags
& (FLG_ADDREG_NOCLOBBER
|FLG_ADDREG_OVERWRITEONLY
))
273 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
274 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
)) return TRUE
;
275 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
)) return TRUE
;
278 switch(flags
& FLG_ADDREG_TYPE_MASK
)
280 case FLG_ADDREG_TYPE_SZ
: type
= REG_SZ
; break;
281 case FLG_ADDREG_TYPE_MULTI_SZ
: type
= REG_MULTI_SZ
; break;
282 case FLG_ADDREG_TYPE_EXPAND_SZ
: type
= REG_EXPAND_SZ
; break;
283 case FLG_ADDREG_TYPE_BINARY
: type
= REG_BINARY
; break;
284 case FLG_ADDREG_TYPE_DWORD
: type
= REG_DWORD
; break;
285 case FLG_ADDREG_TYPE_NONE
: type
= REG_NONE
; break;
286 default: type
= flags
>> 16; break;
289 if (!(flags
& FLG_ADDREG_BINVALUETYPE
) ||
290 (type
== REG_DWORD
&& SetupGetFieldCount(context
) == 5))
292 static const WCHAR empty
;
295 if (type
== REG_MULTI_SZ
)
297 if (!SetupGetMultiSzFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
300 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
301 SetupGetMultiSzFieldW( context
, 5, str
, size
, NULL
);
303 if (flags
& FLG_ADDREG_APPEND
)
305 if (!str
) return TRUE
;
306 append_multi_sz_value( hkey
, value
, str
, size
);
307 HeapFree( GetProcessHeap(), 0, str
);
310 /* else fall through to normal string handling */
314 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
317 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
318 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
322 if (type
== REG_DWORD
)
324 DWORD dw
= str
? strtoulW( str
, NULL
, 0 ) : 0;
325 TRACE( "setting dword %s to %lx\n", debugstr_w(value
), dw
);
326 RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)&dw
, sizeof(dw
) );
330 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(str
) );
331 if (str
) RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)str
, size
* sizeof(WCHAR
) );
332 else RegSetValueExW( hkey
, value
, 0, type
, (const BYTE
*)&empty
, sizeof(WCHAR
) );
334 HeapFree( GetProcessHeap(), 0, str
);
337 else /* get the binary data */
341 if (!SetupGetBinaryField( context
, 5, NULL
, 0, &size
)) size
= 0;
344 if (!(data
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
345 TRACE( "setting binary data %s len %ld\n", debugstr_w(value
), size
);
346 SetupGetBinaryField( context
, 5, data
, size
, NULL
);
348 RegSetValueExW( hkey
, value
, 0, type
, data
, size
);
349 HeapFree( GetProcessHeap(), 0, data
);
355 /***********************************************************************
358 * Called once for each AddReg and DelReg entry in a given section.
360 static BOOL
registry_callback( HINF hinf
, PCWSTR field
, void *arg
)
362 struct registry_callback_info
*info
= arg
;
366 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
368 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
370 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
374 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
376 if (!(root_key
= get_root_key( buffer
, info
->default_root
)))
380 if (!SetupGetStringFieldW( &context
, 2, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
384 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
388 if (flags
& FLG_ADDREG_DELREG_BIT
) continue; /* ignore this entry */
392 if (!flags
) flags
= FLG_ADDREG_DELREG_BIT
;
393 else if (!(flags
& FLG_ADDREG_DELREG_BIT
)) continue; /* ignore this entry */
396 if (info
->delete || (flags
& FLG_ADDREG_OVERWRITEONLY
))
398 if (RegOpenKeyW( root_key
, buffer
, &hkey
)) continue; /* ignore if it doesn't exist */
400 else if (RegCreateKeyW( root_key
, buffer
, &hkey
))
402 ERR( "could not create key %p %s\n", root_key
, debugstr_w(buffer
) );
405 TRACE( "key %p %s\n", root_key
, debugstr_w(buffer
) );
408 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
412 if (!do_reg_operation( hkey
, buffer
, &context
, flags
))
423 /***********************************************************************
426 * Register or unregister a dll.
428 static BOOL
do_register_dll( const struct register_dll_info
*info
, const WCHAR
*path
,
429 INT flags
, INT timeout
, const WCHAR
*args
)
433 SP_REGISTER_CONTROL_STATUSW status
;
435 status
.cbSize
= sizeof(status
);
436 status
.FileName
= path
;
437 status
.FailureCode
= SPREG_SUCCESS
;
438 status
.Win32Error
= ERROR_SUCCESS
;
442 switch(info
->callback( info
->callback_context
, SPFILENOTIFY_STARTREGISTRATION
,
443 (UINT_PTR
)&status
, !info
->unregister
))
446 SetLastError( ERROR_OPERATION_ABORTED
);
455 if (!(module
= LoadLibraryExW( path
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)))
457 WARN( "could not load %s\n", debugstr_w(path
) );
458 status
.FailureCode
= SPREG_LOADLIBRARY
;
459 status
.Win32Error
= GetLastError();
463 if (flags
& FLG_REGSVR_DLLREGISTER
)
465 const char *entry_point
= info
->unregister
? "DllUnregisterServer" : "DllRegisterServer";
466 HRESULT (WINAPI
*func
)(void) = (void *)GetProcAddress( module
, entry_point
);
470 status
.FailureCode
= SPREG_GETPROCADDR
;
471 status
.Win32Error
= GetLastError();
475 TRACE( "calling %s in %s\n", entry_point
, debugstr_w(path
) );
480 WARN( "calling %s in %s returned error %lx\n", entry_point
, debugstr_w(path
), res
);
481 status
.FailureCode
= SPREG_REGSVR
;
482 status
.Win32Error
= res
;
487 if (flags
& FLG_REGSVR_DLLINSTALL
)
489 HRESULT (WINAPI
*func
)(BOOL
,LPCWSTR
) = (void *)GetProcAddress( module
, "DllInstall" );
493 status
.FailureCode
= SPREG_GETPROCADDR
;
494 status
.Win32Error
= GetLastError();
498 TRACE( "calling DllInstall(%d,%s) in %s\n",
499 !info
->unregister
, debugstr_w(args
), debugstr_w(path
) );
500 res
= func( !info
->unregister
, args
);
504 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path
), res
);
505 status
.FailureCode
= SPREG_REGSVR
;
506 status
.Win32Error
= res
;
512 if (module
) FreeLibrary( module
);
513 if (info
->callback
) info
->callback( info
->callback_context
, SPFILENOTIFY_ENDREGISTRATION
,
514 (UINT_PTR
)&status
, !info
->unregister
);
519 /***********************************************************************
520 * register_dlls_callback
522 * Called once for each RegisterDlls entry in a given section.
524 static BOOL
register_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
526 struct register_dll_info
*info
= arg
;
529 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
531 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
533 WCHAR
*path
, *args
, *p
;
534 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
538 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
541 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
543 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
544 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
547 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
548 strcpyW( p
, buffer
);
551 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
554 if (!SetupGetIntField( &context
, 5, &timeout
)) timeout
= 60;
556 /* get command line */
558 if (SetupGetStringFieldW( &context
, 6, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
561 ret
= do_register_dll( info
, path
, flags
, timeout
, args
);
564 HeapFree( GetProcessHeap(), 0, path
);
570 /***********************************************************************
571 * update_ini_callback
573 * Called once for each UpdateInis entry in a given section.
575 static BOOL
update_ini_callback( HINF hinf
, PCWSTR field
, void *arg
)
579 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
581 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
583 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
584 WCHAR filename
[MAX_INF_STRING_LENGTH
];
585 WCHAR section
[MAX_INF_STRING_LENGTH
];
586 WCHAR entry
[MAX_INF_STRING_LENGTH
];
587 WCHAR string
[MAX_INF_STRING_LENGTH
];
590 if (!SetupGetStringFieldW( &context
, 1, filename
,
591 sizeof(filename
)/sizeof(WCHAR
), NULL
))
594 if (!SetupGetStringFieldW( &context
, 2, section
,
595 sizeof(section
)/sizeof(WCHAR
), NULL
))
598 if (!SetupGetStringFieldW( &context
, 4, buffer
,
599 sizeof(buffer
)/sizeof(WCHAR
), NULL
))
602 divider
= strchrW(buffer
,'=');
606 strcpyW(entry
,buffer
);
608 strcpyW(string
,divider
);
612 strcpyW(entry
,buffer
);
616 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry
),
617 debugstr_w(string
),debugstr_w(section
),debugstr_w(filename
));
618 WritePrivateProfileStringW(section
,entry
,string
,filename
);
624 static BOOL
update_ini_fields_callback( HINF hinf
, PCWSTR field
, void *arg
)
626 FIXME( "should update ini fields %s\n", debugstr_w(field
) );
630 static BOOL
ini2reg_callback( HINF hinf
, PCWSTR field
, void *arg
)
632 FIXME( "should do ini2reg %s\n", debugstr_w(field
) );
636 static BOOL
logconf_callback( HINF hinf
, PCWSTR field
, void *arg
)
638 FIXME( "should do logconf %s\n", debugstr_w(field
) );
642 static BOOL
bitreg_callback( HINF hinf
, PCWSTR field
, void *arg
)
644 FIXME( "should do bitreg %s\n", debugstr_w(field
) );
648 static BOOL
profile_items_callback( HINF hinf
, PCWSTR field
, void *arg
)
650 FIXME( "should do profile items %s\n", debugstr_w(field
) );
654 static BOOL
copy_inf_callback( HINF hinf
, PCWSTR field
, void *arg
)
656 FIXME( "should do copy inf %s\n", debugstr_w(field
) );
661 /***********************************************************************
662 * iterate_section_fields
664 * Iterate over all fields of a certain key of a certain section
666 static BOOL
iterate_section_fields( HINF hinf
, PCWSTR section
, PCWSTR key
,
667 iterate_fields_func callback
, void *arg
)
669 WCHAR static_buffer
[200];
670 WCHAR
*buffer
= static_buffer
;
671 DWORD size
= sizeof(static_buffer
)/sizeof(WCHAR
);
675 BOOL ok
= SetupFindFirstLineW( hinf
, section
, key
, &context
);
678 UINT i
, count
= SetupGetFieldCount( &context
);
679 for (i
= 1; i
<= count
; i
++)
681 if (!(buffer
= get_field_string( &context
, i
, buffer
, static_buffer
, &size
)))
683 if (!callback( hinf
, buffer
, arg
))
685 WARN("callback failed for %s %s err %ld\n",
686 debugstr_w(section
), debugstr_w(buffer
), GetLastError() );
690 ok
= SetupFindNextMatchLineW( &context
, key
, &context
);
694 if (buffer
&& buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
699 /***********************************************************************
700 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
702 BOOL WINAPI
SetupInstallFilesFromInfSectionA( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
703 PCSTR section
, PCSTR src_root
, UINT flags
)
705 UNICODE_STRING sectionW
;
708 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
710 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
714 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
719 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
721 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
722 srcW
.Buffer
, flags
);
723 RtlFreeUnicodeString( &srcW
);
725 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
727 RtlFreeUnicodeString( §ionW
);
732 /***********************************************************************
733 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
735 BOOL WINAPI
SetupInstallFilesFromInfSectionW( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
736 PCWSTR section
, PCWSTR src_root
, UINT flags
)
738 struct files_callback_info info
;
741 info
.src_root
= src_root
;
742 info
.copy_flags
= flags
;
743 info
.layout
= hlayout
;
744 return iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
);
748 /***********************************************************************
749 * SetupInstallFromInfSectionA (SETUPAPI.@)
751 BOOL WINAPI
SetupInstallFromInfSectionA( HWND owner
, HINF hinf
, PCSTR section
, UINT flags
,
752 HKEY key_root
, PCSTR src_root
, UINT copy_flags
,
753 PSP_FILE_CALLBACK_A callback
, PVOID context
,
754 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
756 UNICODE_STRING sectionW
, src_rootW
;
757 struct callback_WtoA_context ctx
;
760 src_rootW
.Buffer
= NULL
;
761 if (src_root
&& !RtlCreateUnicodeStringFromAsciiz( &src_rootW
, src_root
))
763 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
767 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
769 ctx
.orig_context
= context
;
770 ctx
.orig_handler
= callback
;
771 ret
= SetupInstallFromInfSectionW( owner
, hinf
, sectionW
.Buffer
, flags
, key_root
,
772 src_rootW
.Buffer
, copy_flags
, QUEUE_callback_WtoA
,
773 &ctx
, devinfo
, devinfo_data
);
774 RtlFreeUnicodeString( §ionW
);
776 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
778 RtlFreeUnicodeString( &src_rootW
);
783 /***********************************************************************
784 * SetupInstallFromInfSectionW (SETUPAPI.@)
786 BOOL WINAPI
SetupInstallFromInfSectionW( HWND owner
, HINF hinf
, PCWSTR section
, UINT flags
,
787 HKEY key_root
, PCWSTR src_root
, UINT copy_flags
,
788 PSP_FILE_CALLBACK_W callback
, PVOID context
,
789 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
791 if (flags
& SPINST_FILES
)
793 struct files_callback_info info
;
797 if (!(queue
= SetupOpenFileQueue())) return FALSE
;
799 info
.src_root
= src_root
;
800 info
.copy_flags
= copy_flags
;
802 ret
= (iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
) &&
803 iterate_section_fields( hinf
, section
, DelFiles
, delete_files_callback
, &info
) &&
804 iterate_section_fields( hinf
, section
, RenFiles
, rename_files_callback
, &info
) &&
805 SetupCommitFileQueueW( owner
, queue
, callback
, context
));
806 SetupCloseFileQueue( queue
);
807 if (!ret
) return FALSE
;
809 if (flags
& SPINST_INIFILES
)
811 if (!iterate_section_fields( hinf
, section
, UpdateInis
, update_ini_callback
, NULL
) ||
812 !iterate_section_fields( hinf
, section
, UpdateIniFields
,
813 update_ini_fields_callback
, NULL
))
816 if (flags
& SPINST_INI2REG
)
818 if (!iterate_section_fields( hinf
, section
, Ini2Reg
, ini2reg_callback
, NULL
))
821 if (flags
& SPINST_LOGCONFIG
)
823 if (!iterate_section_fields( hinf
, section
, LogConf
, logconf_callback
, NULL
))
826 if (flags
& SPINST_REGSVR
)
828 struct register_dll_info info
;
830 info
.unregister
= FALSE
;
831 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
833 info
.callback
= callback
;
834 info
.callback_context
= context
;
836 else info
.callback
= NULL
;
838 if (!iterate_section_fields( hinf
, section
, RegisterDlls
, register_dlls_callback
, &info
))
841 if (flags
& SPINST_UNREGSVR
)
843 struct register_dll_info info
;
845 info
.unregister
= TRUE
;
846 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
848 info
.callback
= callback
;
849 info
.callback_context
= context
;
851 else info
.callback
= NULL
;
853 if (!iterate_section_fields( hinf
, section
, UnregisterDlls
, register_dlls_callback
, &info
))
856 if (flags
& SPINST_REGISTRY
)
858 struct registry_callback_info info
;
860 info
.default_root
= key_root
;
862 if (!iterate_section_fields( hinf
, section
, DelReg
, registry_callback
, &info
))
865 if (!iterate_section_fields( hinf
, section
, AddReg
, registry_callback
, &info
))
868 if (flags
& SPINST_BITREG
)
870 if (!iterate_section_fields( hinf
, section
, BitReg
, bitreg_callback
, NULL
))
873 if (flags
& SPINST_PROFILEITEMS
)
875 if (!iterate_section_fields( hinf
, section
, ProfileItems
, profile_items_callback
, NULL
))
878 if (flags
& SPINST_COPYINF
)
880 if (!iterate_section_fields( hinf
, section
, CopyINF
, copy_inf_callback
, NULL
))
888 /***********************************************************************
889 * InstallHinfSectionW (SETUPAPI.@)
891 * NOTE: 'cmdline' is <section> <mode> <path> from
892 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
894 void WINAPI
InstallHinfSectionW( HWND hwnd
, HINSTANCE handle
, LPCWSTR cmdline
, INT show
)
896 WCHAR
*p
, *path
, section
[MAX_PATH
];
897 void *callback_context
;
901 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd
, handle
, debugstr_w(cmdline
));
903 lstrcpynW( section
, cmdline
, sizeof(section
)/sizeof(WCHAR
) );
905 if (!(p
= strchrW( section
, ' ' ))) return;
907 while (*p
== ' ') p
++;
910 if (!(p
= strchrW( p
, ' ' ))) return;
912 while (*path
== ' ') path
++;
914 hinf
= SetupOpenInfFileW( path
, NULL
, INF_STYLE_WIN4
, NULL
);
915 if (hinf
== INVALID_HANDLE_VALUE
) return;
917 callback_context
= SetupInitDefaultQueueCallback( hwnd
);
918 SetupInstallFromInfSectionW( hwnd
, hinf
, section
, SPINST_ALL
, NULL
, NULL
, SP_COPY_NEWER
,
919 SetupDefaultQueueCallbackW
, callback_context
,
921 SetupTermDefaultQueueCallback( callback_context
);
922 SetupCloseInfFile( hinf
);
924 /* FIXME: should check the mode and maybe reboot */
925 /* there isn't much point in doing that since we */
926 /* don't yet handle deferred file copies anyway. */
930 /***********************************************************************
931 * InstallHinfSectionA (SETUPAPI.@)
933 void WINAPI
InstallHinfSectionA( HWND hwnd
, HINSTANCE handle
, LPCSTR cmdline
, INT show
)
935 UNICODE_STRING cmdlineW
;
937 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW
, cmdline
))
939 InstallHinfSectionW( hwnd
, handle
, cmdlineW
.Buffer
, show
);
940 RtlFreeUnicodeString( &cmdlineW
);
945 /***********************************************************************
946 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
948 BOOL WINAPI
SetupInstallServicesFromInfSectionA( HINF hinf
, PCSTR sectionname
, DWORD flags
)
950 return SetupInstallServicesFromInfSectionExA( hinf
, sectionname
, flags
,
951 NULL
, NULL
, NULL
, NULL
);
955 /***********************************************************************
956 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
958 BOOL WINAPI
SetupInstallServicesFromInfSectionW( HINF hinf
, PCWSTR sectionname
, DWORD flags
)
960 return SetupInstallServicesFromInfSectionExW( hinf
, sectionname
, flags
,
961 NULL
, NULL
, NULL
, NULL
);
965 /***********************************************************************
966 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
968 BOOL WINAPI
SetupInstallServicesFromInfSectionExA( HINF hinf
, PCSTR sectionname
, DWORD flags
, HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
, PVOID reserved1
, PVOID reserved2
)
970 UNICODE_STRING sectionnameW
;
973 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW
, sectionname
))
975 ret
= SetupInstallServicesFromInfSectionExW( hinf
, sectionnameW
.Buffer
, flags
, devinfo
, devinfo_data
, reserved1
, reserved2
);
976 RtlFreeUnicodeString( §ionnameW
);
979 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
985 static BOOL
GetLineText( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, PWSTR
*value
)
992 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, NULL
, 0, &required
)
993 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
996 buf
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) );
999 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1003 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, buf
, required
, &required
) )
1005 HeapFree( GetProcessHeap(), 0, buf
);
1014 static BOOL
GetIntField( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, INT
*value
)
1019 if (! GetLineText( hinf
, section_name
, key_name
, &buffer
) )
1022 res
= wcstol( buffer
, &end
, 0 );
1023 if (end
!= buffer
&& !*end
)
1025 HeapFree(GetProcessHeap(), 0, buffer
);
1031 HeapFree(GetProcessHeap(), 0, buffer
);
1032 SetLastError( ERROR_INVALID_DATA
);
1038 /***********************************************************************
1039 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1041 BOOL WINAPI
SetupInstallServicesFromInfSectionExW( HINF hinf
, PCWSTR sectionname
, DWORD flags
, HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
, PVOID reserved1
, PVOID reserved2
)
1043 SC_HANDLE hSCManager
, hService
;
1044 LPWSTR ServiceBinary
, LoadOrderGroup
;
1045 LPWSTR DisplayName
, Description
, Dependencies
;
1046 INT ServiceType
, StartType
, ErrorControl
;
1048 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf
, debugstr_w(sectionname
),
1049 flags
, devinfo
, devinfo_data
, reserved1
, reserved2
);
1053 /* FIXME: I don't know how to get the service name. ATM, just fail the call */
1054 DPRINT1("Service name not specified!\n");
1057 /* FIXME: use the flags parameters */
1058 /* FIXME: use DeviceInfoSet, DeviceInfoData parameters */
1060 if (!GetIntField(hinf
, sectionname
, L
"ServiceType", &ServiceType
))
1062 if (!GetIntField(hinf
, sectionname
, L
"StartType", &StartType
))
1064 if (!GetIntField(hinf
, sectionname
, L
"ErrorControl", &ErrorControl
))
1067 hSCManager
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASE
, SC_MANAGER_CREATE_SERVICE
);
1068 if (hSCManager
== NULL
)
1071 if (!GetLineText(hinf
, sectionname
, L
"ServiceBinary", &ServiceBinary
))
1073 CloseServiceHandle(hSCManager
);
1076 if (!GetLineText(hinf
, sectionname
, L
"LoadOrderGroup", &LoadOrderGroup
))
1077 /* LoadOrderGroup value is optional. Ignore the error */
1078 LoadOrderGroup
= NULL
;
1080 /* Don't check return value, as these fields are optional and
1081 * GetLineText initialize output parameter even on failure */
1082 GetLineText(hinf
, sectionname
, L
"DisplayName", &DisplayName
);
1083 GetLineText(hinf
, sectionname
, L
"Description", &Description
);
1084 GetLineText(hinf
, sectionname
, L
"Dependencies", &Dependencies
);
1086 hService
= CreateServiceW(
1094 /* BIG HACK!!! As GetLineText() give us a full path, ignore the
1095 * first letters which should be the OS directory. If that's not
1096 * the case, the file name written to registry will be bad and
1097 * the driver will not load...
1099 ServiceBinary
+ GetWindowsDirectoryW(NULL
, 0),
1104 HeapFree(GetProcessHeap(), 0, ServiceBinary
);
1105 HeapFree(GetProcessHeap(), 0, LoadOrderGroup
);
1106 HeapFree(GetProcessHeap(), 0, DisplayName
);
1107 HeapFree(GetProcessHeap(), 0, Description
);
1108 HeapFree(GetProcessHeap(), 0, Dependencies
);
1109 if (hService
== NULL
)
1111 CloseServiceHandle(hSCManager
);
1114 //CloseServiceHandle(hService);
1116 return CloseServiceHandle(hSCManager
);