2 * Setupapi miscellaneous functions
4 * Copyright 2005 Eric Kohl
5 * Copyright 2007 Hans Leidekker
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "setupapi_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* Unicode constants */
27 static const WCHAR BackSlash
[] = {'\\',0};
28 static const WCHAR TranslationRegKey
[] = {'\\','V','e','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0};
32 IN PWSTR InstallerName
,
33 OUT HMODULE
* ModulePointer
,
34 OUT PVOID
* FunctionPointer
)
36 HMODULE hModule
= NULL
;
37 LPSTR FunctionNameA
= NULL
;
41 *ModulePointer
= NULL
;
42 *FunctionPointer
= NULL
;
44 Comma
= strchrW(InstallerName
, ',');
47 rc
= ERROR_INVALID_PARAMETER
;
53 hModule
= LoadLibraryW(InstallerName
);
61 /* Skip comma spaces */
62 while (*Comma
== ',' || isspaceW(*Comma
))
65 /* W->A conversion for function name */
66 FunctionNameA
= pSetupUnicodeToMultiByte(Comma
, CP_ACP
);
74 *FunctionPointer
= GetProcAddress(hModule
, FunctionNameA
);
75 if (!*FunctionPointer
)
81 *ModulePointer
= hModule
;
85 if (rc
!= ERROR_SUCCESS
&& hModule
)
87 MyFree(FunctionNameA
);
93 IN HMODULE ModulePointer
,
94 IN PVOID FunctionPointer
)
96 if (ModulePointer
== NULL
)
98 if (FreeLibrary(ModulePointer
))
101 return GetLastError();
104 /**************************************************************************
105 * MyFree [SETUPAPI.@]
107 * Frees an allocated memory block from the process heap.
110 * lpMem [I] pointer to memory block which will be freed
115 VOID WINAPI
MyFree(LPVOID lpMem
)
117 TRACE("%p\n", lpMem
);
118 HeapFree(GetProcessHeap(), 0, lpMem
);
122 /**************************************************************************
123 * MyMalloc [SETUPAPI.@]
125 * Allocates memory block from the process heap.
128 * dwSize [I] size of the allocated memory block
131 * Success: pointer to allocated memory block
134 LPVOID WINAPI
MyMalloc(DWORD dwSize
)
136 TRACE("%lu\n", dwSize
);
137 return HeapAlloc(GetProcessHeap(), 0, dwSize
);
141 /**************************************************************************
142 * MyRealloc [SETUPAPI.@]
144 * Changes the size of an allocated memory block or allocates a memory
145 * block from the process heap.
148 * lpSrc [I] pointer to memory block which will be resized
149 * dwSize [I] new size of the memory block
152 * Success: pointer to the resized memory block
156 * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
157 * block like MyMalloc.
159 LPVOID WINAPI
MyRealloc(LPVOID lpSrc
, DWORD dwSize
)
161 TRACE("%p %lu\n", lpSrc
, dwSize
);
164 return HeapAlloc(GetProcessHeap(), 0, dwSize
);
166 return HeapReAlloc(GetProcessHeap(), 0, lpSrc
, dwSize
);
170 /**************************************************************************
171 * pSetupDuplicateString [SETUPAPI.@]
173 * Duplicates a unicode string.
176 * lpSrc [I] pointer to the unicode string that will be duplicated
179 * Success: pointer to the duplicated unicode string
183 * Call MyFree() to release the duplicated string.
185 LPWSTR WINAPI
pSetupDuplicateString(LPCWSTR lpSrc
)
189 TRACE("%s\n", debugstr_w(lpSrc
));
191 lpDst
= MyMalloc((lstrlenW(lpSrc
) + 1) * sizeof(WCHAR
));
195 strcpyW(lpDst
, lpSrc
);
201 /**************************************************************************
202 * QueryRegistryValue [SETUPAPI.@]
204 * Retrieves value data from the registry and allocates memory for the
208 * hKey [I] Handle of the key to query
209 * lpValueName [I] Name of value under hkey to query
210 * lpData [O] Destination for the values contents,
211 * lpType [O] Destination for the value type
212 * lpcbData [O] Destination for the size of data
215 * Success: ERROR_SUCCESS
219 * Use MyFree to release the lpData buffer.
221 LONG WINAPI
QueryRegistryValue(HKEY hKey
,
229 TRACE("%p %s %p %p %p\n",
230 hKey
, debugstr_w(lpValueName
), lpData
, lpType
, lpcbData
);
232 /* Get required buffer size */
234 lError
= RegQueryValueExW(hKey
, lpValueName
, 0, lpType
, NULL
, lpcbData
);
235 if (lError
!= ERROR_SUCCESS
)
238 /* Allocate buffer */
239 *lpData
= MyMalloc(*lpcbData
);
241 return ERROR_NOT_ENOUGH_MEMORY
;
243 /* Query registry value */
244 lError
= RegQueryValueExW(hKey
, lpValueName
, 0, lpType
, *lpData
, lpcbData
);
245 if (lError
!= ERROR_SUCCESS
)
252 /**************************************************************************
253 * pSetupMultiByteToUnicode [SETUPAPI.@]
255 * Converts a multi-byte string to a Unicode string.
258 * lpMultiByteStr [I] Multi-byte string to be converted
259 * uCodePage [I] Code page
262 * Success: pointer to the converted Unicode string
266 * Use MyFree to release the returned Unicode string.
268 LPWSTR WINAPI
pSetupMultiByteToUnicode(LPCSTR lpMultiByteStr
, UINT uCodePage
)
273 TRACE("%s %d\n", debugstr_a(lpMultiByteStr
), uCodePage
);
275 nLength
= MultiByteToWideChar(uCodePage
, 0, lpMultiByteStr
,
280 lpUnicodeStr
= MyMalloc(nLength
* sizeof(WCHAR
));
281 if (lpUnicodeStr
== NULL
)
283 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
287 if (!MultiByteToWideChar(uCodePage
, 0, lpMultiByteStr
,
288 nLength
, lpUnicodeStr
, nLength
))
290 MyFree(lpUnicodeStr
);
298 /**************************************************************************
299 * pSetupUnicodeToMultiByte [SETUPAPI.@]
301 * Converts a Unicode string to a multi-byte string.
304 * lpUnicodeStr [I] Unicode string to be converted
305 * uCodePage [I] Code page
308 * Success: pointer to the converted multi-byte string
312 * Use MyFree to release the returned multi-byte string.
314 LPSTR WINAPI
pSetupUnicodeToMultiByte(LPCWSTR lpUnicodeStr
, UINT uCodePage
)
316 LPSTR lpMultiByteStr
;
319 TRACE("%s %d\n", debugstr_w(lpUnicodeStr
), uCodePage
);
321 nLength
= WideCharToMultiByte(uCodePage
, 0, lpUnicodeStr
, -1,
322 NULL
, 0, NULL
, NULL
);
326 lpMultiByteStr
= MyMalloc(nLength
);
327 if (lpMultiByteStr
== NULL
)
330 if (!WideCharToMultiByte(uCodePage
, 0, lpUnicodeStr
, -1,
331 lpMultiByteStr
, nLength
, NULL
, NULL
))
333 MyFree(lpMultiByteStr
);
337 return lpMultiByteStr
;
341 /**************************************************************************
342 * DoesUserHavePrivilege [SETUPAPI.@]
344 * Check whether the current user has got a given privilege.
347 * lpPrivilegeName [I] Name of the privilege to be checked
353 BOOL WINAPI
DoesUserHavePrivilege(LPCWSTR lpPrivilegeName
)
357 PTOKEN_PRIVILEGES lpPrivileges
;
360 BOOL bResult
= FALSE
;
362 TRACE("%s\n", debugstr_w(lpPrivilegeName
));
364 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
367 if (!GetTokenInformation(hToken
, TokenPrivileges
, NULL
, 0, &dwSize
))
369 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
376 lpPrivileges
= MyMalloc(dwSize
);
377 if (lpPrivileges
== NULL
)
383 if (!GetTokenInformation(hToken
, TokenPrivileges
, lpPrivileges
, dwSize
, &dwSize
))
385 MyFree(lpPrivileges
);
392 if (!LookupPrivilegeValueW(NULL
, lpPrivilegeName
, &PrivilegeLuid
))
394 MyFree(lpPrivileges
);
398 for (i
= 0; i
< lpPrivileges
->PrivilegeCount
; i
++)
400 if (lpPrivileges
->Privileges
[i
].Luid
.HighPart
== PrivilegeLuid
.HighPart
&&
401 lpPrivileges
->Privileges
[i
].Luid
.LowPart
== PrivilegeLuid
.LowPart
)
407 MyFree(lpPrivileges
);
413 /**************************************************************************
414 * pSetupEnablePrivilege [SETUPAPI.@]
416 * Enables or disables one of the current users privileges.
419 * lpPrivilegeName [I] Name of the privilege to be changed
420 * bEnable [I] TRUE: Enables the privilege
421 * FALSE: Disables the privilege
427 BOOL WINAPI
pSetupEnablePrivilege(LPCWSTR lpPrivilegeName
, BOOL bEnable
)
429 TOKEN_PRIVILEGES Privileges
;
433 TRACE("%s %s\n", debugstr_w(lpPrivilegeName
), bEnable
? "TRUE" : "FALSE");
435 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &hToken
))
438 Privileges
.PrivilegeCount
= 1;
439 Privileges
.Privileges
[0].Attributes
= (bEnable
) ? SE_PRIVILEGE_ENABLED
: 0;
441 if (!LookupPrivilegeValueW(NULL
, lpPrivilegeName
,
442 &Privileges
.Privileges
[0].Luid
))
448 bResult
= AdjustTokenPrivileges(hToken
, FALSE
, &Privileges
, 0, NULL
, NULL
);
456 /**************************************************************************
457 * DelayedMove [SETUPAPI.@]
459 * Moves a file upon the next reboot.
462 * lpExistingFileName [I] Current file name
463 * lpNewFileName [I] New file name
469 BOOL WINAPI
DelayedMove(LPCWSTR lpExistingFileName
, LPCWSTR lpNewFileName
)
471 return MoveFileExW(lpExistingFileName
, lpNewFileName
,
472 MOVEFILE_REPLACE_EXISTING
| MOVEFILE_DELAY_UNTIL_REBOOT
);
476 /**************************************************************************
477 * FileExists [SETUPAPI.@]
479 * Checks whether a file exists.
482 * lpFileName [I] Name of the file to check
483 * lpNewFileName [O] Optional information about the existing file
489 BOOL WINAPI
FileExists(LPCWSTR lpFileName
, LPWIN32_FIND_DATAW lpFileFindData
)
491 WIN32_FIND_DATAW FindData
;
496 uErrorMode
= SetErrorMode(SEM_FAILCRITICALERRORS
);
498 hFind
= FindFirstFileW(lpFileName
, &FindData
);
499 if (hFind
== INVALID_HANDLE_VALUE
)
501 dwError
= GetLastError();
502 SetErrorMode(uErrorMode
);
503 SetLastError(dwError
);
510 memcpy(lpFileFindData
, &FindData
, sizeof(WIN32_FIND_DATAW
));
512 SetErrorMode(uErrorMode
);
518 /**************************************************************************
519 * CaptureStringArg [SETUPAPI.@]
521 * Captures a UNICODE string.
524 * lpSrc [I] UNICODE string to be captured
525 * lpDst [O] Pointer to the captured UNICODE string
528 * Success: ERROR_SUCCESS
529 * Failure: ERROR_INVALID_PARAMETER
532 * Call MyFree to release the captured UNICODE string.
534 DWORD WINAPI
CaptureStringArg(LPCWSTR pSrc
, LPWSTR
*pDst
)
537 return ERROR_INVALID_PARAMETER
;
539 *pDst
= pSetupDuplicateString(pSrc
);
541 return ERROR_SUCCESS
;
545 /**************************************************************************
546 * pSetupCaptureAndConvertAnsiArg [SETUPAPI.@]
548 * Captures an ANSI string and converts it to a UNICODE string.
551 * lpSrc [I] ANSI string to be captured
552 * lpDst [O] Pointer to the captured UNICODE string
555 * Success: ERROR_SUCCESS
556 * Failure: ERROR_INVALID_PARAMETER
559 * Call MyFree to release the captured UNICODE string.
561 DWORD WINAPI
pSetupCaptureAndConvertAnsiArg(LPCSTR pSrc
, LPWSTR
*pDst
)
564 return ERROR_INVALID_PARAMETER
;
566 *pDst
= pSetupMultiByteToUnicode(pSrc
, CP_ACP
);
568 return ERROR_SUCCESS
;
572 /**************************************************************************
573 * pSetupOpenAndMapFileForRead [SETUPAPI.@]
575 * Open and map a file to a buffer.
578 * lpFileName [I] Name of the file to be opened
579 * lpSize [O] Pointer to the file size
580 * lpFile [0] Pointer to the file handle
581 * lpMapping [0] Pointer to the mapping handle
582 * lpBuffer [0] Pointer to the file buffer
585 * Success: ERROR_SUCCESS
589 * Call UnmapAndCloseFile to release the file.
591 DWORD WINAPI
pSetupOpenAndMapFileForRead(LPCWSTR lpFileName
,
599 TRACE("%s %p %p %p %p\n",
600 debugstr_w(lpFileName
), lpSize
, lpFile
, lpMapping
, lpBuffer
);
602 *lpFile
= CreateFileW(lpFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
603 OPEN_EXISTING
, 0, NULL
);
604 if (*lpFile
== INVALID_HANDLE_VALUE
)
605 return GetLastError();
607 *lpSize
= GetFileSize(*lpFile
, NULL
);
608 if (*lpSize
== INVALID_FILE_SIZE
)
610 dwError
= GetLastError();
611 CloseHandle(*lpFile
);
615 *lpMapping
= CreateFileMappingW(*lpFile
, NULL
, PAGE_READONLY
, 0,
617 if (*lpMapping
== NULL
)
619 dwError
= GetLastError();
620 CloseHandle(*lpFile
);
624 *lpBuffer
= MapViewOfFile(*lpMapping
, FILE_MAP_READ
, 0, 0, *lpSize
);
625 if (*lpBuffer
== NULL
)
627 dwError
= GetLastError();
628 CloseHandle(*lpMapping
);
629 CloseHandle(*lpFile
);
633 return ERROR_SUCCESS
;
637 /**************************************************************************
638 * pSetupUnmapAndCloseFile [SETUPAPI.@]
640 * Unmap and close a mapped file.
643 * hFile [I] Handle to the file
644 * hMapping [I] Handle to the file mapping
645 * lpBuffer [I] Pointer to the file buffer
651 BOOL WINAPI
pSetupUnmapAndCloseFile(HANDLE hFile
, HANDLE hMapping
, LPVOID lpBuffer
)
654 hFile
, hMapping
, lpBuffer
);
656 if (!UnmapViewOfFile(lpBuffer
))
659 if (!CloseHandle(hMapping
))
662 if (!CloseHandle(hFile
))
669 /**************************************************************************
670 * StampFileSecurity [SETUPAPI.@]
672 * Assign a new security descriptor to the given file.
675 * lpFileName [I] Name of the file
676 * pSecurityDescriptor [I] New security descriptor
679 * Success: ERROR_SUCCESS
682 DWORD WINAPI
StampFileSecurity(LPCWSTR lpFileName
, PSECURITY_DESCRIPTOR pSecurityDescriptor
)
684 TRACE("%s %p\n", debugstr_w(lpFileName
), pSecurityDescriptor
);
686 if (!SetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
687 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
688 pSecurityDescriptor
))
689 return GetLastError();
691 return ERROR_SUCCESS
;
695 /**************************************************************************
696 * TakeOwnershipOfFile [SETUPAPI.@]
698 * Takes the ownership of the given file.
701 * lpFileName [I] Name of the file
704 * Success: ERROR_SUCCESS
707 DWORD WINAPI
TakeOwnershipOfFile(LPCWSTR lpFileName
)
709 SECURITY_DESCRIPTOR SecDesc
;
710 HANDLE hToken
= NULL
;
711 PTOKEN_OWNER pOwner
= NULL
;
715 TRACE("%s\n", debugstr_w(lpFileName
));
717 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
718 return GetLastError();
720 if (!GetTokenInformation(hToken
, TokenOwner
, NULL
, 0, &dwSize
))
725 pOwner
= (PTOKEN_OWNER
)MyMalloc(dwSize
);
729 return ERROR_NOT_ENOUGH_MEMORY
;
732 if (!GetTokenInformation(hToken
, TokenOwner
, pOwner
, dwSize
, &dwSize
))
737 if (!InitializeSecurityDescriptor(&SecDesc
, SECURITY_DESCRIPTOR_REVISION
))
742 if (!SetSecurityDescriptorOwner(&SecDesc
, pOwner
->Owner
, FALSE
))
747 if (!SetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
, &SecDesc
))
755 return ERROR_SUCCESS
;
758 dwError
= GetLastError();
769 /**************************************************************************
770 * RetreiveFileSecurity [SETUPAPI.@]
772 * Retrieve the security descriptor that is associated with the given file.
775 * lpFileName [I] Name of the file
778 * Success: ERROR_SUCCESS
781 DWORD WINAPI
RetreiveFileSecurity(LPCWSTR lpFileName
,
782 PSECURITY_DESCRIPTOR
*pSecurityDescriptor
)
784 PSECURITY_DESCRIPTOR SecDesc
;
785 DWORD dwSize
= 0x100;
788 TRACE("%s %p\n", debugstr_w(lpFileName
), pSecurityDescriptor
);
790 SecDesc
= MyMalloc(dwSize
);
792 return ERROR_NOT_ENOUGH_MEMORY
;
794 if (GetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
795 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
796 SecDesc
, dwSize
, &dwSize
))
798 *pSecurityDescriptor
= SecDesc
;
799 return ERROR_SUCCESS
;
802 dwError
= GetLastError();
803 if (dwError
!= ERROR_INSUFFICIENT_BUFFER
)
809 SecDesc
= MyRealloc(SecDesc
, dwSize
);
811 return ERROR_NOT_ENOUGH_MEMORY
;
813 if (GetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
814 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
815 SecDesc
, dwSize
, &dwSize
))
817 *pSecurityDescriptor
= SecDesc
;
818 return ERROR_SUCCESS
;
821 dwError
= GetLastError();
828 static DWORD global_flags
= 0; /* FIXME: what should be in here? */
830 /***********************************************************************
831 * pSetupGetGlobalFlags (SETUPAPI.@)
833 DWORD WINAPI
pSetupGetGlobalFlags(void)
840 /***********************************************************************
841 * pSetupSetGlobalFlags (SETUPAPI.@)
843 void WINAPI
pSetupSetGlobalFlags( DWORD flags
)
845 global_flags
= flags
;
848 /***********************************************************************
849 * AssertFail (SETUPAPI.@)
851 * Shows an assert fail error messagebox
854 * lpFile [I] file where assert failed
855 * uLine [I] line number in file
856 * lpMessage [I] assert message
859 VOID WINAPI
AssertFail(LPSTR lpFile
, UINT uLine
, LPSTR lpMessage
)
861 CHAR szModule
[MAX_PATH
];
866 TRACE("%s %u %s\n", lpFile
, uLine
, lpMessage
);
868 GetModuleFileNameA(hInstance
, szModule
, MAX_PATH
);
869 lpName
= strrchr(szModule
, '\\');
876 "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
877 uLine
, lpFile
, lpMessage
);
879 if (MessageBoxA(NULL
, szBuffer
, lpName
, MB_SETFOREGROUND
|
880 MB_TASKMODAL
| MB_ICONERROR
| MB_YESNO
) == IDYES
)
885 /**************************************************************************
886 * GetSetFileTimestamp [SETUPAPI.@]
888 * Gets or sets a files timestamp.
891 * lpFileName [I] File name
892 * lpCreationTime [I/O] Creation time
893 * lpLastAccessTime [I/O] Last access time
894 * lpLastWriteTime [I/O] Last write time
895 * bSetFileTime [I] TRUE: Set file times
896 * FALSE: Get file times
899 * Success: ERROR_SUCCESS
902 DWORD WINAPI
GetSetFileTimestamp(LPCWSTR lpFileName
,
903 LPFILETIME lpCreationTime
,
904 LPFILETIME lpLastAccessTime
,
905 LPFILETIME lpLastWriteTime
,
906 BOOLEAN bSetFileTime
)
910 DWORD dwError
= ERROR_SUCCESS
;
912 TRACE("%s %p %p %p %x\n", debugstr_w(lpFileName
), lpCreationTime
,
913 lpLastAccessTime
, lpLastWriteTime
, bSetFileTime
);
915 hFile
= CreateFileW(lpFileName
,
916 bSetFileTime
? GENERIC_WRITE
: GENERIC_READ
,
917 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
923 if (hFile
== INVALID_HANDLE_VALUE
)
924 return GetLastError();
927 bRet
= SetFileTime(hFile
, lpCreationTime
, lpLastAccessTime
, lpLastWriteTime
);
929 bRet
= GetFileTime(hFile
, lpCreationTime
, lpLastAccessTime
, lpLastWriteTime
);
932 dwError
= GetLastError();
940 /**************************************************************************
941 * pSetupGetFileTitle [SETUPAPI.@]
943 * Returns a pointer to the last part of a fully qualified file name.
946 * lpFileName [I] File name
949 * Pointer to a files name.
952 pSetupGetFileTitle(LPCWSTR lpFileName
)
958 TRACE("%s\n", debugstr_w(lpFileName
));
960 ptr
= (LPWSTR
)lpFileName
;
970 if (c
== (WCHAR
)'\\' || c
== (WCHAR
)'/' || c
== (WCHAR
)':')
978 /**************************************************************************
979 * pSetupConcatenatePaths [SETUPAPI.@]
981 * Concatenates two paths.
984 * lpPath [I/O] Path to append path to
985 * lpAppend [I] Path to append
986 * dwBufferSize [I] Size of the path buffer
987 * lpRequiredSize [O] Required size for the concatenated path. Optional
994 pSetupConcatenatePaths(LPWSTR lpPath
,
997 LPDWORD lpRequiredSize
)
1002 BOOL bBackslash
= FALSE
;
1004 TRACE("%s %s %lu %p\n", debugstr_w(lpPath
), debugstr_w(lpAppend
),
1005 dwBufferSize
, lpRequiredSize
);
1007 dwPathSize
= lstrlenW(lpPath
);
1009 /* Ignore trailing backslash */
1010 if (lpPath
[dwPathSize
- 1] == (WCHAR
)'\\')
1013 dwAppendSize
= lstrlenW(lpAppend
);
1015 /* Does the source string have a leading backslash? */
1016 if (lpAppend
[0] == (WCHAR
)'\\')
1022 dwTotalSize
= dwPathSize
+ dwAppendSize
+ 2;
1023 if (lpRequiredSize
!= NULL
)
1024 *lpRequiredSize
= dwTotalSize
;
1026 /* Append a backslash to the destination string */
1027 if (bBackslash
== FALSE
)
1029 if (dwPathSize
< dwBufferSize
)
1031 lpPath
[dwPathSize
- 1] = (WCHAR
)'\\';
1036 if (dwPathSize
+ dwAppendSize
< dwBufferSize
)
1038 lstrcpynW(&lpPath
[dwPathSize
],
1043 if (dwBufferSize
>= dwTotalSize
)
1044 lpPath
[dwTotalSize
- 1] = 0;
1046 return (dwBufferSize
>= dwTotalSize
);
1050 /**************************************************************************
1051 * pSetupCenterWindowRelativeToParent [SETUPAPI.@]
1053 * Centers a window relative to its parent.
1056 * hwnd [I] Window to center.
1062 pSetupCenterWindowRelativeToParent(HWND hwnd
)
1068 INT nWindowWidth
, nWindowHeight
;
1069 INT nOwnerWidth
, nOwnerHeight
;
1072 hwndOwner
= GetWindow(hwnd
, GW_OWNER
);
1073 if (hwndOwner
== NULL
)
1078 ClientToScreen(hwndOwner
, &ptOrigin
);
1080 GetWindowRect(hwnd
, &rcWindow
);
1081 GetClientRect(hwndOwner
, &rcOwner
);
1083 nWindowWidth
= rcWindow
.right
- rcWindow
.left
;
1084 nWindowHeight
= rcWindow
.bottom
- rcWindow
.top
;
1086 nOwnerWidth
= rcOwner
.right
- rcOwner
.left
;
1087 nOwnerHeight
= rcOwner
.bottom
- rcOwner
.top
;
1089 posX
= ((nOwnerWidth
- nWindowWidth
) / 2) + ptOrigin
.x
;
1090 posY
= ((nOwnerHeight
- nWindowHeight
) / 2) + ptOrigin
.y
;
1092 MoveWindow(hwnd
, posX
, posY
, nWindowHeight
, nWindowWidth
, 0);
1096 /**************************************************************************
1097 * pSetupGetVersionInfoFromImage [SETUPAPI.@]
1099 * Retrieves version information for a given file.
1102 * lpFileName [I] File name
1103 * lpFileVersion [O] Pointer to the full file version
1104 * lpVersionVarSize [O] Pointer to the size of the variable version
1112 pSetupGetVersionInfoFromImage(LPWSTR lpFileName
,
1113 PULARGE_INTEGER lpFileVersion
,
1114 LPWORD lpVersionVarSize
)
1120 VS_FIXEDFILEINFO
*lpFixedInfo
;
1123 dwSize
= GetFileVersionInfoSizeW(lpFileName
, &dwHandle
);
1127 lpInfo
= MyMalloc(dwSize
);
1131 if (!GetFileVersionInfoW(lpFileName
, 0, dwSize
, lpInfo
))
1137 if (!VerQueryValueW(lpInfo
, BackSlash
,
1138 (LPVOID
*)&lpFixedInfo
, &uSize
))
1144 lpFileVersion
->LowPart
= lpFixedInfo
->dwFileVersionLS
;
1145 lpFileVersion
->HighPart
= lpFixedInfo
->dwFileVersionMS
;
1147 *lpVersionVarSize
= 0;
1148 if (!VerQueryValueW(lpInfo
, TranslationRegKey
,
1149 (LPVOID
*)&lpVarSize
, &uSize
))
1157 *lpVersionVarSize
= *lpVarSize
;
1165 /***********************************************************************
1166 * SetupUninstallOEMInfW (SETUPAPI.@)
1168 BOOL WINAPI
SetupUninstallOEMInfW( PCWSTR inf_file
, DWORD flags
, PVOID reserved
)
1170 static const WCHAR infW
[] = {'\\','i','n','f','\\',0};
1171 WCHAR target
[MAX_PATH
];
1173 TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file
), flags
, reserved
);
1177 SetLastError(ERROR_INVALID_PARAMETER
);
1181 if (!GetWindowsDirectoryW( target
, sizeof(target
)/sizeof(WCHAR
) )) return FALSE
;
1183 strcatW( target
, infW
);
1184 strcatW( target
, inf_file
);
1186 if (flags
& SUOI_FORCEDELETE
)
1187 return DeleteFileW(target
);
1189 FIXME("not deleting %s\n", debugstr_w(target
));
1194 /***********************************************************************
1195 * SetupUninstallOEMInfA (SETUPAPI.@)
1197 BOOL WINAPI
SetupUninstallOEMInfA( PCSTR inf_file
, DWORD flags
, PVOID reserved
)
1200 WCHAR
*inf_fileW
= NULL
;
1202 TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file
), flags
, reserved
);
1204 if (inf_file
&& !(inf_fileW
= strdupAtoW( inf_file
))) return FALSE
;
1205 ret
= SetupUninstallOEMInfW( inf_fileW
, flags
, reserved
);
1206 HeapFree( GetProcessHeap(), 0, inf_fileW
);
1210 /***********************************************************************
1211 * InstallCatalog (SETUPAPI.@)
1213 DWORD WINAPI
InstallCatalog( LPCSTR catalog
, LPCSTR basename
, LPSTR fullname
)
1215 FIXME("%s, %s, %p\n", debugstr_a(catalog
), debugstr_a(basename
), fullname
);
1219 static UINT
detect_compression_type( LPCWSTR file
)
1223 UINT type
= FILE_COMPRESSION_NONE
;
1224 static const BYTE LZ_MAGIC
[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1225 static const BYTE MSZIP_MAGIC
[] = { 0x4b, 0x57, 0x41, 0x4a };
1226 static const BYTE NTCAB_MAGIC
[] = { 0x4d, 0x53, 0x43, 0x46 };
1229 handle
= CreateFileW( file
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1230 if (handle
== INVALID_HANDLE_VALUE
)
1232 ERR("cannot open file %s\n", debugstr_w(file
));
1233 return FILE_COMPRESSION_NONE
;
1235 if (!ReadFile( handle
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
1237 CloseHandle( handle
);
1238 return FILE_COMPRESSION_NONE
;
1240 if (!memcmp( buffer
, LZ_MAGIC
, sizeof(LZ_MAGIC
) )) type
= FILE_COMPRESSION_WINLZA
;
1241 else if (!memcmp( buffer
, MSZIP_MAGIC
, sizeof(MSZIP_MAGIC
) )) type
= FILE_COMPRESSION_MSZIP
;
1242 else if (!memcmp( buffer
, NTCAB_MAGIC
, sizeof(NTCAB_MAGIC
) )) type
= FILE_COMPRESSION_MSZIP
; /* not a typo */
1244 CloseHandle( handle
);
1248 static BOOL
get_file_size( LPCWSTR file
, DWORD
*size
)
1252 handle
= CreateFileW( file
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1253 if (handle
== INVALID_HANDLE_VALUE
)
1255 ERR("cannot open file %s\n", debugstr_w(file
));
1258 *size
= GetFileSize( handle
, NULL
);
1259 CloseHandle( handle
);
1263 static BOOL
get_file_sizes_none( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1267 if (!get_file_size( source
, &size
)) return FALSE
;
1268 if (source_size
) *source_size
= size
;
1269 if (target_size
) *target_size
= size
;
1273 static BOOL
get_file_sizes_lz( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1280 if (!get_file_size( source
, &size
)) ret
= FALSE
;
1281 else *source_size
= size
;
1288 if ((file
= LZOpenFileW( (LPWSTR
)source
, &of
, OF_READ
)) < 0)
1290 ERR("cannot open source file for reading\n");
1293 *target_size
= LZSeek( file
, 0, 2 );
1299 static UINT CALLBACK
file_compression_info_callback( PVOID context
, UINT notification
, UINT_PTR param1
, UINT_PTR param2
)
1301 DWORD
*size
= context
;
1302 FILE_IN_CABINET_INFO_W
*info
= (FILE_IN_CABINET_INFO_W
*)param1
;
1304 switch (notification
)
1306 case SPFILENOTIFY_FILEINCABINET
:
1308 *size
= info
->FileSize
;
1311 default: return NO_ERROR
;
1315 static BOOL
get_file_sizes_cab( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1322 if (!get_file_size( source
, &size
)) ret
= FALSE
;
1323 else *source_size
= size
;
1327 ret
= SetupIterateCabinetW( source
, 0, file_compression_info_callback
, target_size
);
1332 /***********************************************************************
1333 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1335 * See SetupGetFileCompressionInfoExW.
1337 BOOL WINAPI
SetupGetFileCompressionInfoExA( PCSTR source
, PSTR name
, DWORD len
, PDWORD required
,
1338 PDWORD source_size
, PDWORD target_size
, PUINT type
)
1341 WCHAR
*nameW
= NULL
, *sourceW
= NULL
;
1345 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source
), name
, len
, required
,
1346 source_size
, target_size
, type
);
1348 if (!source
|| !(sourceW
= pSetupMultiByteToUnicode( source
, CP_ACP
))) return FALSE
;
1352 ret
= SetupGetFileCompressionInfoExW( sourceW
, NULL
, 0, &nb_chars
, NULL
, NULL
, NULL
);
1353 if (!(nameW
= HeapAlloc( GetProcessHeap(), 0, nb_chars
* sizeof(WCHAR
) )))
1359 ret
= SetupGetFileCompressionInfoExW( sourceW
, nameW
, nb_chars
, &nb_chars
, source_size
, target_size
, type
);
1362 if ((nameA
= pSetupUnicodeToMultiByte( nameW
, CP_ACP
)))
1364 if (name
&& len
>= nb_chars
) lstrcpyA( name
, nameA
);
1367 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1373 if (required
) *required
= nb_chars
;
1374 HeapFree( GetProcessHeap(), 0, nameW
);
1380 /***********************************************************************
1381 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1383 * Get compression type and compressed/uncompressed sizes of a given file.
1386 * source [I] File to examine.
1387 * name [O] Actual filename used.
1388 * len [I] Length in characters of 'name' buffer.
1389 * required [O] Number of characters written to 'name'.
1390 * source_size [O] Size of compressed file.
1391 * target_size [O] Size of uncompressed file.
1392 * type [O] Compression type.
1398 BOOL WINAPI
SetupGetFileCompressionInfoExW( PCWSTR source
, PWSTR name
, DWORD len
, PDWORD required
,
1399 PDWORD source_size
, PDWORD target_size
, PUINT type
)
1405 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source
), name
, len
, required
,
1406 source_size
, target_size
, type
);
1408 if (!source
) return FALSE
;
1410 source_len
= lstrlenW( source
) + 1;
1411 if (required
) *required
= source_len
;
1412 if (name
&& len
>= source_len
)
1414 lstrcpyW( name
, source
);
1419 comp
= detect_compression_type( source
);
1420 if (type
) *type
= comp
;
1424 case FILE_COMPRESSION_MSZIP
:
1425 case FILE_COMPRESSION_NTCAB
: ret
= get_file_sizes_cab( source
, source_size
, target_size
); break;
1426 case FILE_COMPRESSION_NONE
: ret
= get_file_sizes_none( source
, source_size
, target_size
); break;
1427 case FILE_COMPRESSION_WINLZA
: ret
= get_file_sizes_lz( source
, source_size
, target_size
); break;
1433 /***********************************************************************
1434 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1436 * See SetupGetFileCompressionInfoW.
1438 DWORD WINAPI
SetupGetFileCompressionInfoA( PCSTR source
, PSTR
*name
, PDWORD source_size
,
1439 PDWORD target_size
, PUINT type
)
1442 DWORD error
, required
;
1445 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source
), name
, source_size
, target_size
, type
);
1447 if (!source
|| !name
|| !source_size
|| !target_size
|| !type
)
1448 return ERROR_INVALID_PARAMETER
;
1450 ret
= SetupGetFileCompressionInfoExA( source
, NULL
, 0, &required
, NULL
, NULL
, NULL
);
1451 if (!(actual_name
= MyMalloc( required
))) return ERROR_NOT_ENOUGH_MEMORY
;
1453 ret
= SetupGetFileCompressionInfoExA( source
, actual_name
, required
, &required
,
1454 source_size
, target_size
, type
);
1457 error
= GetLastError();
1458 MyFree( actual_name
);
1461 *name
= actual_name
;
1462 return ERROR_SUCCESS
;
1465 /***********************************************************************
1466 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1468 * Get compression type and compressed/uncompressed sizes of a given file.
1471 * source [I] File to examine.
1472 * name [O] Actual filename used.
1473 * source_size [O] Size of compressed file.
1474 * target_size [O] Size of uncompressed file.
1475 * type [O] Compression type.
1478 * Success: ERROR_SUCCESS
1479 * Failure: Win32 error code.
1481 DWORD WINAPI
SetupGetFileCompressionInfoW( PCWSTR source
, PWSTR
*name
, PDWORD source_size
,
1482 PDWORD target_size
, PUINT type
)
1485 DWORD error
, required
;
1488 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source
), name
, source_size
, target_size
, type
);
1490 if (!source
|| !name
|| !source_size
|| !target_size
|| !type
)
1491 return ERROR_INVALID_PARAMETER
;
1493 ret
= SetupGetFileCompressionInfoExW( source
, NULL
, 0, &required
, NULL
, NULL
, NULL
);
1494 if (!(actual_name
= MyMalloc( required
))) return ERROR_NOT_ENOUGH_MEMORY
;
1496 ret
= SetupGetFileCompressionInfoExW( source
, actual_name
, required
, &required
,
1497 source_size
, target_size
, type
);
1500 error
= GetLastError();
1501 MyFree( actual_name
);
1504 *name
= actual_name
;
1505 return ERROR_SUCCESS
;
1508 static DWORD
decompress_file_lz( LPCWSTR source
, LPCWSTR target
)
1515 if ((src
= LZOpenFileW( (LPWSTR
)source
, &sof
, OF_READ
)) < 0)
1517 ERR("cannot open source file for reading\n");
1518 return ERROR_FILE_NOT_FOUND
;
1520 if ((dst
= LZOpenFileW( (LPWSTR
)target
, &dof
, OF_CREATE
)) < 0)
1522 ERR("cannot open target file for writing\n");
1524 return ERROR_FILE_NOT_FOUND
;
1526 if ((error
= LZCopy( src
, dst
)) >= 0) ret
= ERROR_SUCCESS
;
1529 WARN("failed to decompress file %d\n", error
);
1530 ret
= ERROR_INVALID_DATA
;
1538 static UINT CALLBACK
decompress_or_copy_callback( PVOID context
, UINT notification
, UINT_PTR param1
, UINT_PTR param2
)
1540 FILE_IN_CABINET_INFO_W
*info
= (FILE_IN_CABINET_INFO_W
*)param1
;
1542 switch (notification
)
1544 case SPFILENOTIFY_FILEINCABINET
:
1546 LPCWSTR filename
, targetname
= context
;
1549 if ((p
= strrchrW( targetname
, '\\' ))) filename
= p
+ 1;
1550 else filename
= targetname
;
1552 if (!lstrcmpiW( filename
, info
->NameInCabinet
))
1554 strcpyW( info
->FullTargetName
, targetname
);
1559 default: return NO_ERROR
;
1563 static DWORD
decompress_file_cab( LPCWSTR source
, LPCWSTR target
)
1567 ret
= SetupIterateCabinetW( source
, 0, decompress_or_copy_callback
, (PVOID
)target
);
1569 if (ret
) return ERROR_SUCCESS
;
1570 else return GetLastError();
1573 /***********************************************************************
1574 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1576 * See SetupDecompressOrCopyFileW.
1578 DWORD WINAPI
SetupDecompressOrCopyFileA( PCSTR source
, PCSTR target
, PUINT type
)
1581 WCHAR
*sourceW
= NULL
, *targetW
= NULL
;
1583 if (source
&& !(sourceW
= pSetupMultiByteToUnicode( source
, CP_ACP
))) return FALSE
;
1584 if (target
&& !(targetW
= pSetupMultiByteToUnicode( target
, CP_ACP
)))
1587 return ERROR_NOT_ENOUGH_MEMORY
;
1590 ret
= SetupDecompressOrCopyFileW( sourceW
, targetW
, type
);
1598 /***********************************************************************
1599 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1601 * Copy a file and decompress it if needed.
1604 * source [I] File to copy.
1605 * target [I] Filename of the copy.
1606 * type [I] Compression type.
1609 * Success: ERROR_SUCCESS
1610 * Failure: Win32 error code.
1612 DWORD WINAPI
SetupDecompressOrCopyFileW( PCWSTR source
, PCWSTR target
, PUINT type
)
1615 DWORD ret
= ERROR_INVALID_PARAMETER
;
1617 if (!source
|| !target
) return ERROR_INVALID_PARAMETER
;
1619 if (!type
) comp
= detect_compression_type( source
);
1624 case FILE_COMPRESSION_NONE
:
1625 if (CopyFileW( source
, target
, FALSE
)) ret
= ERROR_SUCCESS
;
1626 else ret
= GetLastError();
1628 case FILE_COMPRESSION_WINLZA
:
1629 ret
= decompress_file_lz( source
, target
);
1631 case FILE_COMPRESSION_NTCAB
:
1632 case FILE_COMPRESSION_MSZIP
:
1633 ret
= decompress_file_cab( source
, target
);
1636 WARN("unknown compression type %d\n", comp
);
1640 TRACE("%s -> %s %d\n", debugstr_w(source
), debugstr_w(target
), comp
);
1645 * implemented (used by pSetupGuidFromString)
1647 static BOOL
TrimGuidString(PCWSTR szString
, LPWSTR szNewString
)
1652 if (wcslen(szString
) == 38)
1654 if ((szString
[0] == L
'{') && (szString
[37] == L
'}'))
1656 for (Index
= 0; Index
< wcslen(szString
); Index
++)
1657 szBuffer
[Index
] = szString
[Index
+ 1];
1659 szBuffer
[36] = L
'\0';
1660 wcscpy(szNewString
, szBuffer
);
1664 szNewString
[0] = L
'\0';
1673 pSetupGuidFromString(PCWSTR pString
, LPGUID lpGUID
)
1678 if (!TrimGuidString(pString
, szBuffer
))
1680 return RPC_S_INVALID_STRING_UUID
;
1683 Status
= UuidFromStringW(szBuffer
, lpGUID
);
1684 if (Status
!= RPC_S_OK
)
1686 return RPC_S_INVALID_STRING_UUID
;
1697 pSetupStringFromGuid(LPGUID lpGUID
, PWSTR pString
, DWORD dwStringLen
)
1703 if (dwStringLen
< 39)
1705 return ERROR_INSUFFICIENT_BUFFER
;
1708 Status
= UuidToStringW(lpGUID
, &rpcBuffer
);
1709 if (Status
!= RPC_S_OK
)
1714 wcscpy(szBuffer
, L
"{");
1715 wcscat(szBuffer
, rpcBuffer
);
1716 wcscat(szBuffer
, L
"}");
1718 wcscpy(pString
, szBuffer
);
1720 RpcStringFreeW(&rpcBuffer
);
1729 pSetupIsGuidNull(LPGUID lpGUID
)
1731 return IsEqualGUID(lpGUID
, &GUID_NULL
);
1739 pSetupIsUserAdmin(VOID
)
1741 SID_IDENTIFIER_AUTHORITY Authority
= {SECURITY_NT_AUTHORITY
};
1742 BOOL bResult
= FALSE
;
1745 if (!AllocateAndInitializeSid(&Authority
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
1746 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0,
1752 if (!CheckTokenMembership(NULL
, lpSid
, &bResult
))
1762 /***********************************************************************
1763 * SetupInitializeFileLogW(SETUPAPI.@)
1765 HSPFILELOG WINAPI
SetupInitializeFileLogW(LPCWSTR LogFileName
, DWORD Flags
)
1767 struct FileLog
* Log
;
1769 WCHAR Windir
[MAX_PATH
];
1772 TRACE("%s, 0x%x\n",debugstr_w(LogFileName
),Flags
);
1774 if (Flags
& SPFILELOG_SYSTEMLOG
)
1776 if (!pSetupIsUserAdmin() && !(Flags
& SPFILELOG_QUERYONLY
))
1778 /* insufficient privileges */
1779 SetLastError(ERROR_ACCESS_DENIED
);
1780 return INVALID_HANDLE_VALUE
;
1783 if (LogFileName
|| (Flags
& SPFILELOG_FORCENEW
))
1785 /* invalid parameter */
1786 SetLastError(ERROR_INVALID_PARAMETER
);
1787 return INVALID_HANDLE_VALUE
;
1790 ret
= GetSystemWindowsDirectoryW(Windir
, MAX_PATH
);
1791 if (!ret
|| ret
>= MAX_PATH
)
1793 /* generic failure */
1794 return INVALID_HANDLE_VALUE
;
1798 wcscat(Windir
, L
"repair\\setup.log");
1804 /* invalid parameter */
1805 SetLastError(ERROR_INVALID_PARAMETER
);
1806 return INVALID_HANDLE_VALUE
;
1809 wcsncpy(Windir
, LogFileName
, MAX_PATH
);
1812 if (FileExists(Windir
, NULL
))
1814 /* take ownership */
1815 ret
= TakeOwnershipOfFile(Windir
);
1817 if (ret
!= ERROR_SUCCESS
)
1821 return INVALID_HANDLE_VALUE
;
1824 if (!SetFileAttributesW(Windir
, FILE_ATTRIBUTE_NORMAL
))
1827 return INVALID_HANDLE_VALUE
;
1830 if ((Flags
& SPFILELOG_FORCENEW
))
1832 if (!DeleteFileW(Windir
))
1835 return INVALID_HANDLE_VALUE
;
1841 hLog
= CreateFileW(Windir
,
1842 (Flags
& SPFILELOG_QUERYONLY
) ? GENERIC_READ
: GENERIC_WRITE
,
1843 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1846 FILE_ATTRIBUTE_NORMAL
,
1849 if (hLog
== INVALID_HANDLE_VALUE
)
1852 return INVALID_HANDLE_VALUE
;
1855 /* close log handle */
1858 /* allocate file log struct */
1859 Log
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct FileLog
));
1862 /* not enough memory */
1863 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1864 return INVALID_HANDLE_VALUE
;
1867 /* initialize log */
1868 Log
->LogName
= HeapAlloc(GetProcessHeap(), 0, (wcslen(Windir
)+1) * sizeof(WCHAR
));
1871 /* not enough memory */
1872 HeapFree(GetProcessHeap(), 0, Log
);
1873 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1874 return INVALID_HANDLE_VALUE
;
1877 wcscpy(Log
->LogName
, Windir
);
1878 Log
->ReadOnly
= (Flags
& SPFILELOG_QUERYONLY
);
1879 Log
->SystemLog
= (Flags
& SPFILELOG_SYSTEMLOG
);
1881 return (HSPFILELOG
)Log
;
1884 /***********************************************************************
1885 * SetupInitializeFileLogA(SETUPAPI.@)
1887 HSPFILELOG WINAPI
SetupInitializeFileLogA(LPCSTR LogFileName
, DWORD Flags
)
1890 LPWSTR LogFileNameW
= NULL
;
1892 TRACE("%s, 0x%x\n",debugstr_a(LogFileName
),Flags
);
1896 LogFileNameW
= strdupAtoW(LogFileName
);
1900 /* not enough memory */
1901 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1902 return INVALID_HANDLE_VALUE
;
1905 hLog
= SetupInitializeFileLogW(LogFileNameW
, Flags
);
1906 HeapFree(GetProcessHeap(), 0, LogFileNameW
);
1910 hLog
= SetupInitializeFileLogW(NULL
, Flags
);
1916 /***********************************************************************
1917 * SetupTerminateFileLog(SETUPAPI.@)
1919 BOOL WINAPI
SetupTerminateFileLog(HANDLE FileLogHandle
)
1921 struct FileLog
* Log
;
1923 TRACE ("%p\n",FileLogHandle
);
1925 Log
= (struct FileLog
*)FileLogHandle
;
1927 /* free file log handle */
1928 HeapFree(GetProcessHeap(), 0, Log
->LogName
);
1929 HeapFree(GetProcessHeap(), 0, Log
);
1931 SetLastError(ERROR_SUCCESS
);