gdiplus: Support GdipSetClipRegion in metafiles.
[wine.git] / dlls / setupapi / misc.c
blob98a6ed7e89e4911713471aff88c5bb8726104a1a
1 /*
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 <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30 #include "lzexpand.h"
31 #include "softpub.h"
32 #include "mscat.h"
33 #include "shlobj.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 #include "setupapi_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
42 /* arbitrary limit not related to what native actually uses */
43 #define OEM_INDEX_LIMIT 999
45 /* Handles and critical sections for the SetupLog API */
46 static HANDLE setupact = INVALID_HANDLE_VALUE;
47 static HANDLE setuperr = INVALID_HANDLE_VALUE;
48 static CRITICAL_SECTION setupapi_cs;
49 static CRITICAL_SECTION_DEBUG critsect_debug =
51 0, 0, &setupapi_cs,
52 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
53 0, 0, { (DWORD_PTR)(__FILE__ ": setupapi_cs") }
55 static CRITICAL_SECTION setupapi_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
57 /**************************************************************************
58 * MyFree [SETUPAPI.@]
60 * Frees an allocated memory block from the process heap.
62 * PARAMS
63 * lpMem [I] pointer to memory block which will be freed
65 * RETURNS
66 * None
68 VOID WINAPI MyFree(LPVOID lpMem)
70 HeapFree(GetProcessHeap(), 0, lpMem);
74 /**************************************************************************
75 * MyMalloc [SETUPAPI.@]
77 * Allocates memory block from the process heap.
79 * PARAMS
80 * dwSize [I] size of the allocated memory block
82 * RETURNS
83 * Success: pointer to allocated memory block
84 * Failure: NULL
86 LPVOID WINAPI MyMalloc(DWORD dwSize)
88 return HeapAlloc(GetProcessHeap(), 0, dwSize);
92 /**************************************************************************
93 * MyRealloc [SETUPAPI.@]
95 * Changes the size of an allocated memory block or allocates a memory
96 * block from the process heap.
98 * PARAMS
99 * lpSrc [I] pointer to memory block which will be resized
100 * dwSize [I] new size of the memory block
102 * RETURNS
103 * Success: pointer to the resized memory block
104 * Failure: NULL
106 * NOTES
107 * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
108 * block like MyMalloc.
110 LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
112 if (lpSrc == NULL)
113 return HeapAlloc(GetProcessHeap(), 0, dwSize);
115 return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
119 /**************************************************************************
120 * DuplicateString [SETUPAPI.@]
122 * Duplicates a unicode string.
124 * PARAMS
125 * lpSrc [I] pointer to the unicode string that will be duplicated
127 * RETURNS
128 * Success: pointer to the duplicated unicode string
129 * Failure: NULL
131 * NOTES
132 * Call MyFree() to release the duplicated string.
134 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
136 LPWSTR lpDst;
138 lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
139 if (lpDst == NULL)
140 return NULL;
142 strcpyW(lpDst, lpSrc);
144 return lpDst;
148 /**************************************************************************
149 * QueryRegistryValue [SETUPAPI.@]
151 * Retrieves value data from the registry and allocates memory for the
152 * value data.
154 * PARAMS
155 * hKey [I] Handle of the key to query
156 * lpValueName [I] Name of value under hkey to query
157 * lpData [O] Destination for the values contents,
158 * lpType [O] Destination for the value type
159 * lpcbData [O] Destination for the size of data
161 * RETURNS
162 * Success: ERROR_SUCCESS
163 * Failure: Otherwise
165 * NOTES
166 * Use MyFree to release the lpData buffer.
168 LONG WINAPI QueryRegistryValue(HKEY hKey,
169 LPCWSTR lpValueName,
170 LPBYTE *lpData,
171 LPDWORD lpType,
172 LPDWORD lpcbData)
174 LONG lError;
176 TRACE("%p %s %p %p %p\n",
177 hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
179 /* Get required buffer size */
180 *lpcbData = 0;
181 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
182 if (lError != ERROR_SUCCESS)
183 return lError;
185 /* Allocate buffer */
186 *lpData = MyMalloc(*lpcbData);
187 if (*lpData == NULL)
188 return ERROR_NOT_ENOUGH_MEMORY;
190 /* Query registry value */
191 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
192 if (lError != ERROR_SUCCESS)
193 MyFree(*lpData);
195 return lError;
199 /**************************************************************************
200 * IsUserAdmin [SETUPAPI.@]
202 * Checks whether the current user is a member of the Administrators group.
204 * PARAMS
205 * None
207 * RETURNS
208 * Success: TRUE
209 * Failure: FALSE
211 BOOL WINAPI IsUserAdmin(VOID)
213 TRACE("\n");
214 return IsUserAnAdmin();
218 /**************************************************************************
219 * MultiByteToUnicode [SETUPAPI.@]
221 * Converts a multi-byte string to a Unicode string.
223 * PARAMS
224 * lpMultiByteStr [I] Multi-byte string to be converted
225 * uCodePage [I] Code page
227 * RETURNS
228 * Success: pointer to the converted Unicode string
229 * Failure: NULL
231 * NOTE
232 * Use MyFree to release the returned Unicode string.
234 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
236 LPWSTR lpUnicodeStr;
237 int nLength;
239 nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
240 -1, NULL, 0);
241 if (nLength == 0)
242 return NULL;
244 lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
245 if (lpUnicodeStr == NULL)
246 return NULL;
248 if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
249 nLength, lpUnicodeStr, nLength))
251 MyFree(lpUnicodeStr);
252 return NULL;
255 return lpUnicodeStr;
259 /**************************************************************************
260 * UnicodeToMultiByte [SETUPAPI.@]
262 * Converts a Unicode string to a multi-byte string.
264 * PARAMS
265 * lpUnicodeStr [I] Unicode string to be converted
266 * uCodePage [I] Code page
268 * RETURNS
269 * Success: pointer to the converted multi-byte string
270 * Failure: NULL
272 * NOTE
273 * Use MyFree to release the returned multi-byte string.
275 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
277 LPSTR lpMultiByteStr;
278 int nLength;
280 nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
281 NULL, 0, NULL, NULL);
282 if (nLength == 0)
283 return NULL;
285 lpMultiByteStr = MyMalloc(nLength);
286 if (lpMultiByteStr == NULL)
287 return NULL;
289 if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
290 lpMultiByteStr, nLength, NULL, NULL))
292 MyFree(lpMultiByteStr);
293 return NULL;
296 return lpMultiByteStr;
300 /**************************************************************************
301 * DoesUserHavePrivilege [SETUPAPI.@]
303 * Check whether the current user has got a given privilege.
305 * PARAMS
306 * lpPrivilegeName [I] Name of the privilege to be checked
308 * RETURNS
309 * Success: TRUE
310 * Failure: FALSE
312 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
314 HANDLE hToken;
315 DWORD dwSize;
316 PTOKEN_PRIVILEGES lpPrivileges;
317 LUID PrivilegeLuid;
318 DWORD i;
319 BOOL bResult = FALSE;
321 TRACE("%s\n", debugstr_w(lpPrivilegeName));
323 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
324 return FALSE;
326 if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
328 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
330 CloseHandle(hToken);
331 return FALSE;
335 lpPrivileges = MyMalloc(dwSize);
336 if (lpPrivileges == NULL)
338 CloseHandle(hToken);
339 return FALSE;
342 if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
344 MyFree(lpPrivileges);
345 CloseHandle(hToken);
346 return FALSE;
349 CloseHandle(hToken);
351 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
353 MyFree(lpPrivileges);
354 return FALSE;
357 for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
359 if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
360 lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
362 bResult = TRUE;
366 MyFree(lpPrivileges);
368 return bResult;
372 /**************************************************************************
373 * EnablePrivilege [SETUPAPI.@]
375 * Enables or disables one of the current users privileges.
377 * PARAMS
378 * lpPrivilegeName [I] Name of the privilege to be changed
379 * bEnable [I] TRUE: Enables the privilege
380 * FALSE: Disables the privilege
382 * RETURNS
383 * Success: TRUE
384 * Failure: FALSE
386 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
388 TOKEN_PRIVILEGES Privileges;
389 HANDLE hToken;
390 BOOL bResult;
392 TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
394 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
395 return FALSE;
397 Privileges.PrivilegeCount = 1;
398 Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
400 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
401 &Privileges.Privileges[0].Luid))
403 CloseHandle(hToken);
404 return FALSE;
407 bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
409 CloseHandle(hToken);
411 return bResult;
415 /**************************************************************************
416 * DelayedMove [SETUPAPI.@]
418 * Moves a file upon the next reboot.
420 * PARAMS
421 * lpExistingFileName [I] Current file name
422 * lpNewFileName [I] New file name
424 * RETURNS
425 * Success: TRUE
426 * Failure: FALSE
428 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
430 return MoveFileExW(lpExistingFileName, lpNewFileName,
431 MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
435 /**************************************************************************
436 * FileExists [SETUPAPI.@]
438 * Checks whether a file exists.
440 * PARAMS
441 * lpFileName [I] Name of the file to check
442 * lpNewFileName [O] Optional information about the existing file
444 * RETURNS
445 * Success: TRUE
446 * Failure: FALSE
448 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
450 WIN32_FIND_DATAW FindData;
451 HANDLE hFind;
452 UINT uErrorMode;
453 DWORD dwError;
455 uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
457 hFind = FindFirstFileW(lpFileName, &FindData);
458 if (hFind == INVALID_HANDLE_VALUE)
460 dwError = GetLastError();
461 SetErrorMode(uErrorMode);
462 SetLastError(dwError);
463 return FALSE;
466 FindClose(hFind);
468 if (lpFileFindData)
469 *lpFileFindData = FindData;
471 SetErrorMode(uErrorMode);
473 return TRUE;
477 /**************************************************************************
478 * CaptureStringArg [SETUPAPI.@]
480 * Captures a UNICODE string.
482 * PARAMS
483 * lpSrc [I] UNICODE string to be captured
484 * lpDst [O] Pointer to the captured UNICODE string
486 * RETURNS
487 * Success: ERROR_SUCCESS
488 * Failure: ERROR_INVALID_PARAMETER
490 * NOTE
491 * Call MyFree to release the captured UNICODE string.
493 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
495 if (pDst == NULL)
496 return ERROR_INVALID_PARAMETER;
498 *pDst = DuplicateString(pSrc);
500 return ERROR_SUCCESS;
504 /**************************************************************************
505 * CaptureAndConvertAnsiArg [SETUPAPI.@]
507 * Captures an ANSI string and converts it to a UNICODE string.
509 * PARAMS
510 * lpSrc [I] ANSI string to be captured
511 * lpDst [O] Pointer to the captured UNICODE string
513 * RETURNS
514 * Success: ERROR_SUCCESS
515 * Failure: ERROR_INVALID_PARAMETER
517 * NOTE
518 * Call MyFree to release the captured UNICODE string.
520 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
522 if (pDst == NULL)
523 return ERROR_INVALID_PARAMETER;
525 *pDst = MultiByteToUnicode(pSrc, CP_ACP);
527 return ERROR_SUCCESS;
531 /**************************************************************************
532 * OpenAndMapFileForRead [SETUPAPI.@]
534 * Open and map a file to a buffer.
536 * PARAMS
537 * lpFileName [I] Name of the file to be opened
538 * lpSize [O] Pointer to the file size
539 * lpFile [0] Pointer to the file handle
540 * lpMapping [0] Pointer to the mapping handle
541 * lpBuffer [0] Pointer to the file buffer
543 * RETURNS
544 * Success: ERROR_SUCCESS
545 * Failure: Other
547 * NOTE
548 * Call UnmapAndCloseFile to release the file.
550 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
551 LPDWORD lpSize,
552 LPHANDLE lpFile,
553 LPHANDLE lpMapping,
554 LPVOID *lpBuffer)
556 DWORD dwError;
558 TRACE("%s %p %p %p %p\n",
559 debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
561 *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
562 OPEN_EXISTING, 0, NULL);
563 if (*lpFile == INVALID_HANDLE_VALUE)
564 return GetLastError();
566 *lpSize = GetFileSize(*lpFile, NULL);
567 if (*lpSize == INVALID_FILE_SIZE)
569 dwError = GetLastError();
570 CloseHandle(*lpFile);
571 return dwError;
574 *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
575 *lpSize, NULL);
576 if (*lpMapping == NULL)
578 dwError = GetLastError();
579 CloseHandle(*lpFile);
580 return dwError;
583 *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
584 if (*lpBuffer == NULL)
586 dwError = GetLastError();
587 CloseHandle(*lpMapping);
588 CloseHandle(*lpFile);
589 return dwError;
592 return ERROR_SUCCESS;
596 /**************************************************************************
597 * UnmapAndCloseFile [SETUPAPI.@]
599 * Unmap and close a mapped file.
601 * PARAMS
602 * hFile [I] Handle to the file
603 * hMapping [I] Handle to the file mapping
604 * lpBuffer [I] Pointer to the file buffer
606 * RETURNS
607 * Success: TRUE
608 * Failure: FALSE
610 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
612 TRACE("%p %p %p\n",
613 hFile, hMapping, lpBuffer);
615 if (!UnmapViewOfFile(lpBuffer))
616 return FALSE;
618 if (!CloseHandle(hMapping))
619 return FALSE;
621 if (!CloseHandle(hFile))
622 return FALSE;
624 return TRUE;
628 /**************************************************************************
629 * StampFileSecurity [SETUPAPI.@]
631 * Assign a new security descriptor to the given file.
633 * PARAMS
634 * lpFileName [I] Name of the file
635 * pSecurityDescriptor [I] New security descriptor
637 * RETURNS
638 * Success: ERROR_SUCCESS
639 * Failure: other
641 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
643 TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
645 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
646 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
647 pSecurityDescriptor))
648 return GetLastError();
650 return ERROR_SUCCESS;
654 /**************************************************************************
655 * TakeOwnershipOfFile [SETUPAPI.@]
657 * Takes the ownership of the given file.
659 * PARAMS
660 * lpFileName [I] Name of the file
662 * RETURNS
663 * Success: ERROR_SUCCESS
664 * Failure: other
666 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
668 SECURITY_DESCRIPTOR SecDesc;
669 HANDLE hToken = NULL;
670 PTOKEN_OWNER pOwner = NULL;
671 DWORD dwError;
672 DWORD dwSize;
674 TRACE("%s\n", debugstr_w(lpFileName));
676 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
677 return GetLastError();
679 if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
681 goto fail;
684 pOwner = MyMalloc(dwSize);
685 if (pOwner == NULL)
687 CloseHandle(hToken);
688 return ERROR_NOT_ENOUGH_MEMORY;
691 if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
693 goto fail;
696 if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
698 goto fail;
701 if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
703 goto fail;
706 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
708 goto fail;
711 MyFree(pOwner);
712 CloseHandle(hToken);
714 return ERROR_SUCCESS;
716 fail:;
717 dwError = GetLastError();
719 MyFree(pOwner);
721 if (hToken != NULL)
722 CloseHandle(hToken);
724 return dwError;
728 /**************************************************************************
729 * RetreiveFileSecurity [SETUPAPI.@]
731 * Retrieve the security descriptor that is associated with the given file.
733 * PARAMS
734 * lpFileName [I] Name of the file
736 * RETURNS
737 * Success: ERROR_SUCCESS
738 * Failure: other
740 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
741 PSECURITY_DESCRIPTOR *pSecurityDescriptor)
743 PSECURITY_DESCRIPTOR SecDesc;
744 DWORD dwSize = 0x100;
745 DWORD dwError;
747 SecDesc = MyMalloc(dwSize);
748 if (SecDesc == NULL)
749 return ERROR_NOT_ENOUGH_MEMORY;
751 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
752 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
753 SecDesc, dwSize, &dwSize))
755 *pSecurityDescriptor = SecDesc;
756 return ERROR_SUCCESS;
759 dwError = GetLastError();
760 if (dwError != ERROR_INSUFFICIENT_BUFFER)
762 MyFree(SecDesc);
763 return dwError;
766 SecDesc = MyRealloc(SecDesc, dwSize);
767 if (SecDesc == NULL)
768 return ERROR_NOT_ENOUGH_MEMORY;
770 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
771 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
772 SecDesc, dwSize, &dwSize))
774 *pSecurityDescriptor = SecDesc;
775 return ERROR_SUCCESS;
778 dwError = GetLastError();
779 MyFree(SecDesc);
781 return dwError;
785 static DWORD global_flags = 0; /* FIXME: what should be in here? */
787 /***********************************************************************
788 * pSetupGetGlobalFlags (SETUPAPI.@)
790 DWORD WINAPI pSetupGetGlobalFlags(void)
792 FIXME( "stub\n" );
793 return global_flags;
797 /***********************************************************************
798 * pSetupSetGlobalFlags (SETUPAPI.@)
800 void WINAPI pSetupSetGlobalFlags( DWORD flags )
802 global_flags = flags;
805 /***********************************************************************
806 * CMP_WaitNoPendingInstallEvents (SETUPAPI.@)
808 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
810 static BOOL warned = FALSE;
812 if (!warned)
814 FIXME("%d\n", dwTimeout);
815 warned = TRUE;
817 return WAIT_OBJECT_0;
820 /***********************************************************************
821 * AssertFail (SETUPAPI.@)
823 * Shows an assert fail error messagebox
825 * PARAMS
826 * lpFile [I] file where assert failed
827 * uLine [I] line number in file
828 * lpMessage [I] assert message
831 void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage)
833 FIXME("%s %u %s\n", lpFile, uLine, lpMessage);
836 /***********************************************************************
837 * SetupCopyOEMInfA (SETUPAPI.@)
839 BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location,
840 DWORD media_type, DWORD style, PSTR dest,
841 DWORD buffer_size, PDWORD required_size, PSTR *component )
843 BOOL ret = FALSE;
844 LPWSTR destW = NULL, sourceW = NULL, locationW = NULL;
845 DWORD size;
847 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_a(source), debugstr_a(location),
848 media_type, style, dest, buffer_size, required_size, component);
850 if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE;
851 if (source && !(sourceW = strdupAtoW( source ))) goto done;
852 if (location && !(locationW = strdupAtoW( location ))) goto done;
854 if (!(ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW,
855 buffer_size, &size, NULL )))
857 if (required_size) *required_size = size;
858 goto done;
861 if (dest)
863 if (buffer_size >= size)
865 WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
866 if (component) *component = strrchr( dest, '\\' ) + 1;
868 else
870 SetLastError( ERROR_INSUFFICIENT_BUFFER );
871 goto done;
875 done:
876 MyFree( destW );
877 HeapFree( GetProcessHeap(), 0, sourceW );
878 HeapFree( GetProcessHeap(), 0, locationW );
879 if (ret) SetLastError(ERROR_SUCCESS);
880 return ret;
883 static int compare_files( HANDLE file1, HANDLE file2 )
885 char buffer1[2048];
886 char buffer2[2048];
887 DWORD size1;
888 DWORD size2;
890 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
891 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
893 int ret;
894 if (size1 != size2)
895 return size1 > size2 ? 1 : -1;
896 if (!size1)
897 return 0;
898 ret = memcmp( buffer1, buffer2, size1 );
899 if (ret)
900 return ret;
903 return 0;
906 /***********************************************************************
907 * SetupCopyOEMInfW (SETUPAPI.@)
909 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
910 DWORD media_type, DWORD style, PWSTR dest,
911 DWORD buffer_size, PDWORD required_size, PWSTR *component )
913 BOOL ret = FALSE;
914 WCHAR target[MAX_PATH], catalog_file[MAX_PATH], *p;
915 static const WCHAR inf[] = { '\\','i','n','f','\\',0 };
916 static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
917 static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
918 DWORD size;
919 HINF hinf;
921 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source), debugstr_w(location),
922 media_type, style, dest, buffer_size, required_size, component);
924 if (!source)
926 SetLastError(ERROR_INVALID_PARAMETER);
927 return FALSE;
930 /* check for a relative path */
931 if (!(*source == '\\' || (*source && source[1] == ':')))
933 SetLastError(ERROR_FILE_NOT_FOUND);
934 return FALSE;
937 if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE;
939 strcatW( target, inf );
940 if ((p = strrchrW( source, '\\' )))
941 strcatW( target, p + 1 );
943 /* does the file exist already? */
944 if ((GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES) &&
945 !(style & SP_COPY_NOOVERWRITE))
947 static const WCHAR oem[] = { 'o','e','m',0 };
948 unsigned int i;
949 LARGE_INTEGER source_file_size;
950 HANDLE source_file;
952 source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
953 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
954 NULL, OPEN_EXISTING, 0, NULL );
955 if (source_file == INVALID_HANDLE_VALUE)
956 return FALSE;
958 if (!GetFileSizeEx( source_file, &source_file_size ))
960 CloseHandle( source_file );
961 return FALSE;
964 p = strrchrW( target, '\\' ) + 1;
965 memcpy( p, oem, sizeof(oem) );
966 p += sizeof(oem)/sizeof(oem[0]) - 1;
968 /* generate OEMnnn.inf ending */
969 for (i = 0; i < OEM_INDEX_LIMIT; i++)
971 static const WCHAR format[] = { '%','u','.','i','n','f',0 };
972 HANDLE dest_file;
973 LARGE_INTEGER dest_file_size;
975 wsprintfW( p, format, i );
976 dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
977 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
978 NULL, OPEN_EXISTING, 0, NULL );
979 /* if we found a file name that doesn't exist then we're done */
980 if (dest_file == INVALID_HANDLE_VALUE)
981 break;
982 /* now check if the same inf file has already been copied to the inf
983 * directory. if so, use that file and don't create a new one */
984 if (!GetFileSizeEx( dest_file, &dest_file_size ) ||
985 (dest_file_size.QuadPart != source_file_size.QuadPart) ||
986 compare_files( source_file, dest_file ))
988 CloseHandle( dest_file );
989 continue;
991 CloseHandle( dest_file );
992 break;
995 CloseHandle( source_file );
996 if (i == OEM_INDEX_LIMIT)
998 SetLastError( ERROR_FILENAME_EXCED_RANGE );
999 return FALSE;
1003 hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL );
1004 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
1006 if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file,
1007 sizeof(catalog_file)/sizeof(catalog_file[0]), NULL ))
1009 WCHAR source_cat[MAX_PATH];
1010 HCATADMIN handle;
1011 HCATINFO cat;
1012 GUID msguid = DRIVER_ACTION_VERIFY;
1014 SetupCloseInfFile( hinf );
1016 strcpyW( source_cat, source );
1017 p = strrchrW( source_cat, '\\' );
1018 if (p) p++;
1019 else p = source_cat;
1020 strcpyW( p, catalog_file );
1022 TRACE("installing catalog file %s\n", debugstr_w( source_cat ));
1024 if (!CryptCATAdminAcquireContext(&handle, &msguid, 0))
1026 ERR("Could not acquire security context\n");
1027 return FALSE;
1030 if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0)))
1032 ERR("Could not add catalog\n");
1033 CryptCATAdminReleaseContext(handle, 0);
1034 return FALSE;
1037 CryptCATAdminReleaseCatalogContext(handle, cat, 0);
1038 CryptCATAdminReleaseContext(handle, 0);
1040 else
1041 SetupCloseInfFile( hinf );
1043 if (!(ret = CopyFileW( source, target, (style & SP_COPY_NOOVERWRITE) != 0 )))
1044 return ret;
1046 if (style & SP_COPY_DELETESOURCE)
1047 DeleteFileW( source );
1049 size = strlenW( target ) + 1;
1050 if (dest)
1052 if (buffer_size >= size)
1054 strcpyW( dest, target );
1056 else
1058 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1059 ret = FALSE;
1063 if (component) *component = p + 1;
1064 if (required_size) *required_size = size;
1065 if (ret) SetLastError(ERROR_SUCCESS);
1067 return ret;
1070 /***********************************************************************
1071 * SetupUninstallOEMInfA (SETUPAPI.@)
1073 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1075 BOOL ret;
1076 WCHAR *inf_fileW = NULL;
1078 TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file), flags, reserved);
1080 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1081 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1082 HeapFree( GetProcessHeap(), 0, inf_fileW );
1083 return ret;
1086 /***********************************************************************
1087 * SetupUninstallOEMInfW (SETUPAPI.@)
1089 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1091 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1092 WCHAR target[MAX_PATH];
1094 TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file), flags, reserved);
1096 if (!inf_file)
1098 SetLastError(ERROR_INVALID_PARAMETER);
1099 return FALSE;
1102 if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE;
1104 strcatW( target, infW );
1105 strcatW( target, inf_file );
1107 if (flags & SUOI_FORCEDELETE)
1108 return DeleteFileW(target);
1110 FIXME("not deleting %s\n", debugstr_w(target));
1112 return TRUE;
1115 /***********************************************************************
1116 * InstallCatalog (SETUPAPI.@)
1118 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1120 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1121 return 0;
1124 /***********************************************************************
1125 * pSetupInstallCatalog (SETUPAPI.@)
1127 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1129 HCATADMIN admin;
1130 HCATINFO cat;
1132 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1134 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1135 return GetLastError();
1137 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1139 DWORD rc = GetLastError();
1140 CryptCATAdminReleaseContext(admin, 0);
1141 return rc;
1143 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1144 CryptCATAdminReleaseContext(admin,0);
1146 if (fullname)
1147 FIXME("not returning full installed catalog path\n");
1149 return NO_ERROR;
1152 static UINT detect_compression_type( LPCWSTR file )
1154 DWORD size;
1155 HANDLE handle;
1156 UINT type = FILE_COMPRESSION_NONE;
1157 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1158 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1159 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1160 BYTE buffer[8];
1162 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1163 if (handle == INVALID_HANDLE_VALUE)
1165 ERR("cannot open file %s\n", debugstr_w(file));
1166 return FILE_COMPRESSION_NONE;
1168 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1170 CloseHandle( handle );
1171 return FILE_COMPRESSION_NONE;
1173 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1174 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1175 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1177 CloseHandle( handle );
1178 return type;
1181 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1183 HANDLE handle;
1185 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1186 if (handle == INVALID_HANDLE_VALUE)
1188 ERR("cannot open file %s\n", debugstr_w(file));
1189 return FALSE;
1191 *size = GetFileSize( handle, NULL );
1192 CloseHandle( handle );
1193 return TRUE;
1196 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1198 DWORD size;
1200 if (!get_file_size( source, &size )) return FALSE;
1201 if (source_size) *source_size = size;
1202 if (target_size) *target_size = size;
1203 return TRUE;
1206 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1208 DWORD size;
1209 BOOL ret = TRUE;
1211 if (source_size)
1213 if (!get_file_size( source, &size )) ret = FALSE;
1214 else *source_size = size;
1216 if (target_size)
1218 INT file;
1219 OFSTRUCT of;
1221 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1223 ERR("cannot open source file for reading\n");
1224 return FALSE;
1226 *target_size = LZSeek( file, 0, 2 );
1227 LZClose( file );
1229 return ret;
1232 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1234 DWORD *size = context;
1235 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1237 switch (notification)
1239 case SPFILENOTIFY_FILEINCABINET:
1241 *size = info->FileSize;
1242 return FILEOP_SKIP;
1244 default: return NO_ERROR;
1248 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1250 DWORD size;
1251 BOOL ret = TRUE;
1253 if (source_size)
1255 if (!get_file_size( source, &size )) ret = FALSE;
1256 else *source_size = size;
1258 if (target_size)
1260 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1262 return ret;
1265 /***********************************************************************
1266 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1268 * See SetupGetFileCompressionInfoExW.
1270 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1271 PDWORD source_size, PDWORD target_size, PUINT type )
1273 BOOL ret;
1274 WCHAR *nameW = NULL, *sourceW = NULL;
1275 DWORD nb_chars = 0;
1276 LPSTR nameA;
1278 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1279 source_size, target_size, type);
1281 if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1283 if (name)
1285 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1286 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1288 MyFree( sourceW );
1289 return FALSE;
1292 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1293 if (ret)
1295 if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1297 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1298 else
1300 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1301 ret = FALSE;
1303 MyFree( nameA );
1306 if (required) *required = nb_chars;
1307 HeapFree( GetProcessHeap(), 0, nameW );
1308 MyFree( sourceW );
1310 return ret;
1313 /***********************************************************************
1314 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1316 * Get compression type and compressed/uncompressed sizes of a given file.
1318 * PARAMS
1319 * source [I] File to examine.
1320 * name [O] Actual filename used.
1321 * len [I] Length in characters of 'name' buffer.
1322 * required [O] Number of characters written to 'name'.
1323 * source_size [O] Size of compressed file.
1324 * target_size [O] Size of uncompressed file.
1325 * type [O] Compression type.
1327 * RETURNS
1328 * Success: TRUE
1329 * Failure: FALSE
1331 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1332 PDWORD source_size, PDWORD target_size, PUINT type )
1334 UINT comp;
1335 BOOL ret = FALSE;
1336 DWORD source_len;
1338 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1339 source_size, target_size, type);
1341 if (!source) return FALSE;
1343 source_len = lstrlenW( source ) + 1;
1344 if (required) *required = source_len;
1345 if (name && len >= source_len)
1347 lstrcpyW( name, source );
1348 ret = TRUE;
1350 else return FALSE;
1352 comp = detect_compression_type( source );
1353 if (type) *type = comp;
1355 switch (comp)
1357 case FILE_COMPRESSION_MSZIP:
1358 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1359 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1360 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1361 default: break;
1363 return ret;
1366 /***********************************************************************
1367 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1369 * See SetupGetFileCompressionInfoW.
1371 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1372 PDWORD target_size, PUINT type )
1374 BOOL ret;
1375 DWORD error, required;
1376 LPSTR actual_name;
1378 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1380 if (!source || !name || !source_size || !target_size || !type)
1381 return ERROR_INVALID_PARAMETER;
1383 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1384 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1386 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1387 source_size, target_size, type );
1388 if (!ret)
1390 error = GetLastError();
1391 MyFree( actual_name );
1392 return error;
1394 *name = actual_name;
1395 return ERROR_SUCCESS;
1398 /***********************************************************************
1399 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1401 * Get compression type and compressed/uncompressed sizes of a given file.
1403 * PARAMS
1404 * source [I] File to examine.
1405 * name [O] Actual filename used.
1406 * source_size [O] Size of compressed file.
1407 * target_size [O] Size of uncompressed file.
1408 * type [O] Compression type.
1410 * RETURNS
1411 * Success: ERROR_SUCCESS
1412 * Failure: Win32 error code.
1414 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1415 PDWORD target_size, PUINT type )
1417 BOOL ret;
1418 DWORD error, required;
1419 LPWSTR actual_name;
1421 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1423 if (!source || !name || !source_size || !target_size || !type)
1424 return ERROR_INVALID_PARAMETER;
1426 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1427 if (!(actual_name = MyMalloc( required * sizeof(WCHAR) )))
1428 return ERROR_NOT_ENOUGH_MEMORY;
1430 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1431 source_size, target_size, type );
1432 if (!ret)
1434 error = GetLastError();
1435 MyFree( actual_name );
1436 return error;
1438 *name = actual_name;
1439 return ERROR_SUCCESS;
1442 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1444 DWORD ret;
1445 LONG error;
1446 INT src, dst;
1447 OFSTRUCT sof, dof;
1449 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1451 ERR("cannot open source file for reading\n");
1452 return ERROR_FILE_NOT_FOUND;
1454 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1456 ERR("cannot open target file for writing\n");
1457 LZClose( src );
1458 return ERROR_FILE_NOT_FOUND;
1460 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1461 else
1463 WARN("failed to decompress file %d\n", error);
1464 ret = ERROR_INVALID_DATA;
1467 LZClose( src );
1468 LZClose( dst );
1469 return ret;
1472 struct callback_context
1474 BOOL has_extracted;
1475 LPCWSTR target;
1478 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1480 struct callback_context *context_info = context;
1481 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1483 switch (notification)
1485 case SPFILENOTIFY_FILEINCABINET:
1487 if (context_info->has_extracted)
1488 return FILEOP_ABORT;
1490 TRACE("Requesting extraction of cabinet file %s\n",
1491 wine_dbgstr_w(info->NameInCabinet));
1492 strcpyW( info->FullTargetName, context_info->target );
1493 context_info->has_extracted = TRUE;
1494 return FILEOP_DOIT;
1496 default: return NO_ERROR;
1500 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1502 struct callback_context context = {0, target};
1503 BOOL ret;
1505 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1507 if (ret) return ERROR_SUCCESS;
1508 else return GetLastError();
1511 /***********************************************************************
1512 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1514 * See SetupDecompressOrCopyFileW.
1516 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1518 DWORD ret = 0;
1519 WCHAR *sourceW = NULL, *targetW = NULL;
1521 if (source && !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1522 if (target && !(targetW = MultiByteToUnicode( target, CP_ACP )))
1524 MyFree( sourceW );
1525 return ERROR_NOT_ENOUGH_MEMORY;
1528 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1530 MyFree( sourceW );
1531 MyFree( targetW );
1533 return ret;
1536 /***********************************************************************
1537 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1539 * Copy a file and decompress it if needed.
1541 * PARAMS
1542 * source [I] File to copy.
1543 * target [I] Filename of the copy.
1544 * type [I] Compression type.
1546 * RETURNS
1547 * Success: ERROR_SUCCESS
1548 * Failure: Win32 error code.
1550 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1552 UINT comp;
1553 DWORD ret = ERROR_INVALID_PARAMETER;
1555 TRACE("(%s, %s, %p)\n", debugstr_w(source), debugstr_w(target), type);
1557 if (!source || !target) return ERROR_INVALID_PARAMETER;
1559 if (!type)
1561 comp = detect_compression_type( source );
1562 TRACE("Detected compression type %u\n", comp);
1564 else
1566 comp = *type;
1567 TRACE("Using specified compression type %u\n", comp);
1570 switch (comp)
1572 case FILE_COMPRESSION_NONE:
1573 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1574 else ret = GetLastError();
1575 break;
1576 case FILE_COMPRESSION_WINLZA:
1577 ret = decompress_file_lz( source, target );
1578 break;
1579 case FILE_COMPRESSION_NTCAB:
1580 case FILE_COMPRESSION_MSZIP:
1581 ret = decompress_file_cab( source, target );
1582 break;
1583 default:
1584 WARN("unknown compression type %d\n", comp);
1585 break;
1588 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1589 return ret;
1592 static BOOL non_interactive_mode;
1594 /***********************************************************************
1595 * SetupGetNonInteractiveMode (SETUPAPI.@)
1597 BOOL WINAPI SetupGetNonInteractiveMode( void )
1599 FIXME("\n");
1600 return non_interactive_mode;
1603 /***********************************************************************
1604 * SetupSetNonInteractiveMode (SETUPAPI.@)
1606 BOOL WINAPI SetupSetNonInteractiveMode( BOOL flag )
1608 BOOL ret = non_interactive_mode;
1610 FIXME("%d\n", flag);
1612 non_interactive_mode = flag;
1613 return ret;
1616 /***********************************************************************
1617 * SetupCloseLog(SETUPAPI.@)
1619 void WINAPI SetupCloseLog(void)
1621 EnterCriticalSection(&setupapi_cs);
1623 CloseHandle(setupact);
1624 setupact = INVALID_HANDLE_VALUE;
1626 CloseHandle(setuperr);
1627 setuperr = INVALID_HANDLE_VALUE;
1629 LeaveCriticalSection(&setupapi_cs);
1632 /***********************************************************************
1633 * SetupOpenLog(SETUPAPI.@)
1635 BOOL WINAPI SetupOpenLog(BOOL reserved)
1637 WCHAR path[MAX_PATH];
1639 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
1640 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
1642 EnterCriticalSection(&setupapi_cs);
1644 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
1646 LeaveCriticalSection(&setupapi_cs);
1647 return TRUE;
1650 GetWindowsDirectoryW(path, MAX_PATH);
1651 lstrcatW(path, setupactlog);
1653 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1654 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1655 if (setupact == INVALID_HANDLE_VALUE)
1657 LeaveCriticalSection(&setupapi_cs);
1658 return FALSE;
1661 SetFilePointer(setupact, 0, NULL, FILE_END);
1663 GetWindowsDirectoryW(path, MAX_PATH);
1664 lstrcatW(path, setuperrlog);
1666 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1667 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1668 if (setuperr == INVALID_HANDLE_VALUE)
1670 CloseHandle(setupact);
1671 setupact = INVALID_HANDLE_VALUE;
1672 LeaveCriticalSection(&setupapi_cs);
1673 return FALSE;
1676 SetFilePointer(setuperr, 0, NULL, FILE_END);
1678 LeaveCriticalSection(&setupapi_cs);
1680 return TRUE;
1683 /***********************************************************************
1684 * SetupLogErrorA(SETUPAPI.@)
1686 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
1688 static const char null[] = "(null)";
1689 BOOL ret;
1690 DWORD written;
1691 DWORD len;
1693 EnterCriticalSection(&setupapi_cs);
1695 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
1697 SetLastError(ERROR_FILE_INVALID);
1698 ret = FALSE;
1699 goto done;
1702 if (message == NULL)
1703 message = null;
1705 len = lstrlenA(message);
1707 ret = WriteFile(setupact, message, len, &written, NULL);
1708 if (!ret)
1709 goto done;
1711 if (severity >= LogSevMaximum)
1713 ret = FALSE;
1714 goto done;
1717 if (severity > LogSevInformation)
1718 ret = WriteFile(setuperr, message, len, &written, NULL);
1720 done:
1721 LeaveCriticalSection(&setupapi_cs);
1722 return ret;
1725 /***********************************************************************
1726 * SetupLogErrorW(SETUPAPI.@)
1728 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
1730 LPSTR msg = NULL;
1731 DWORD len;
1732 BOOL ret;
1734 if (message)
1736 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
1737 msg = HeapAlloc(GetProcessHeap(), 0, len);
1738 if (msg == NULL)
1740 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1741 return FALSE;
1743 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
1746 /* This is the normal way to proceed. The log files are ASCII files
1747 * and W is to be converted.
1749 ret = SetupLogErrorA(msg, severity);
1751 HeapFree(GetProcessHeap(), 0, msg);
1752 return ret;
1755 /***********************************************************************
1756 * CM_Get_Version (SETUPAPI.@)
1758 WORD WINAPI CM_Get_Version(void)
1760 TRACE("()\n");
1761 return 0x0400;