Release 6.15.
[wine.git] / dlls / setupapi / misc.c
blob26e5359804cd1affcea76bce734cdbd244b71aca
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"
34 #include "shlwapi.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 lstrcpyW(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 ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL );
856 if (required_size) *required_size = size;
858 if (dest)
860 if (buffer_size >= size)
862 WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
863 if (component) *component = strrchr( dest, '\\' ) + 1;
865 else
866 SetLastError( ERROR_INSUFFICIENT_BUFFER );
869 done:
870 MyFree( destW );
871 HeapFree( GetProcessHeap(), 0, sourceW );
872 HeapFree( GetProcessHeap(), 0, locationW );
873 if (ret) SetLastError(ERROR_SUCCESS);
874 return ret;
877 static int compare_files( HANDLE file1, HANDLE file2 )
879 char buffer1[2048];
880 char buffer2[2048];
881 DWORD size1;
882 DWORD size2;
884 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
885 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
887 int ret;
888 if (size1 != size2)
889 return size1 > size2 ? 1 : -1;
890 if (!size1)
891 return 0;
892 ret = memcmp( buffer1, buffer2, size1 );
893 if (ret)
894 return ret;
897 return 0;
900 static BOOL find_existing_inf(const WCHAR *source, WCHAR *target)
902 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
903 static const WCHAR wildcardW[] = {'*',0};
905 LARGE_INTEGER source_file_size, dest_file_size;
906 HANDLE source_file, dest_file;
907 WIN32_FIND_DATAW find_data;
908 HANDLE find_handle;
910 source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
911 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
912 NULL, OPEN_EXISTING, 0, NULL );
913 if (source_file == INVALID_HANDLE_VALUE)
914 return FALSE;
916 if (!GetFileSizeEx( source_file, &source_file_size ))
918 CloseHandle( source_file );
919 return FALSE;
922 GetWindowsDirectoryW( target, MAX_PATH );
923 lstrcatW( target, infW );
924 lstrcatW( target, wildcardW );
925 if ((find_handle = FindFirstFileW( target, &find_data )) != INVALID_HANDLE_VALUE)
927 do {
928 GetWindowsDirectoryW( target, MAX_PATH );
929 lstrcatW( target, infW );
930 lstrcatW( target, find_data.cFileName );
931 dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
932 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
933 NULL, OPEN_EXISTING, 0, NULL );
934 if (dest_file == INVALID_HANDLE_VALUE)
935 continue;
937 SetFilePointer( source_file, 0, NULL, FILE_BEGIN );
939 if (GetFileSizeEx( dest_file, &dest_file_size )
940 && dest_file_size.QuadPart == source_file_size.QuadPart
941 && !compare_files( source_file, dest_file ))
943 CloseHandle( dest_file );
944 CloseHandle( source_file );
945 FindClose( find_handle );
946 return TRUE;
948 CloseHandle( dest_file );
949 } while (FindNextFileW( find_handle, &find_data ));
951 FindClose( find_handle );
954 CloseHandle( source_file );
955 return FALSE;
958 /***********************************************************************
959 * SetupCopyOEMInfW (SETUPAPI.@)
961 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
962 DWORD media_type, DWORD style, PWSTR dest,
963 DWORD buffer_size, DWORD *required_size, WCHAR **filepart )
965 BOOL ret = FALSE;
966 WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p;
967 static const WCHAR inf[] = { '\\','i','n','f','\\',0 };
968 static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
969 static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
970 FILE *pnf_file;
971 unsigned int i;
972 DWORD size;
973 HINF hinf;
975 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source), debugstr_w(location),
976 media_type, style, dest, buffer_size, required_size, filepart);
978 if (!source)
980 SetLastError(ERROR_INVALID_PARAMETER);
981 return FALSE;
984 /* check for a relative path */
985 if (!(*source == '\\' || (*source && source[1] == ':')))
987 SetLastError(ERROR_FILE_NOT_FOUND);
988 return FALSE;
991 if (find_existing_inf( source, target ))
993 TRACE("Found existing INF %s.\n", debugstr_w(target));
994 if (style & SP_COPY_NOOVERWRITE)
996 SetLastError( ERROR_FILE_EXISTS );
997 ret = FALSE;
999 else
1000 ret = TRUE;
1001 goto done;
1004 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1005 lstrcatW( target, inf );
1006 lstrcatW( target, wcsrchr( source, '\\' ) + 1 );
1007 if (GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES)
1009 for (i = 0; i < OEM_INDEX_LIMIT; i++)
1011 static const WCHAR formatW[] = {'o','e','m','%','u','.','i','n','f',0};
1013 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1014 lstrcatW( target, inf );
1015 swprintf( target + lstrlenW(target), ARRAY_SIZE(target) - lstrlenW(target), formatW, i );
1017 if (GetFileAttributesW( target ) == INVALID_FILE_ATTRIBUTES)
1018 break;
1020 if (i == OEM_INDEX_LIMIT)
1022 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1023 return FALSE;
1027 hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL );
1028 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
1030 if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file,
1031 ARRAY_SIZE( catalog_file ), NULL ))
1033 WCHAR source_cat[MAX_PATH];
1034 HCATADMIN handle;
1035 HCATINFO cat;
1036 GUID msguid = DRIVER_ACTION_VERIFY;
1038 SetupCloseInfFile( hinf );
1040 lstrcpyW( source_cat, source );
1041 p = wcsrchr( source_cat, '\\' );
1042 if (p) p++;
1043 else p = source_cat;
1044 lstrcpyW( p, catalog_file );
1046 TRACE("installing catalog file %s\n", debugstr_w( source_cat ));
1048 if (!CryptCATAdminAcquireContext(&handle, &msguid, 0))
1050 ERR("Could not acquire security context\n");
1051 return FALSE;
1054 if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0)))
1056 ERR("Could not add catalog\n");
1057 CryptCATAdminReleaseContext(handle, 0);
1058 return FALSE;
1061 CryptCATAdminReleaseCatalogContext(handle, cat, 0);
1062 CryptCATAdminReleaseContext(handle, 0);
1064 else
1065 SetupCloseInfFile( hinf );
1067 if (!(ret = CopyFileW( source, target, TRUE )))
1068 return ret;
1070 done:
1071 if (style & SP_COPY_DELETESOURCE)
1072 DeleteFileW( source );
1074 if (ret)
1076 wcscpy(pnf_path, target);
1077 PathRemoveExtensionW(pnf_path);
1078 PathAddExtensionW(pnf_path, L".pnf");
1079 if ((pnf_file = _wfopen(pnf_path, L"w")))
1081 fputws(PNF_HEADER, pnf_file);
1082 fputws(source, pnf_file);
1083 fclose(pnf_file);
1087 size = lstrlenW( target ) + 1;
1088 if (dest)
1090 if (buffer_size >= size)
1092 lstrcpyW( dest, target );
1093 if (filepart) *filepart = wcsrchr( dest, '\\' ) + 1;
1095 else
1097 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1098 ret = FALSE;
1102 if (required_size) *required_size = size;
1103 if (ret) SetLastError(ERROR_SUCCESS);
1105 return ret;
1108 /***********************************************************************
1109 * SetupUninstallOEMInfA (SETUPAPI.@)
1111 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1113 BOOL ret;
1114 WCHAR *inf_fileW = NULL;
1116 TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file), flags, reserved);
1118 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1119 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1120 HeapFree( GetProcessHeap(), 0, inf_fileW );
1121 return ret;
1124 /***********************************************************************
1125 * SetupUninstallOEMInfW (SETUPAPI.@)
1127 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1129 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1130 WCHAR target[MAX_PATH];
1132 TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file), flags, reserved);
1134 if (!inf_file)
1136 SetLastError(ERROR_INVALID_PARAMETER);
1137 return FALSE;
1140 if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) return FALSE;
1142 lstrcatW( target, infW );
1143 lstrcatW( target, inf_file );
1145 if (flags & SUOI_FORCEDELETE)
1146 return DeleteFileW(target);
1148 FIXME("not deleting %s\n", debugstr_w(target));
1150 return TRUE;
1153 /***********************************************************************
1154 * InstallCatalog (SETUPAPI.@)
1156 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1158 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1159 return 0;
1162 /***********************************************************************
1163 * pSetupInstallCatalog (SETUPAPI.@)
1165 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1167 HCATADMIN admin;
1168 HCATINFO cat;
1170 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1172 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1173 return GetLastError();
1175 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1177 DWORD rc = GetLastError();
1178 CryptCATAdminReleaseContext(admin, 0);
1179 return rc;
1181 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1182 CryptCATAdminReleaseContext(admin,0);
1184 if (fullname)
1185 FIXME("not returning full installed catalog path\n");
1187 return NO_ERROR;
1190 static UINT detect_compression_type( LPCWSTR file )
1192 DWORD size;
1193 HANDLE handle;
1194 UINT type = FILE_COMPRESSION_NONE;
1195 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1196 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1197 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1198 BYTE buffer[8];
1200 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1201 if (handle == INVALID_HANDLE_VALUE)
1203 ERR("cannot open file %s\n", debugstr_w(file));
1204 return FILE_COMPRESSION_NONE;
1206 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1208 CloseHandle( handle );
1209 return FILE_COMPRESSION_NONE;
1211 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1212 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1213 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1215 CloseHandle( handle );
1216 return type;
1219 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1221 HANDLE handle;
1223 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1224 if (handle == INVALID_HANDLE_VALUE)
1226 ERR("cannot open file %s\n", debugstr_w(file));
1227 return FALSE;
1229 *size = GetFileSize( handle, NULL );
1230 CloseHandle( handle );
1231 return TRUE;
1234 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1236 DWORD size;
1238 if (!get_file_size( source, &size )) return FALSE;
1239 if (source_size) *source_size = size;
1240 if (target_size) *target_size = size;
1241 return TRUE;
1244 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1246 DWORD size;
1247 BOOL ret = TRUE;
1249 if (source_size)
1251 if (!get_file_size( source, &size )) ret = FALSE;
1252 else *source_size = size;
1254 if (target_size)
1256 INT file;
1257 OFSTRUCT of;
1259 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1261 ERR("cannot open source file for reading\n");
1262 return FALSE;
1264 *target_size = LZSeek( file, 0, 2 );
1265 LZClose( file );
1267 return ret;
1270 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1272 DWORD *size = context;
1273 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1275 switch (notification)
1277 case SPFILENOTIFY_FILEINCABINET:
1279 *size = info->FileSize;
1280 return FILEOP_SKIP;
1282 default: return NO_ERROR;
1286 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1288 DWORD size;
1289 BOOL ret = TRUE;
1291 if (source_size)
1293 if (!get_file_size( source, &size )) ret = FALSE;
1294 else *source_size = size;
1296 if (target_size)
1298 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1300 return ret;
1303 /***********************************************************************
1304 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1306 * See SetupGetFileCompressionInfoExW.
1308 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1309 PDWORD source_size, PDWORD target_size, PUINT type )
1311 BOOL ret;
1312 WCHAR *nameW = NULL, *sourceW = NULL;
1313 DWORD nb_chars = 0;
1314 LPSTR nameA;
1316 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1317 source_size, target_size, type);
1319 if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1321 if (name)
1323 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1324 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1326 MyFree( sourceW );
1327 return FALSE;
1330 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1331 if (ret)
1333 if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1335 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1336 else
1338 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1339 ret = FALSE;
1341 MyFree( nameA );
1344 if (required) *required = nb_chars;
1345 HeapFree( GetProcessHeap(), 0, nameW );
1346 MyFree( sourceW );
1348 return ret;
1351 /***********************************************************************
1352 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1354 * Get compression type and compressed/uncompressed sizes of a given file.
1356 * PARAMS
1357 * source [I] File to examine.
1358 * name [O] Actual filename used.
1359 * len [I] Length in characters of 'name' buffer.
1360 * required [O] Number of characters written to 'name'.
1361 * source_size [O] Size of compressed file.
1362 * target_size [O] Size of uncompressed file.
1363 * type [O] Compression type.
1365 * RETURNS
1366 * Success: TRUE
1367 * Failure: FALSE
1369 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1370 PDWORD source_size, PDWORD target_size, PUINT type )
1372 UINT comp;
1373 BOOL ret = FALSE;
1374 DWORD source_len;
1376 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1377 source_size, target_size, type);
1379 if (!source) return FALSE;
1381 source_len = lstrlenW( source ) + 1;
1382 if (required) *required = source_len;
1383 if (name && len >= source_len)
1385 lstrcpyW( name, source );
1386 ret = TRUE;
1388 else return FALSE;
1390 comp = detect_compression_type( source );
1391 if (type) *type = comp;
1393 switch (comp)
1395 case FILE_COMPRESSION_MSZIP:
1396 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1397 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1398 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1399 default: break;
1401 return ret;
1404 /***********************************************************************
1405 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1407 * See SetupGetFileCompressionInfoW.
1409 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1410 PDWORD target_size, PUINT type )
1412 BOOL ret;
1413 DWORD error, required;
1414 LPSTR actual_name;
1416 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1418 if (!source || !name || !source_size || !target_size || !type)
1419 return ERROR_INVALID_PARAMETER;
1421 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1422 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1424 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1425 source_size, target_size, type );
1426 if (!ret)
1428 error = GetLastError();
1429 MyFree( actual_name );
1430 return error;
1432 *name = actual_name;
1433 return ERROR_SUCCESS;
1436 /***********************************************************************
1437 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1439 * Get compression type and compressed/uncompressed sizes of a given file.
1441 * PARAMS
1442 * source [I] File to examine.
1443 * name [O] Actual filename used.
1444 * source_size [O] Size of compressed file.
1445 * target_size [O] Size of uncompressed file.
1446 * type [O] Compression type.
1448 * RETURNS
1449 * Success: ERROR_SUCCESS
1450 * Failure: Win32 error code.
1452 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1453 PDWORD target_size, PUINT type )
1455 BOOL ret;
1456 DWORD error, required;
1457 LPWSTR actual_name;
1459 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1461 if (!source || !name || !source_size || !target_size || !type)
1462 return ERROR_INVALID_PARAMETER;
1464 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1465 if (!(actual_name = MyMalloc( required * sizeof(WCHAR) )))
1466 return ERROR_NOT_ENOUGH_MEMORY;
1468 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1469 source_size, target_size, type );
1470 if (!ret)
1472 error = GetLastError();
1473 MyFree( actual_name );
1474 return error;
1476 *name = actual_name;
1477 return ERROR_SUCCESS;
1480 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1482 DWORD ret;
1483 LONG error;
1484 INT src, dst;
1485 OFSTRUCT sof, dof;
1487 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1489 ERR("cannot open source file for reading\n");
1490 return ERROR_FILE_NOT_FOUND;
1492 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1494 ERR("cannot open target file for writing\n");
1495 LZClose( src );
1496 return ERROR_FILE_NOT_FOUND;
1498 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1499 else
1501 WARN("failed to decompress file %d\n", error);
1502 ret = ERROR_INVALID_DATA;
1505 LZClose( src );
1506 LZClose( dst );
1507 return ret;
1510 struct callback_context
1512 BOOL has_extracted;
1513 LPCWSTR target;
1516 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1518 struct callback_context *context_info = context;
1519 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1521 switch (notification)
1523 case SPFILENOTIFY_FILEINCABINET:
1525 if (context_info->has_extracted)
1526 return FILEOP_ABORT;
1528 TRACE("Requesting extraction of cabinet file %s\n",
1529 wine_dbgstr_w(info->NameInCabinet));
1530 lstrcpyW( info->FullTargetName, context_info->target );
1531 context_info->has_extracted = TRUE;
1532 return FILEOP_DOIT;
1534 default: return NO_ERROR;
1538 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1540 struct callback_context context = {0, target};
1541 BOOL ret;
1543 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1545 if (ret) return ERROR_SUCCESS;
1546 else return GetLastError();
1549 /***********************************************************************
1550 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1552 * See SetupDecompressOrCopyFileW.
1554 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1556 DWORD ret = 0;
1557 WCHAR *sourceW = NULL, *targetW = NULL;
1559 if (source && !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1560 if (target && !(targetW = MultiByteToUnicode( target, CP_ACP )))
1562 MyFree( sourceW );
1563 return ERROR_NOT_ENOUGH_MEMORY;
1566 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1568 MyFree( sourceW );
1569 MyFree( targetW );
1571 return ret;
1574 /***********************************************************************
1575 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1577 * Copy a file and decompress it if needed.
1579 * PARAMS
1580 * source [I] File to copy.
1581 * target [I] Filename of the copy.
1582 * type [I] Compression type.
1584 * RETURNS
1585 * Success: ERROR_SUCCESS
1586 * Failure: Win32 error code.
1588 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1590 UINT comp;
1591 DWORD ret = ERROR_INVALID_PARAMETER;
1593 TRACE("(%s, %s, %p)\n", debugstr_w(source), debugstr_w(target), type);
1595 if (!source || !target) return ERROR_INVALID_PARAMETER;
1597 if (!type)
1599 comp = detect_compression_type( source );
1600 TRACE("Detected compression type %u\n", comp);
1602 else
1604 comp = *type;
1605 TRACE("Using specified compression type %u\n", comp);
1608 switch (comp)
1610 case FILE_COMPRESSION_NONE:
1611 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1612 else ret = GetLastError();
1613 break;
1614 case FILE_COMPRESSION_WINLZA:
1615 ret = decompress_file_lz( source, target );
1616 break;
1617 case FILE_COMPRESSION_NTCAB:
1618 case FILE_COMPRESSION_MSZIP:
1619 ret = decompress_file_cab( source, target );
1620 break;
1621 default:
1622 WARN("unknown compression type %d\n", comp);
1623 break;
1626 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1627 return ret;
1630 static BOOL non_interactive_mode;
1632 /***********************************************************************
1633 * SetupGetNonInteractiveMode (SETUPAPI.@)
1635 BOOL WINAPI SetupGetNonInteractiveMode( void )
1637 FIXME("\n");
1638 return non_interactive_mode;
1641 /***********************************************************************
1642 * SetupSetNonInteractiveMode (SETUPAPI.@)
1644 BOOL WINAPI SetupSetNonInteractiveMode( BOOL flag )
1646 BOOL ret = non_interactive_mode;
1648 FIXME("%d\n", flag);
1650 non_interactive_mode = flag;
1651 return ret;
1654 /***********************************************************************
1655 * SetupCloseLog(SETUPAPI.@)
1657 void WINAPI SetupCloseLog(void)
1659 EnterCriticalSection(&setupapi_cs);
1661 CloseHandle(setupact);
1662 setupact = INVALID_HANDLE_VALUE;
1664 CloseHandle(setuperr);
1665 setuperr = INVALID_HANDLE_VALUE;
1667 LeaveCriticalSection(&setupapi_cs);
1670 /***********************************************************************
1671 * SetupOpenLog(SETUPAPI.@)
1673 BOOL WINAPI SetupOpenLog(BOOL reserved)
1675 WCHAR path[MAX_PATH];
1677 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
1678 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
1680 EnterCriticalSection(&setupapi_cs);
1682 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
1684 LeaveCriticalSection(&setupapi_cs);
1685 return TRUE;
1688 GetWindowsDirectoryW(path, MAX_PATH);
1689 lstrcatW(path, setupactlog);
1691 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1692 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1693 if (setupact == INVALID_HANDLE_VALUE)
1695 LeaveCriticalSection(&setupapi_cs);
1696 return FALSE;
1699 SetFilePointer(setupact, 0, NULL, FILE_END);
1701 GetWindowsDirectoryW(path, MAX_PATH);
1702 lstrcatW(path, setuperrlog);
1704 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1705 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1706 if (setuperr == INVALID_HANDLE_VALUE)
1708 CloseHandle(setupact);
1709 setupact = INVALID_HANDLE_VALUE;
1710 LeaveCriticalSection(&setupapi_cs);
1711 return FALSE;
1714 SetFilePointer(setuperr, 0, NULL, FILE_END);
1716 LeaveCriticalSection(&setupapi_cs);
1718 return TRUE;
1721 /***********************************************************************
1722 * SetupLogErrorA(SETUPAPI.@)
1724 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
1726 static const char null[] = "(null)";
1727 BOOL ret;
1728 DWORD written;
1729 DWORD len;
1731 EnterCriticalSection(&setupapi_cs);
1733 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
1735 SetLastError(ERROR_FILE_INVALID);
1736 ret = FALSE;
1737 goto done;
1740 if (message == NULL)
1741 message = null;
1743 len = lstrlenA(message);
1745 ret = WriteFile(setupact, message, len, &written, NULL);
1746 if (!ret)
1747 goto done;
1749 if (severity >= LogSevMaximum)
1751 ret = FALSE;
1752 goto done;
1755 if (severity > LogSevInformation)
1756 ret = WriteFile(setuperr, message, len, &written, NULL);
1758 done:
1759 LeaveCriticalSection(&setupapi_cs);
1760 return ret;
1763 /***********************************************************************
1764 * SetupLogErrorW(SETUPAPI.@)
1766 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
1768 LPSTR msg = NULL;
1769 DWORD len;
1770 BOOL ret;
1772 if (message)
1774 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
1775 msg = HeapAlloc(GetProcessHeap(), 0, len);
1776 if (msg == NULL)
1778 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1779 return FALSE;
1781 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
1784 /* This is the normal way to proceed. The log files are ASCII files
1785 * and W is to be converted.
1787 ret = SetupLogErrorA(msg, severity);
1789 HeapFree(GetProcessHeap(), 0, msg);
1790 return ret;
1793 /***********************************************************************
1794 * CM_Get_Version (SETUPAPI.@)
1796 WORD WINAPI CM_Get_Version(void)
1798 TRACE("()\n");
1799 return 0x0400;