winex11.drv: Ignore .dwAspect in FORMATETC during XDnD.
[wine.git] / dlls / setupapi / misc.c
blob3b5d62b682cb2969bfe3d80d860c6564a0377d15
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/debug.h"
37 #include "setupapi_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
41 /* arbitrary limit not related to what native actually uses */
42 #define OEM_INDEX_LIMIT 999
44 /* Handles and critical sections for the SetupLog API */
45 static HANDLE setupact = INVALID_HANDLE_VALUE;
46 static HANDLE setuperr = INVALID_HANDLE_VALUE;
47 static CRITICAL_SECTION setupapi_cs;
48 static CRITICAL_SECTION_DEBUG critsect_debug =
50 0, 0, &setupapi_cs,
51 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
52 0, 0, { (DWORD_PTR)(__FILE__ ": setupapi_cs") }
54 static CRITICAL_SECTION setupapi_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
56 /**************************************************************************
57 * MyFree [SETUPAPI.@]
59 * Frees an allocated memory block from the process heap.
61 * PARAMS
62 * lpMem [I] pointer to memory block which will be freed
64 * RETURNS
65 * None
67 VOID WINAPI MyFree(LPVOID lpMem)
69 HeapFree(GetProcessHeap(), 0, lpMem);
73 /**************************************************************************
74 * MyMalloc [SETUPAPI.@]
76 * Allocates memory block from the process heap.
78 * PARAMS
79 * dwSize [I] size of the allocated memory block
81 * RETURNS
82 * Success: pointer to allocated memory block
83 * Failure: NULL
85 LPVOID WINAPI MyMalloc(DWORD dwSize)
87 return HeapAlloc(GetProcessHeap(), 0, dwSize);
91 /**************************************************************************
92 * MyRealloc [SETUPAPI.@]
94 * Changes the size of an allocated memory block or allocates a memory
95 * block from the process heap.
97 * PARAMS
98 * lpSrc [I] pointer to memory block which will be resized
99 * dwSize [I] new size of the memory block
101 * RETURNS
102 * Success: pointer to the resized memory block
103 * Failure: NULL
105 * NOTES
106 * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
107 * block like MyMalloc.
109 LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
111 if (lpSrc == NULL)
112 return HeapAlloc(GetProcessHeap(), 0, dwSize);
114 return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
118 /**************************************************************************
119 * DuplicateString [SETUPAPI.@]
121 * Duplicates a unicode string.
123 * PARAMS
124 * lpSrc [I] pointer to the unicode string that will be duplicated
126 * RETURNS
127 * Success: pointer to the duplicated unicode string
128 * Failure: NULL
130 * NOTES
131 * Call MyFree() to release the duplicated string.
133 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
135 LPWSTR lpDst;
137 lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
138 if (lpDst == NULL)
139 return NULL;
141 lstrcpyW(lpDst, lpSrc);
143 return lpDst;
147 /**************************************************************************
148 * QueryRegistryValue [SETUPAPI.@]
150 * Retrieves value data from the registry and allocates memory for the
151 * value data.
153 * PARAMS
154 * hKey [I] Handle of the key to query
155 * lpValueName [I] Name of value under hkey to query
156 * lpData [O] Destination for the values contents,
157 * lpType [O] Destination for the value type
158 * lpcbData [O] Destination for the size of data
160 * RETURNS
161 * Success: ERROR_SUCCESS
162 * Failure: Otherwise
164 * NOTES
165 * Use MyFree to release the lpData buffer.
167 LONG WINAPI QueryRegistryValue(HKEY hKey,
168 LPCWSTR lpValueName,
169 LPBYTE *lpData,
170 LPDWORD lpType,
171 LPDWORD lpcbData)
173 LONG lError;
175 TRACE("%p %s %p %p %p\n",
176 hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
178 /* Get required buffer size */
179 *lpcbData = 0;
180 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
181 if (lError != ERROR_SUCCESS)
182 return lError;
184 /* Allocate buffer */
185 *lpData = MyMalloc(*lpcbData);
186 if (*lpData == NULL)
187 return ERROR_NOT_ENOUGH_MEMORY;
189 /* Query registry value */
190 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
191 if (lError != ERROR_SUCCESS)
192 MyFree(*lpData);
194 return lError;
198 /**************************************************************************
199 * IsUserAdmin [SETUPAPI.@]
201 * Checks whether the current user is a member of the Administrators group.
203 * PARAMS
204 * None
206 * RETURNS
207 * Success: TRUE
208 * Failure: FALSE
210 BOOL WINAPI IsUserAdmin(VOID)
212 TRACE("\n");
213 return IsUserAnAdmin();
217 /**************************************************************************
218 * MultiByteToUnicode [SETUPAPI.@]
220 * Converts a multi-byte string to a Unicode string.
222 * PARAMS
223 * lpMultiByteStr [I] Multi-byte string to be converted
224 * uCodePage [I] Code page
226 * RETURNS
227 * Success: pointer to the converted Unicode string
228 * Failure: NULL
230 * NOTE
231 * Use MyFree to release the returned Unicode string.
233 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
235 LPWSTR lpUnicodeStr;
236 int nLength;
238 nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
239 -1, NULL, 0);
240 if (nLength == 0)
241 return NULL;
243 lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
244 if (lpUnicodeStr == NULL)
245 return NULL;
247 if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
248 nLength, lpUnicodeStr, nLength))
250 MyFree(lpUnicodeStr);
251 return NULL;
254 return lpUnicodeStr;
258 /**************************************************************************
259 * UnicodeToMultiByte [SETUPAPI.@]
261 * Converts a Unicode string to a multi-byte string.
263 * PARAMS
264 * lpUnicodeStr [I] Unicode string to be converted
265 * uCodePage [I] Code page
267 * RETURNS
268 * Success: pointer to the converted multi-byte string
269 * Failure: NULL
271 * NOTE
272 * Use MyFree to release the returned multi-byte string.
274 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
276 LPSTR lpMultiByteStr;
277 int nLength;
279 nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
280 NULL, 0, NULL, NULL);
281 if (nLength == 0)
282 return NULL;
284 lpMultiByteStr = MyMalloc(nLength);
285 if (lpMultiByteStr == NULL)
286 return NULL;
288 if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
289 lpMultiByteStr, nLength, NULL, NULL))
291 MyFree(lpMultiByteStr);
292 return NULL;
295 return lpMultiByteStr;
299 /**************************************************************************
300 * DoesUserHavePrivilege [SETUPAPI.@]
302 * Check whether the current user has got a given privilege.
304 * PARAMS
305 * lpPrivilegeName [I] Name of the privilege to be checked
307 * RETURNS
308 * Success: TRUE
309 * Failure: FALSE
311 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
313 HANDLE hToken;
314 DWORD dwSize;
315 PTOKEN_PRIVILEGES lpPrivileges;
316 LUID PrivilegeLuid;
317 DWORD i;
318 BOOL bResult = FALSE;
320 TRACE("%s\n", debugstr_w(lpPrivilegeName));
322 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
323 return FALSE;
325 if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
327 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
329 CloseHandle(hToken);
330 return FALSE;
334 lpPrivileges = MyMalloc(dwSize);
335 if (lpPrivileges == NULL)
337 CloseHandle(hToken);
338 return FALSE;
341 if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
343 MyFree(lpPrivileges);
344 CloseHandle(hToken);
345 return FALSE;
348 CloseHandle(hToken);
350 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
352 MyFree(lpPrivileges);
353 return FALSE;
356 for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
358 if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
359 lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
361 bResult = TRUE;
365 MyFree(lpPrivileges);
367 return bResult;
371 /**************************************************************************
372 * EnablePrivilege [SETUPAPI.@]
374 * Enables or disables one of the current users privileges.
376 * PARAMS
377 * lpPrivilegeName [I] Name of the privilege to be changed
378 * bEnable [I] TRUE: Enables the privilege
379 * FALSE: Disables the privilege
381 * RETURNS
382 * Success: TRUE
383 * Failure: FALSE
385 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
387 TOKEN_PRIVILEGES Privileges;
388 HANDLE hToken;
389 BOOL bResult;
391 TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
393 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
394 return FALSE;
396 Privileges.PrivilegeCount = 1;
397 Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
399 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
400 &Privileges.Privileges[0].Luid))
402 CloseHandle(hToken);
403 return FALSE;
406 bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
408 CloseHandle(hToken);
410 return bResult;
414 /**************************************************************************
415 * DelayedMove [SETUPAPI.@]
417 * Moves a file upon the next reboot.
419 * PARAMS
420 * lpExistingFileName [I] Current file name
421 * lpNewFileName [I] New file name
423 * RETURNS
424 * Success: TRUE
425 * Failure: FALSE
427 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
429 return MoveFileExW(lpExistingFileName, lpNewFileName,
430 MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
434 /**************************************************************************
435 * FileExists [SETUPAPI.@]
437 * Checks whether a file exists.
439 * PARAMS
440 * lpFileName [I] Name of the file to check
441 * lpNewFileName [O] Optional information about the existing file
443 * RETURNS
444 * Success: TRUE
445 * Failure: FALSE
447 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
449 WIN32_FIND_DATAW FindData;
450 HANDLE hFind;
451 UINT uErrorMode;
452 DWORD dwError;
454 uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
456 hFind = FindFirstFileW(lpFileName, &FindData);
457 if (hFind == INVALID_HANDLE_VALUE)
459 dwError = GetLastError();
460 SetErrorMode(uErrorMode);
461 SetLastError(dwError);
462 return FALSE;
465 FindClose(hFind);
467 if (lpFileFindData)
468 *lpFileFindData = FindData;
470 SetErrorMode(uErrorMode);
472 return TRUE;
476 /**************************************************************************
477 * CaptureStringArg [SETUPAPI.@]
479 * Captures a UNICODE string.
481 * PARAMS
482 * lpSrc [I] UNICODE string to be captured
483 * lpDst [O] Pointer to the captured UNICODE string
485 * RETURNS
486 * Success: ERROR_SUCCESS
487 * Failure: ERROR_INVALID_PARAMETER
489 * NOTE
490 * Call MyFree to release the captured UNICODE string.
492 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
494 if (pDst == NULL)
495 return ERROR_INVALID_PARAMETER;
497 *pDst = DuplicateString(pSrc);
499 return ERROR_SUCCESS;
503 /**************************************************************************
504 * CaptureAndConvertAnsiArg [SETUPAPI.@]
506 * Captures an ANSI string and converts it to a UNICODE string.
508 * PARAMS
509 * lpSrc [I] ANSI string to be captured
510 * lpDst [O] Pointer to the captured UNICODE string
512 * RETURNS
513 * Success: ERROR_SUCCESS
514 * Failure: ERROR_INVALID_PARAMETER
516 * NOTE
517 * Call MyFree to release the captured UNICODE string.
519 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
521 if (pDst == NULL)
522 return ERROR_INVALID_PARAMETER;
524 *pDst = MultiByteToUnicode(pSrc, CP_ACP);
526 return ERROR_SUCCESS;
530 /**************************************************************************
531 * OpenAndMapFileForRead [SETUPAPI.@]
533 * Open and map a file to a buffer.
535 * PARAMS
536 * lpFileName [I] Name of the file to be opened
537 * lpSize [O] Pointer to the file size
538 * lpFile [0] Pointer to the file handle
539 * lpMapping [0] Pointer to the mapping handle
540 * lpBuffer [0] Pointer to the file buffer
542 * RETURNS
543 * Success: ERROR_SUCCESS
544 * Failure: Other
546 * NOTE
547 * Call UnmapAndCloseFile to release the file.
549 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
550 LPDWORD lpSize,
551 LPHANDLE lpFile,
552 LPHANDLE lpMapping,
553 LPVOID *lpBuffer)
555 DWORD dwError;
557 TRACE("%s %p %p %p %p\n",
558 debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
560 *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
561 OPEN_EXISTING, 0, NULL);
562 if (*lpFile == INVALID_HANDLE_VALUE)
563 return GetLastError();
565 *lpSize = GetFileSize(*lpFile, NULL);
566 if (*lpSize == INVALID_FILE_SIZE)
568 dwError = GetLastError();
569 CloseHandle(*lpFile);
570 return dwError;
573 *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
574 *lpSize, NULL);
575 if (*lpMapping == NULL)
577 dwError = GetLastError();
578 CloseHandle(*lpFile);
579 return dwError;
582 *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
583 if (*lpBuffer == NULL)
585 dwError = GetLastError();
586 CloseHandle(*lpMapping);
587 CloseHandle(*lpFile);
588 return dwError;
591 return ERROR_SUCCESS;
595 /**************************************************************************
596 * UnmapAndCloseFile [SETUPAPI.@]
598 * Unmap and close a mapped file.
600 * PARAMS
601 * hFile [I] Handle to the file
602 * hMapping [I] Handle to the file mapping
603 * lpBuffer [I] Pointer to the file buffer
605 * RETURNS
606 * Success: TRUE
607 * Failure: FALSE
609 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
611 TRACE("%p %p %p\n",
612 hFile, hMapping, lpBuffer);
614 if (!UnmapViewOfFile(lpBuffer))
615 return FALSE;
617 if (!CloseHandle(hMapping))
618 return FALSE;
620 if (!CloseHandle(hFile))
621 return FALSE;
623 return TRUE;
627 /**************************************************************************
628 * StampFileSecurity [SETUPAPI.@]
630 * Assign a new security descriptor to the given file.
632 * PARAMS
633 * lpFileName [I] Name of the file
634 * pSecurityDescriptor [I] New security descriptor
636 * RETURNS
637 * Success: ERROR_SUCCESS
638 * Failure: other
640 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
642 TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
644 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
645 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
646 pSecurityDescriptor))
647 return GetLastError();
649 return ERROR_SUCCESS;
653 /**************************************************************************
654 * TakeOwnershipOfFile [SETUPAPI.@]
656 * Takes the ownership of the given file.
658 * PARAMS
659 * lpFileName [I] Name of the file
661 * RETURNS
662 * Success: ERROR_SUCCESS
663 * Failure: other
665 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
667 SECURITY_DESCRIPTOR SecDesc;
668 HANDLE hToken = NULL;
669 PTOKEN_OWNER pOwner = NULL;
670 DWORD dwError;
671 DWORD dwSize;
673 TRACE("%s\n", debugstr_w(lpFileName));
675 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
676 return GetLastError();
678 if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
680 goto fail;
683 pOwner = MyMalloc(dwSize);
684 if (pOwner == NULL)
686 CloseHandle(hToken);
687 return ERROR_NOT_ENOUGH_MEMORY;
690 if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
692 goto fail;
695 if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
697 goto fail;
700 if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
702 goto fail;
705 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
707 goto fail;
710 MyFree(pOwner);
711 CloseHandle(hToken);
713 return ERROR_SUCCESS;
715 fail:;
716 dwError = GetLastError();
718 MyFree(pOwner);
720 if (hToken != NULL)
721 CloseHandle(hToken);
723 return dwError;
727 /**************************************************************************
728 * RetreiveFileSecurity [SETUPAPI.@]
730 * Retrieve the security descriptor that is associated with the given file.
732 * PARAMS
733 * lpFileName [I] Name of the file
735 * RETURNS
736 * Success: ERROR_SUCCESS
737 * Failure: other
739 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
740 PSECURITY_DESCRIPTOR *pSecurityDescriptor)
742 PSECURITY_DESCRIPTOR SecDesc;
743 DWORD dwSize = 0x100;
744 DWORD dwError;
746 SecDesc = MyMalloc(dwSize);
747 if (SecDesc == NULL)
748 return ERROR_NOT_ENOUGH_MEMORY;
750 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
751 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
752 SecDesc, dwSize, &dwSize))
754 *pSecurityDescriptor = SecDesc;
755 return ERROR_SUCCESS;
758 dwError = GetLastError();
759 if (dwError != ERROR_INSUFFICIENT_BUFFER)
761 MyFree(SecDesc);
762 return dwError;
765 SecDesc = MyRealloc(SecDesc, dwSize);
766 if (SecDesc == NULL)
767 return ERROR_NOT_ENOUGH_MEMORY;
769 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
770 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
771 SecDesc, dwSize, &dwSize))
773 *pSecurityDescriptor = SecDesc;
774 return ERROR_SUCCESS;
777 dwError = GetLastError();
778 MyFree(SecDesc);
780 return dwError;
784 static DWORD global_flags = 0; /* FIXME: what should be in here? */
786 /***********************************************************************
787 * pSetupGetGlobalFlags (SETUPAPI.@)
789 DWORD WINAPI pSetupGetGlobalFlags(void)
791 FIXME( "stub\n" );
792 return global_flags;
796 /***********************************************************************
797 * pSetupSetGlobalFlags (SETUPAPI.@)
799 void WINAPI pSetupSetGlobalFlags( DWORD flags )
801 global_flags = flags;
804 /***********************************************************************
805 * CMP_WaitNoPendingInstallEvents (SETUPAPI.@)
807 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
809 static BOOL warned = FALSE;
811 if (!warned)
813 FIXME("%d\n", dwTimeout);
814 warned = TRUE;
816 return WAIT_OBJECT_0;
819 /***********************************************************************
820 * AssertFail (SETUPAPI.@)
822 * Shows an assert fail error messagebox
824 * PARAMS
825 * lpFile [I] file where assert failed
826 * uLine [I] line number in file
827 * lpMessage [I] assert message
830 void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage)
832 FIXME("%s %u %s\n", lpFile, uLine, lpMessage);
835 /***********************************************************************
836 * SetupCopyOEMInfA (SETUPAPI.@)
838 BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location,
839 DWORD media_type, DWORD style, PSTR dest,
840 DWORD buffer_size, PDWORD required_size, PSTR *component )
842 BOOL ret = FALSE;
843 LPWSTR destW = NULL, sourceW = NULL, locationW = NULL;
844 DWORD size;
846 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_a(source), debugstr_a(location),
847 media_type, style, dest, buffer_size, required_size, component);
849 if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE;
850 if (source && !(sourceW = strdupAtoW( source ))) goto done;
851 if (location && !(locationW = strdupAtoW( location ))) goto done;
853 ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL );
855 if (required_size) *required_size = size;
857 if (dest)
859 if (buffer_size >= size)
861 WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
862 if (component) *component = strrchr( dest, '\\' ) + 1;
864 else
865 SetLastError( ERROR_INSUFFICIENT_BUFFER );
868 done:
869 MyFree( destW );
870 HeapFree( GetProcessHeap(), 0, sourceW );
871 HeapFree( GetProcessHeap(), 0, locationW );
872 if (ret) SetLastError(ERROR_SUCCESS);
873 return ret;
876 static int compare_files( HANDLE file1, HANDLE file2 )
878 char buffer1[2048];
879 char buffer2[2048];
880 DWORD size1;
881 DWORD size2;
883 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
884 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
886 int ret;
887 if (size1 != size2)
888 return size1 > size2 ? 1 : -1;
889 if (!size1)
890 return 0;
891 ret = memcmp( buffer1, buffer2, size1 );
892 if (ret)
893 return ret;
896 return 0;
899 static BOOL find_existing_inf(const WCHAR *source, WCHAR *target)
901 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
902 static const WCHAR wildcardW[] = {'*',0};
904 LARGE_INTEGER source_file_size, dest_file_size;
905 HANDLE source_file, dest_file;
906 WIN32_FIND_DATAW find_data;
907 HANDLE find_handle;
909 source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
910 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
911 NULL, OPEN_EXISTING, 0, NULL );
912 if (source_file == INVALID_HANDLE_VALUE)
913 return FALSE;
915 if (!GetFileSizeEx( source_file, &source_file_size ))
917 CloseHandle( source_file );
918 return FALSE;
921 GetWindowsDirectoryW( target, MAX_PATH );
922 lstrcatW( target, infW );
923 lstrcatW( target, wildcardW );
924 if ((find_handle = FindFirstFileW( target, &find_data )) != INVALID_HANDLE_VALUE)
926 do {
927 GetWindowsDirectoryW( target, MAX_PATH );
928 lstrcatW( target, infW );
929 lstrcatW( target, find_data.cFileName );
930 dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
931 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
932 NULL, OPEN_EXISTING, 0, NULL );
933 if (dest_file == INVALID_HANDLE_VALUE)
934 continue;
936 if (GetFileSizeEx( dest_file, &dest_file_size )
937 && dest_file_size.QuadPart == source_file_size.QuadPart
938 && !compare_files( source_file, dest_file ))
940 CloseHandle( dest_file );
941 CloseHandle( source_file );
942 FindClose( find_handle );
943 return TRUE;
945 CloseHandle( dest_file );
946 } while (FindNextFileW( find_handle, &find_data ));
948 FindClose( find_handle );
951 CloseHandle( source_file );
952 return FALSE;
955 /***********************************************************************
956 * SetupCopyOEMInfW (SETUPAPI.@)
958 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
959 DWORD media_type, DWORD style, PWSTR dest,
960 DWORD buffer_size, DWORD *required_size, WCHAR **filepart )
962 BOOL ret = FALSE;
963 WCHAR target[MAX_PATH], catalog_file[MAX_PATH], *p;
964 static const WCHAR inf[] = { '\\','i','n','f','\\',0 };
965 static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
966 static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
967 unsigned int i;
968 DWORD size;
969 HINF hinf;
971 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source), debugstr_w(location),
972 media_type, style, dest, buffer_size, required_size, filepart);
974 if (!source)
976 SetLastError(ERROR_INVALID_PARAMETER);
977 return FALSE;
980 /* check for a relative path */
981 if (!(*source == '\\' || (*source && source[1] == ':')))
983 SetLastError(ERROR_FILE_NOT_FOUND);
984 return FALSE;
987 if (find_existing_inf( source, target ))
989 TRACE("Found existing INF %s.\n", debugstr_w(target));
990 if (style & SP_COPY_NOOVERWRITE)
992 SetLastError( ERROR_FILE_EXISTS );
993 ret = FALSE;
995 else
996 ret = TRUE;
997 goto done;
1000 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1001 lstrcatW( target, inf );
1002 lstrcatW( target, wcsrchr( source, '\\' ) + 1 );
1003 if (GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES)
1005 for (i = 0; i < OEM_INDEX_LIMIT; i++)
1007 static const WCHAR formatW[] = {'o','e','m','%','u','.','i','n','f',0};
1009 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1010 lstrcatW( target, inf );
1011 swprintf( target + lstrlenW(target), ARRAY_SIZE(target) - lstrlenW(target), formatW, i );
1013 if (GetFileAttributesW( target ) == INVALID_FILE_ATTRIBUTES)
1014 break;
1016 if (i == OEM_INDEX_LIMIT)
1018 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1019 return FALSE;
1023 hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL );
1024 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
1026 if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file,
1027 ARRAY_SIZE( catalog_file ), NULL ))
1029 WCHAR source_cat[MAX_PATH];
1030 HCATADMIN handle;
1031 HCATINFO cat;
1032 GUID msguid = DRIVER_ACTION_VERIFY;
1034 SetupCloseInfFile( hinf );
1036 lstrcpyW( source_cat, source );
1037 p = wcsrchr( source_cat, '\\' );
1038 if (p) p++;
1039 else p = source_cat;
1040 lstrcpyW( p, catalog_file );
1042 TRACE("installing catalog file %s\n", debugstr_w( source_cat ));
1044 if (!CryptCATAdminAcquireContext(&handle, &msguid, 0))
1046 ERR("Could not acquire security context\n");
1047 return FALSE;
1050 if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0)))
1052 ERR("Could not add catalog\n");
1053 CryptCATAdminReleaseContext(handle, 0);
1054 return FALSE;
1057 CryptCATAdminReleaseCatalogContext(handle, cat, 0);
1058 CryptCATAdminReleaseContext(handle, 0);
1060 else
1061 SetupCloseInfFile( hinf );
1063 if (!(ret = CopyFileW( source, target, TRUE )))
1064 return ret;
1066 done:
1067 if (style & SP_COPY_DELETESOURCE)
1068 DeleteFileW( source );
1070 size = lstrlenW( target ) + 1;
1071 if (dest)
1073 if (buffer_size >= size)
1075 lstrcpyW( dest, target );
1076 if (filepart) *filepart = wcsrchr( dest, '\\' ) + 1;
1078 else
1080 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1081 ret = FALSE;
1085 if (required_size) *required_size = size;
1086 if (ret) SetLastError(ERROR_SUCCESS);
1088 return ret;
1091 /***********************************************************************
1092 * SetupUninstallOEMInfA (SETUPAPI.@)
1094 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1096 BOOL ret;
1097 WCHAR *inf_fileW = NULL;
1099 TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file), flags, reserved);
1101 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1102 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1103 HeapFree( GetProcessHeap(), 0, inf_fileW );
1104 return ret;
1107 /***********************************************************************
1108 * SetupUninstallOEMInfW (SETUPAPI.@)
1110 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1112 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1113 WCHAR target[MAX_PATH];
1115 TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file), flags, reserved);
1117 if (!inf_file)
1119 SetLastError(ERROR_INVALID_PARAMETER);
1120 return FALSE;
1123 if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) return FALSE;
1125 lstrcatW( target, infW );
1126 lstrcatW( target, inf_file );
1128 if (flags & SUOI_FORCEDELETE)
1129 return DeleteFileW(target);
1131 FIXME("not deleting %s\n", debugstr_w(target));
1133 return TRUE;
1136 /***********************************************************************
1137 * InstallCatalog (SETUPAPI.@)
1139 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1141 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1142 return 0;
1145 /***********************************************************************
1146 * pSetupInstallCatalog (SETUPAPI.@)
1148 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1150 HCATADMIN admin;
1151 HCATINFO cat;
1153 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1155 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1156 return GetLastError();
1158 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1160 DWORD rc = GetLastError();
1161 CryptCATAdminReleaseContext(admin, 0);
1162 return rc;
1164 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1165 CryptCATAdminReleaseContext(admin,0);
1167 if (fullname)
1168 FIXME("not returning full installed catalog path\n");
1170 return NO_ERROR;
1173 static UINT detect_compression_type( LPCWSTR file )
1175 DWORD size;
1176 HANDLE handle;
1177 UINT type = FILE_COMPRESSION_NONE;
1178 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1179 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1180 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1181 BYTE buffer[8];
1183 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1184 if (handle == INVALID_HANDLE_VALUE)
1186 ERR("cannot open file %s\n", debugstr_w(file));
1187 return FILE_COMPRESSION_NONE;
1189 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1191 CloseHandle( handle );
1192 return FILE_COMPRESSION_NONE;
1194 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1195 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1196 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1198 CloseHandle( handle );
1199 return type;
1202 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1204 HANDLE handle;
1206 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1207 if (handle == INVALID_HANDLE_VALUE)
1209 ERR("cannot open file %s\n", debugstr_w(file));
1210 return FALSE;
1212 *size = GetFileSize( handle, NULL );
1213 CloseHandle( handle );
1214 return TRUE;
1217 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1219 DWORD size;
1221 if (!get_file_size( source, &size )) return FALSE;
1222 if (source_size) *source_size = size;
1223 if (target_size) *target_size = size;
1224 return TRUE;
1227 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1229 DWORD size;
1230 BOOL ret = TRUE;
1232 if (source_size)
1234 if (!get_file_size( source, &size )) ret = FALSE;
1235 else *source_size = size;
1237 if (target_size)
1239 INT file;
1240 OFSTRUCT of;
1242 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1244 ERR("cannot open source file for reading\n");
1245 return FALSE;
1247 *target_size = LZSeek( file, 0, 2 );
1248 LZClose( file );
1250 return ret;
1253 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1255 DWORD *size = context;
1256 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1258 switch (notification)
1260 case SPFILENOTIFY_FILEINCABINET:
1262 *size = info->FileSize;
1263 return FILEOP_SKIP;
1265 default: return NO_ERROR;
1269 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1271 DWORD size;
1272 BOOL ret = TRUE;
1274 if (source_size)
1276 if (!get_file_size( source, &size )) ret = FALSE;
1277 else *source_size = size;
1279 if (target_size)
1281 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1283 return ret;
1286 /***********************************************************************
1287 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1289 * See SetupGetFileCompressionInfoExW.
1291 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1292 PDWORD source_size, PDWORD target_size, PUINT type )
1294 BOOL ret;
1295 WCHAR *nameW = NULL, *sourceW = NULL;
1296 DWORD nb_chars = 0;
1297 LPSTR nameA;
1299 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1300 source_size, target_size, type);
1302 if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1304 if (name)
1306 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1307 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1309 MyFree( sourceW );
1310 return FALSE;
1313 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1314 if (ret)
1316 if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1318 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1319 else
1321 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1322 ret = FALSE;
1324 MyFree( nameA );
1327 if (required) *required = nb_chars;
1328 HeapFree( GetProcessHeap(), 0, nameW );
1329 MyFree( sourceW );
1331 return ret;
1334 /***********************************************************************
1335 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1337 * Get compression type and compressed/uncompressed sizes of a given file.
1339 * PARAMS
1340 * source [I] File to examine.
1341 * name [O] Actual filename used.
1342 * len [I] Length in characters of 'name' buffer.
1343 * required [O] Number of characters written to 'name'.
1344 * source_size [O] Size of compressed file.
1345 * target_size [O] Size of uncompressed file.
1346 * type [O] Compression type.
1348 * RETURNS
1349 * Success: TRUE
1350 * Failure: FALSE
1352 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1353 PDWORD source_size, PDWORD target_size, PUINT type )
1355 UINT comp;
1356 BOOL ret = FALSE;
1357 DWORD source_len;
1359 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1360 source_size, target_size, type);
1362 if (!source) return FALSE;
1364 source_len = lstrlenW( source ) + 1;
1365 if (required) *required = source_len;
1366 if (name && len >= source_len)
1368 lstrcpyW( name, source );
1369 ret = TRUE;
1371 else return FALSE;
1373 comp = detect_compression_type( source );
1374 if (type) *type = comp;
1376 switch (comp)
1378 case FILE_COMPRESSION_MSZIP:
1379 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1380 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1381 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1382 default: break;
1384 return ret;
1387 /***********************************************************************
1388 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1390 * See SetupGetFileCompressionInfoW.
1392 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1393 PDWORD target_size, PUINT type )
1395 BOOL ret;
1396 DWORD error, required;
1397 LPSTR actual_name;
1399 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1401 if (!source || !name || !source_size || !target_size || !type)
1402 return ERROR_INVALID_PARAMETER;
1404 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1405 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1407 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1408 source_size, target_size, type );
1409 if (!ret)
1411 error = GetLastError();
1412 MyFree( actual_name );
1413 return error;
1415 *name = actual_name;
1416 return ERROR_SUCCESS;
1419 /***********************************************************************
1420 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1422 * Get compression type and compressed/uncompressed sizes of a given file.
1424 * PARAMS
1425 * source [I] File to examine.
1426 * name [O] Actual filename used.
1427 * source_size [O] Size of compressed file.
1428 * target_size [O] Size of uncompressed file.
1429 * type [O] Compression type.
1431 * RETURNS
1432 * Success: ERROR_SUCCESS
1433 * Failure: Win32 error code.
1435 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1436 PDWORD target_size, PUINT type )
1438 BOOL ret;
1439 DWORD error, required;
1440 LPWSTR actual_name;
1442 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1444 if (!source || !name || !source_size || !target_size || !type)
1445 return ERROR_INVALID_PARAMETER;
1447 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1448 if (!(actual_name = MyMalloc( required * sizeof(WCHAR) )))
1449 return ERROR_NOT_ENOUGH_MEMORY;
1451 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1452 source_size, target_size, type );
1453 if (!ret)
1455 error = GetLastError();
1456 MyFree( actual_name );
1457 return error;
1459 *name = actual_name;
1460 return ERROR_SUCCESS;
1463 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1465 DWORD ret;
1466 LONG error;
1467 INT src, dst;
1468 OFSTRUCT sof, dof;
1470 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1472 ERR("cannot open source file for reading\n");
1473 return ERROR_FILE_NOT_FOUND;
1475 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1477 ERR("cannot open target file for writing\n");
1478 LZClose( src );
1479 return ERROR_FILE_NOT_FOUND;
1481 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1482 else
1484 WARN("failed to decompress file %d\n", error);
1485 ret = ERROR_INVALID_DATA;
1488 LZClose( src );
1489 LZClose( dst );
1490 return ret;
1493 struct callback_context
1495 BOOL has_extracted;
1496 LPCWSTR target;
1499 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1501 struct callback_context *context_info = context;
1502 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1504 switch (notification)
1506 case SPFILENOTIFY_FILEINCABINET:
1508 if (context_info->has_extracted)
1509 return FILEOP_ABORT;
1511 TRACE("Requesting extraction of cabinet file %s\n",
1512 wine_dbgstr_w(info->NameInCabinet));
1513 lstrcpyW( info->FullTargetName, context_info->target );
1514 context_info->has_extracted = TRUE;
1515 return FILEOP_DOIT;
1517 default: return NO_ERROR;
1521 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1523 struct callback_context context = {0, target};
1524 BOOL ret;
1526 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1528 if (ret) return ERROR_SUCCESS;
1529 else return GetLastError();
1532 /***********************************************************************
1533 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1535 * See SetupDecompressOrCopyFileW.
1537 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1539 DWORD ret = 0;
1540 WCHAR *sourceW = NULL, *targetW = NULL;
1542 if (source && !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1543 if (target && !(targetW = MultiByteToUnicode( target, CP_ACP )))
1545 MyFree( sourceW );
1546 return ERROR_NOT_ENOUGH_MEMORY;
1549 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1551 MyFree( sourceW );
1552 MyFree( targetW );
1554 return ret;
1557 /***********************************************************************
1558 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1560 * Copy a file and decompress it if needed.
1562 * PARAMS
1563 * source [I] File to copy.
1564 * target [I] Filename of the copy.
1565 * type [I] Compression type.
1567 * RETURNS
1568 * Success: ERROR_SUCCESS
1569 * Failure: Win32 error code.
1571 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1573 UINT comp;
1574 DWORD ret = ERROR_INVALID_PARAMETER;
1576 TRACE("(%s, %s, %p)\n", debugstr_w(source), debugstr_w(target), type);
1578 if (!source || !target) return ERROR_INVALID_PARAMETER;
1580 if (!type)
1582 comp = detect_compression_type( source );
1583 TRACE("Detected compression type %u\n", comp);
1585 else
1587 comp = *type;
1588 TRACE("Using specified compression type %u\n", comp);
1591 switch (comp)
1593 case FILE_COMPRESSION_NONE:
1594 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1595 else ret = GetLastError();
1596 break;
1597 case FILE_COMPRESSION_WINLZA:
1598 ret = decompress_file_lz( source, target );
1599 break;
1600 case FILE_COMPRESSION_NTCAB:
1601 case FILE_COMPRESSION_MSZIP:
1602 ret = decompress_file_cab( source, target );
1603 break;
1604 default:
1605 WARN("unknown compression type %d\n", comp);
1606 break;
1609 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1610 return ret;
1613 static BOOL non_interactive_mode;
1615 /***********************************************************************
1616 * SetupGetNonInteractiveMode (SETUPAPI.@)
1618 BOOL WINAPI SetupGetNonInteractiveMode( void )
1620 FIXME("\n");
1621 return non_interactive_mode;
1624 /***********************************************************************
1625 * SetupSetNonInteractiveMode (SETUPAPI.@)
1627 BOOL WINAPI SetupSetNonInteractiveMode( BOOL flag )
1629 BOOL ret = non_interactive_mode;
1631 FIXME("%d\n", flag);
1633 non_interactive_mode = flag;
1634 return ret;
1637 /***********************************************************************
1638 * SetupCloseLog(SETUPAPI.@)
1640 void WINAPI SetupCloseLog(void)
1642 EnterCriticalSection(&setupapi_cs);
1644 CloseHandle(setupact);
1645 setupact = INVALID_HANDLE_VALUE;
1647 CloseHandle(setuperr);
1648 setuperr = INVALID_HANDLE_VALUE;
1650 LeaveCriticalSection(&setupapi_cs);
1653 /***********************************************************************
1654 * SetupOpenLog(SETUPAPI.@)
1656 BOOL WINAPI SetupOpenLog(BOOL reserved)
1658 WCHAR path[MAX_PATH];
1660 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
1661 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
1663 EnterCriticalSection(&setupapi_cs);
1665 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
1667 LeaveCriticalSection(&setupapi_cs);
1668 return TRUE;
1671 GetWindowsDirectoryW(path, MAX_PATH);
1672 lstrcatW(path, setupactlog);
1674 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1675 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1676 if (setupact == INVALID_HANDLE_VALUE)
1678 LeaveCriticalSection(&setupapi_cs);
1679 return FALSE;
1682 SetFilePointer(setupact, 0, NULL, FILE_END);
1684 GetWindowsDirectoryW(path, MAX_PATH);
1685 lstrcatW(path, setuperrlog);
1687 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1688 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1689 if (setuperr == INVALID_HANDLE_VALUE)
1691 CloseHandle(setupact);
1692 setupact = INVALID_HANDLE_VALUE;
1693 LeaveCriticalSection(&setupapi_cs);
1694 return FALSE;
1697 SetFilePointer(setuperr, 0, NULL, FILE_END);
1699 LeaveCriticalSection(&setupapi_cs);
1701 return TRUE;
1704 /***********************************************************************
1705 * SetupLogErrorA(SETUPAPI.@)
1707 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
1709 static const char null[] = "(null)";
1710 BOOL ret;
1711 DWORD written;
1712 DWORD len;
1714 EnterCriticalSection(&setupapi_cs);
1716 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
1718 SetLastError(ERROR_FILE_INVALID);
1719 ret = FALSE;
1720 goto done;
1723 if (message == NULL)
1724 message = null;
1726 len = lstrlenA(message);
1728 ret = WriteFile(setupact, message, len, &written, NULL);
1729 if (!ret)
1730 goto done;
1732 if (severity >= LogSevMaximum)
1734 ret = FALSE;
1735 goto done;
1738 if (severity > LogSevInformation)
1739 ret = WriteFile(setuperr, message, len, &written, NULL);
1741 done:
1742 LeaveCriticalSection(&setupapi_cs);
1743 return ret;
1746 /***********************************************************************
1747 * SetupLogErrorW(SETUPAPI.@)
1749 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
1751 LPSTR msg = NULL;
1752 DWORD len;
1753 BOOL ret;
1755 if (message)
1757 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
1758 msg = HeapAlloc(GetProcessHeap(), 0, len);
1759 if (msg == NULL)
1761 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1762 return FALSE;
1764 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
1767 /* This is the normal way to proceed. The log files are ASCII files
1768 * and W is to be converted.
1770 ret = SetupLogErrorA(msg, severity);
1772 HeapFree(GetProcessHeap(), 0, msg);
1773 return ret;
1776 /***********************************************************************
1777 * CM_Get_Version (SETUPAPI.@)
1779 WORD WINAPI CM_Get_Version(void)
1781 TRACE("()\n");
1782 return 0x0400;