d3dx9/tests: Add test for user data in D3DXLoadMeshHierarchyFromXInMemory().
[wine.git] / dlls / setupapi / misc.c
blob701801f7380f3f5ef4e3755d320ccbd2d430413f
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 free(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 malloc(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 return realloc(lpSrc, dwSize);
116 /**************************************************************************
117 * DuplicateString [SETUPAPI.@]
119 * Duplicates a unicode string.
121 * PARAMS
122 * lpSrc [I] pointer to the unicode string that will be duplicated
124 * RETURNS
125 * Success: pointer to the duplicated unicode string
126 * Failure: NULL
128 * NOTES
129 * Call MyFree() to release the duplicated string.
131 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
133 LPWSTR lpDst;
135 lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
136 if (lpDst == NULL)
137 return NULL;
139 lstrcpyW(lpDst, lpSrc);
141 return lpDst;
145 /**************************************************************************
146 * QueryRegistryValue [SETUPAPI.@]
148 * Retrieves value data from the registry and allocates memory for the
149 * value data.
151 * PARAMS
152 * hKey [I] Handle of the key to query
153 * lpValueName [I] Name of value under hkey to query
154 * lpData [O] Destination for the values contents,
155 * lpType [O] Destination for the value type
156 * lpcbData [O] Destination for the size of data
158 * RETURNS
159 * Success: ERROR_SUCCESS
160 * Failure: Otherwise
162 * NOTES
163 * Use MyFree to release the lpData buffer.
165 LONG WINAPI QueryRegistryValue(HKEY hKey,
166 LPCWSTR lpValueName,
167 LPBYTE *lpData,
168 LPDWORD lpType,
169 LPDWORD lpcbData)
171 LONG lError;
173 TRACE("%p %s %p %p %p\n",
174 hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
176 /* Get required buffer size */
177 *lpcbData = 0;
178 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
179 if (lError != ERROR_SUCCESS)
180 return lError;
182 /* Allocate buffer */
183 *lpData = MyMalloc(*lpcbData);
184 if (*lpData == NULL)
185 return ERROR_NOT_ENOUGH_MEMORY;
187 /* Query registry value */
188 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
189 if (lError != ERROR_SUCCESS)
190 MyFree(*lpData);
192 return lError;
196 /**************************************************************************
197 * IsUserAdmin [SETUPAPI.@]
199 * Checks whether the current user is a member of the Administrators group.
201 * PARAMS
202 * None
204 * RETURNS
205 * Success: TRUE
206 * Failure: FALSE
208 BOOL WINAPI IsUserAdmin(VOID)
210 TRACE("\n");
211 return IsUserAnAdmin();
215 /**************************************************************************
216 * MultiByteToUnicode [SETUPAPI.@]
218 * Converts a multi-byte string to a Unicode string.
220 * PARAMS
221 * lpMultiByteStr [I] Multi-byte string to be converted
222 * uCodePage [I] Code page
224 * RETURNS
225 * Success: pointer to the converted Unicode string
226 * Failure: NULL
228 * NOTE
229 * Use MyFree to release the returned Unicode string.
231 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
233 LPWSTR lpUnicodeStr;
234 int nLength;
236 nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
237 -1, NULL, 0);
238 if (nLength == 0)
239 return NULL;
241 lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
242 if (lpUnicodeStr == NULL)
243 return NULL;
245 if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
246 nLength, lpUnicodeStr, nLength))
248 MyFree(lpUnicodeStr);
249 return NULL;
252 return lpUnicodeStr;
256 /**************************************************************************
257 * UnicodeToMultiByte [SETUPAPI.@]
259 * Converts a Unicode string to a multi-byte string.
261 * PARAMS
262 * lpUnicodeStr [I] Unicode string to be converted
263 * uCodePage [I] Code page
265 * RETURNS
266 * Success: pointer to the converted multi-byte string
267 * Failure: NULL
269 * NOTE
270 * Use MyFree to release the returned multi-byte string.
272 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
274 LPSTR lpMultiByteStr;
275 int nLength;
277 nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
278 NULL, 0, NULL, NULL);
279 if (nLength == 0)
280 return NULL;
282 lpMultiByteStr = MyMalloc(nLength);
283 if (lpMultiByteStr == NULL)
284 return NULL;
286 if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
287 lpMultiByteStr, nLength, NULL, NULL))
289 MyFree(lpMultiByteStr);
290 return NULL;
293 return lpMultiByteStr;
297 /**************************************************************************
298 * DoesUserHavePrivilege [SETUPAPI.@]
300 * Check whether the current user has got a given privilege.
302 * PARAMS
303 * lpPrivilegeName [I] Name of the privilege to be checked
305 * RETURNS
306 * Success: TRUE
307 * Failure: FALSE
309 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
311 HANDLE hToken;
312 DWORD dwSize;
313 PTOKEN_PRIVILEGES lpPrivileges;
314 LUID PrivilegeLuid;
315 DWORD i;
316 BOOL bResult = FALSE;
318 TRACE("%s\n", debugstr_w(lpPrivilegeName));
320 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
321 return FALSE;
323 if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
325 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
327 CloseHandle(hToken);
328 return FALSE;
332 lpPrivileges = MyMalloc(dwSize);
333 if (lpPrivileges == NULL)
335 CloseHandle(hToken);
336 return FALSE;
339 if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
341 MyFree(lpPrivileges);
342 CloseHandle(hToken);
343 return FALSE;
346 CloseHandle(hToken);
348 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
350 MyFree(lpPrivileges);
351 return FALSE;
354 for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
356 if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
357 lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
359 bResult = TRUE;
363 MyFree(lpPrivileges);
365 return bResult;
369 /**************************************************************************
370 * EnablePrivilege [SETUPAPI.@]
372 * Enables or disables one of the current users privileges.
374 * PARAMS
375 * lpPrivilegeName [I] Name of the privilege to be changed
376 * bEnable [I] TRUE: Enables the privilege
377 * FALSE: Disables the privilege
379 * RETURNS
380 * Success: TRUE
381 * Failure: FALSE
383 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
385 TOKEN_PRIVILEGES Privileges;
386 HANDLE hToken;
387 BOOL bResult;
389 TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
391 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
392 return FALSE;
394 Privileges.PrivilegeCount = 1;
395 Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
397 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
398 &Privileges.Privileges[0].Luid))
400 CloseHandle(hToken);
401 return FALSE;
404 bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
406 CloseHandle(hToken);
408 return bResult;
412 /**************************************************************************
413 * DelayedMove [SETUPAPI.@]
415 * Moves a file upon the next reboot.
417 * PARAMS
418 * lpExistingFileName [I] Current file name
419 * lpNewFileName [I] New file name
421 * RETURNS
422 * Success: TRUE
423 * Failure: FALSE
425 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
427 return MoveFileExW(lpExistingFileName, lpNewFileName,
428 MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
432 /**************************************************************************
433 * FileExists [SETUPAPI.@]
435 * Checks whether a file exists.
437 * PARAMS
438 * lpFileName [I] Name of the file to check
439 * lpNewFileName [O] Optional information about the existing file
441 * RETURNS
442 * Success: TRUE
443 * Failure: FALSE
445 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
447 WIN32_FIND_DATAW FindData;
448 HANDLE hFind;
449 UINT uErrorMode;
450 DWORD dwError;
452 uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
454 hFind = FindFirstFileW(lpFileName, &FindData);
455 if (hFind == INVALID_HANDLE_VALUE)
457 dwError = GetLastError();
458 SetErrorMode(uErrorMode);
459 SetLastError(dwError);
460 return FALSE;
463 FindClose(hFind);
465 if (lpFileFindData)
466 *lpFileFindData = FindData;
468 SetErrorMode(uErrorMode);
470 return TRUE;
474 /**************************************************************************
475 * CaptureStringArg [SETUPAPI.@]
477 * Captures a UNICODE string.
479 * PARAMS
480 * lpSrc [I] UNICODE string to be captured
481 * lpDst [O] Pointer to the captured UNICODE string
483 * RETURNS
484 * Success: ERROR_SUCCESS
485 * Failure: ERROR_INVALID_PARAMETER
487 * NOTE
488 * Call MyFree to release the captured UNICODE string.
490 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
492 if (pDst == NULL)
493 return ERROR_INVALID_PARAMETER;
495 *pDst = DuplicateString(pSrc);
497 return ERROR_SUCCESS;
501 /**************************************************************************
502 * CaptureAndConvertAnsiArg [SETUPAPI.@]
504 * Captures an ANSI string and converts it to a UNICODE string.
506 * PARAMS
507 * lpSrc [I] ANSI string to be captured
508 * lpDst [O] Pointer to the captured UNICODE string
510 * RETURNS
511 * Success: ERROR_SUCCESS
512 * Failure: ERROR_INVALID_PARAMETER
514 * NOTE
515 * Call MyFree to release the captured UNICODE string.
517 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
519 if (pDst == NULL)
520 return ERROR_INVALID_PARAMETER;
522 *pDst = MultiByteToUnicode(pSrc, CP_ACP);
524 return ERROR_SUCCESS;
528 /**************************************************************************
529 * OpenAndMapFileForRead [SETUPAPI.@]
531 * Open and map a file to a buffer.
533 * PARAMS
534 * lpFileName [I] Name of the file to be opened
535 * lpSize [O] Pointer to the file size
536 * lpFile [0] Pointer to the file handle
537 * lpMapping [0] Pointer to the mapping handle
538 * lpBuffer [0] Pointer to the file buffer
540 * RETURNS
541 * Success: ERROR_SUCCESS
542 * Failure: Other
544 * NOTE
545 * Call UnmapAndCloseFile to release the file.
547 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
548 LPDWORD lpSize,
549 LPHANDLE lpFile,
550 LPHANDLE lpMapping,
551 LPVOID *lpBuffer)
553 DWORD dwError;
555 TRACE("%s %p %p %p %p\n",
556 debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
558 *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
559 OPEN_EXISTING, 0, NULL);
560 if (*lpFile == INVALID_HANDLE_VALUE)
561 return GetLastError();
563 *lpSize = GetFileSize(*lpFile, NULL);
564 if (*lpSize == INVALID_FILE_SIZE)
566 dwError = GetLastError();
567 CloseHandle(*lpFile);
568 return dwError;
571 *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
572 *lpSize, NULL);
573 if (*lpMapping == NULL)
575 dwError = GetLastError();
576 CloseHandle(*lpFile);
577 return dwError;
580 *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
581 if (*lpBuffer == NULL)
583 dwError = GetLastError();
584 CloseHandle(*lpMapping);
585 CloseHandle(*lpFile);
586 return dwError;
589 return ERROR_SUCCESS;
593 /**************************************************************************
594 * UnmapAndCloseFile [SETUPAPI.@]
596 * Unmap and close a mapped file.
598 * PARAMS
599 * hFile [I] Handle to the file
600 * hMapping [I] Handle to the file mapping
601 * lpBuffer [I] Pointer to the file buffer
603 * RETURNS
604 * Success: TRUE
605 * Failure: FALSE
607 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
609 TRACE("%p %p %p\n",
610 hFile, hMapping, lpBuffer);
612 if (!UnmapViewOfFile(lpBuffer))
613 return FALSE;
615 if (!CloseHandle(hMapping))
616 return FALSE;
618 if (!CloseHandle(hFile))
619 return FALSE;
621 return TRUE;
625 /**************************************************************************
626 * StampFileSecurity [SETUPAPI.@]
628 * Assign a new security descriptor to the given file.
630 * PARAMS
631 * lpFileName [I] Name of the file
632 * pSecurityDescriptor [I] New security descriptor
634 * RETURNS
635 * Success: ERROR_SUCCESS
636 * Failure: other
638 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
640 TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
642 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
643 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
644 pSecurityDescriptor))
645 return GetLastError();
647 return ERROR_SUCCESS;
651 /**************************************************************************
652 * TakeOwnershipOfFile [SETUPAPI.@]
654 * Takes the ownership of the given file.
656 * PARAMS
657 * lpFileName [I] Name of the file
659 * RETURNS
660 * Success: ERROR_SUCCESS
661 * Failure: other
663 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
665 SECURITY_DESCRIPTOR SecDesc;
666 HANDLE hToken = NULL;
667 PTOKEN_OWNER pOwner = NULL;
668 DWORD dwError;
669 DWORD dwSize;
671 TRACE("%s\n", debugstr_w(lpFileName));
673 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
674 return GetLastError();
676 if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
678 goto fail;
681 pOwner = MyMalloc(dwSize);
682 if (pOwner == NULL)
684 CloseHandle(hToken);
685 return ERROR_NOT_ENOUGH_MEMORY;
688 if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
690 goto fail;
693 if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
695 goto fail;
698 if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
700 goto fail;
703 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
705 goto fail;
708 MyFree(pOwner);
709 CloseHandle(hToken);
711 return ERROR_SUCCESS;
713 fail:;
714 dwError = GetLastError();
716 MyFree(pOwner);
718 if (hToken != NULL)
719 CloseHandle(hToken);
721 return dwError;
725 /**************************************************************************
726 * RetreiveFileSecurity [SETUPAPI.@]
728 * Retrieve the security descriptor that is associated with the given file.
730 * PARAMS
731 * lpFileName [I] Name of the file
733 * RETURNS
734 * Success: ERROR_SUCCESS
735 * Failure: other
737 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
738 PSECURITY_DESCRIPTOR *pSecurityDescriptor)
740 SECURITY_DESCRIPTOR *SecDesc, *NewSecDesc;
741 DWORD dwSize = 0x100;
742 DWORD dwError;
744 SecDesc = MyMalloc(dwSize);
745 if (SecDesc == NULL)
746 return ERROR_NOT_ENOUGH_MEMORY;
748 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
749 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
750 SecDesc, dwSize, &dwSize))
752 *pSecurityDescriptor = SecDesc;
753 return ERROR_SUCCESS;
756 dwError = GetLastError();
757 if (dwError != ERROR_INSUFFICIENT_BUFFER)
759 MyFree(SecDesc);
760 return dwError;
763 NewSecDesc = MyRealloc(SecDesc, dwSize);
764 if (NewSecDesc == NULL)
766 MyFree(SecDesc);
767 return ERROR_NOT_ENOUGH_MEMORY;
769 SecDesc = NewSecDesc;
771 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
772 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
773 SecDesc, dwSize, &dwSize))
775 *pSecurityDescriptor = SecDesc;
776 return ERROR_SUCCESS;
779 dwError = GetLastError();
780 MyFree(SecDesc);
782 return dwError;
786 static DWORD global_flags = 0; /* FIXME: what should be in here? */
788 /***********************************************************************
789 * pSetupGetGlobalFlags (SETUPAPI.@)
791 DWORD WINAPI pSetupGetGlobalFlags(void)
793 FIXME( "stub\n" );
794 return global_flags;
798 /***********************************************************************
799 * pSetupSetGlobalFlags (SETUPAPI.@)
801 void WINAPI pSetupSetGlobalFlags( DWORD flags )
803 global_flags = flags;
806 /***********************************************************************
807 * CMP_WaitNoPendingInstallEvents (SETUPAPI.@)
809 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
811 static BOOL warned = FALSE;
813 if (!warned)
815 FIXME("%ld\n", dwTimeout);
816 warned = TRUE;
818 return WAIT_OBJECT_0;
821 /***********************************************************************
822 * AssertFail (SETUPAPI.@)
824 * Shows an assert fail error messagebox
826 * PARAMS
827 * lpFile [I] file where assert failed
828 * uLine [I] line number in file
829 * lpMessage [I] assert message
832 void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage)
834 FIXME("%s %u %s\n", lpFile, uLine, lpMessage);
837 /***********************************************************************
838 * SetupCopyOEMInfA (SETUPAPI.@)
840 BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location,
841 DWORD media_type, DWORD style, PSTR dest,
842 DWORD buffer_size, PDWORD required_size, PSTR *component )
844 BOOL ret = FALSE;
845 LPWSTR destW = NULL, sourceW = NULL, locationW = NULL;
846 DWORD size;
848 TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_a(source), debugstr_a(location),
849 media_type, style, dest, buffer_size, required_size, component);
851 if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE;
852 if (source && !(sourceW = strdupAtoW( source ))) goto done;
853 if (location && !(locationW = strdupAtoW( location ))) goto done;
855 ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL );
857 if (required_size) *required_size = size;
859 if (dest)
861 if (buffer_size >= size)
863 WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
864 if (component) *component = strrchr( dest, '\\' ) + 1;
866 else
867 SetLastError( ERROR_INSUFFICIENT_BUFFER );
870 done:
871 MyFree( destW );
872 free( sourceW );
873 free( locationW );
874 if (ret) SetLastError(ERROR_SUCCESS);
875 return ret;
878 static int compare_files( HANDLE file1, HANDLE file2 )
880 char buffer1[2048];
881 char buffer2[2048];
882 DWORD size1;
883 DWORD size2;
885 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
886 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
888 int ret;
889 if (size1 != size2)
890 return size1 > size2 ? 1 : -1;
891 if (!size1)
892 return 0;
893 ret = memcmp( buffer1, buffer2, size1 );
894 if (ret)
895 return ret;
898 return 0;
901 static BOOL find_existing_inf(const WCHAR *source, WCHAR *target)
903 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
904 static const WCHAR wildcardW[] = {'*',0};
906 LARGE_INTEGER source_file_size, dest_file_size;
907 HANDLE source_file, dest_file;
908 WIN32_FIND_DATAW find_data;
909 HANDLE find_handle;
911 source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
912 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
913 NULL, OPEN_EXISTING, 0, NULL );
914 if (source_file == INVALID_HANDLE_VALUE)
915 return FALSE;
917 if (!GetFileSizeEx( source_file, &source_file_size ))
919 CloseHandle( source_file );
920 return FALSE;
923 GetWindowsDirectoryW( target, MAX_PATH );
924 lstrcatW( target, infW );
925 lstrcatW( target, wildcardW );
926 if ((find_handle = FindFirstFileW( target, &find_data )) != INVALID_HANDLE_VALUE)
928 do {
929 GetWindowsDirectoryW( target, MAX_PATH );
930 lstrcatW( target, infW );
931 lstrcatW( target, find_data.cFileName );
932 dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
933 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
934 NULL, OPEN_EXISTING, 0, NULL );
935 if (dest_file == INVALID_HANDLE_VALUE)
936 continue;
938 SetFilePointer( source_file, 0, NULL, FILE_BEGIN );
940 if (GetFileSizeEx( dest_file, &dest_file_size )
941 && dest_file_size.QuadPart == source_file_size.QuadPart
942 && !compare_files( source_file, dest_file ))
944 CloseHandle( dest_file );
945 CloseHandle( source_file );
946 FindClose( find_handle );
947 return TRUE;
949 CloseHandle( dest_file );
950 } while (FindNextFileW( find_handle, &find_data ));
952 FindClose( find_handle );
955 CloseHandle( source_file );
956 return FALSE;
959 /***********************************************************************
960 * SetupCopyOEMInfW (SETUPAPI.@)
962 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
963 DWORD media_type, DWORD style, PWSTR dest,
964 DWORD buffer_size, DWORD *required_size, WCHAR **filepart )
966 BOOL ret = FALSE;
967 WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p;
968 static const WCHAR inf[] = { '\\','i','n','f','\\',0 };
969 static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
970 static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
971 FILE *pnf_file;
972 unsigned int i;
973 DWORD size;
974 HINF hinf;
976 TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_w(source), debugstr_w(location),
977 media_type, style, dest, buffer_size, required_size, filepart);
979 if (!source)
981 SetLastError(ERROR_INVALID_PARAMETER);
982 return FALSE;
985 /* check for a relative path */
986 if (!(*source == '\\' || (*source && source[1] == ':')))
988 SetLastError(ERROR_FILE_NOT_FOUND);
989 return FALSE;
992 if (find_existing_inf( source, target ))
994 TRACE("Found existing INF %s.\n", debugstr_w(target));
995 if (style & SP_COPY_NOOVERWRITE)
997 SetLastError( ERROR_FILE_EXISTS );
998 ret = FALSE;
1000 else
1001 ret = TRUE;
1002 goto done;
1005 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1006 lstrcatW( target, inf );
1007 lstrcatW( target, wcsrchr( source, '\\' ) + 1 );
1008 if (GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES)
1010 for (i = 0; i < OEM_INDEX_LIMIT; i++)
1012 static const WCHAR formatW[] = {'o','e','m','%','u','.','i','n','f',0};
1014 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1015 lstrcatW( target, inf );
1016 swprintf( target + lstrlenW(target), ARRAY_SIZE(target) - lstrlenW(target), formatW, i );
1018 if (GetFileAttributesW( target ) == INVALID_FILE_ATTRIBUTES)
1019 break;
1021 if (i == OEM_INDEX_LIMIT)
1023 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1024 return FALSE;
1028 hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL );
1029 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
1031 if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file,
1032 ARRAY_SIZE( catalog_file ), NULL ))
1034 WCHAR source_cat[MAX_PATH];
1035 HCATADMIN handle;
1036 HCATINFO cat;
1037 GUID msguid = DRIVER_ACTION_VERIFY;
1039 SetupCloseInfFile( hinf );
1041 lstrcpyW( source_cat, source );
1042 p = wcsrchr( source_cat, '\\' );
1043 if (p) p++;
1044 else p = source_cat;
1045 lstrcpyW( p, catalog_file );
1047 TRACE("installing catalog file %s\n", debugstr_w( source_cat ));
1049 if (!CryptCATAdminAcquireContext(&handle, &msguid, 0))
1051 ERR("Could not acquire security context\n");
1052 return FALSE;
1055 if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0)))
1057 ERR("Could not add catalog\n");
1058 CryptCATAdminReleaseContext(handle, 0);
1059 return FALSE;
1062 CryptCATAdminReleaseCatalogContext(handle, cat, 0);
1063 CryptCATAdminReleaseContext(handle, 0);
1065 else
1066 SetupCloseInfFile( hinf );
1068 if (!(ret = CopyFileW( source, target, TRUE )))
1069 return ret;
1071 done:
1072 if (style & SP_COPY_DELETESOURCE)
1073 DeleteFileW( source );
1075 if (ret)
1077 wcscpy(pnf_path, target);
1078 PathRemoveExtensionW(pnf_path);
1079 PathAddExtensionW(pnf_path, L".pnf");
1080 if ((pnf_file = _wfopen(pnf_path, L"w")))
1082 fputws(PNF_HEADER, pnf_file);
1083 fputws(source, pnf_file);
1084 fclose(pnf_file);
1088 size = lstrlenW( target ) + 1;
1089 if (dest)
1091 if (buffer_size >= size)
1093 lstrcpyW( dest, target );
1094 if (filepart) *filepart = wcsrchr( dest, '\\' ) + 1;
1096 else
1098 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1099 ret = FALSE;
1103 if (required_size) *required_size = size;
1104 if (ret) SetLastError(ERROR_SUCCESS);
1106 return ret;
1109 /***********************************************************************
1110 * SetupUninstallOEMInfA (SETUPAPI.@)
1112 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1114 BOOL ret;
1115 WCHAR *inf_fileW = NULL;
1117 TRACE("%s, 0x%08lx, %p\n", debugstr_a(inf_file), flags, reserved);
1119 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1120 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1121 free( inf_fileW );
1122 return ret;
1125 /***********************************************************************
1126 * SetupUninstallOEMInfW (SETUPAPI.@)
1128 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1130 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1131 WCHAR target[MAX_PATH];
1133 TRACE("%s, 0x%08lx, %p\n", debugstr_w(inf_file), flags, reserved);
1135 if (!inf_file)
1137 SetLastError(ERROR_INVALID_PARAMETER);
1138 return FALSE;
1141 if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) return FALSE;
1143 lstrcatW( target, infW );
1144 lstrcatW( target, inf_file );
1146 if (flags & SUOI_FORCEDELETE)
1147 return DeleteFileW(target);
1149 FIXME("not deleting %s\n", debugstr_w(target));
1151 return TRUE;
1154 /***********************************************************************
1155 * InstallCatalog (SETUPAPI.@)
1157 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1159 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1160 return 0;
1163 /***********************************************************************
1164 * pSetupInstallCatalog (SETUPAPI.@)
1166 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1168 HCATADMIN admin;
1169 HCATINFO cat;
1171 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1173 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1174 return GetLastError();
1176 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1178 DWORD rc = GetLastError();
1179 CryptCATAdminReleaseContext(admin, 0);
1180 return rc;
1182 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1183 CryptCATAdminReleaseContext(admin,0);
1185 if (fullname)
1186 FIXME("not returning full installed catalog path\n");
1188 return NO_ERROR;
1191 static UINT detect_compression_type( LPCWSTR file )
1193 DWORD size;
1194 HANDLE handle;
1195 UINT type = FILE_COMPRESSION_NONE;
1196 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1197 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1198 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1199 BYTE buffer[8];
1201 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1202 if (handle == INVALID_HANDLE_VALUE)
1204 ERR("cannot open file %s\n", debugstr_w(file));
1205 return FILE_COMPRESSION_NONE;
1207 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1209 CloseHandle( handle );
1210 return FILE_COMPRESSION_NONE;
1212 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1213 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1214 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1216 CloseHandle( handle );
1217 return type;
1220 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1222 HANDLE handle;
1224 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1225 if (handle == INVALID_HANDLE_VALUE)
1227 ERR("cannot open file %s\n", debugstr_w(file));
1228 return FALSE;
1230 *size = GetFileSize( handle, NULL );
1231 CloseHandle( handle );
1232 return TRUE;
1235 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1237 DWORD size;
1239 if (!get_file_size( source, &size )) return FALSE;
1240 if (source_size) *source_size = size;
1241 if (target_size) *target_size = size;
1242 return TRUE;
1245 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1247 DWORD size;
1248 BOOL ret = TRUE;
1250 if (source_size)
1252 if (!get_file_size( source, &size )) ret = FALSE;
1253 else *source_size = size;
1255 if (target_size)
1257 INT file;
1258 OFSTRUCT of;
1260 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1262 ERR("cannot open source file for reading\n");
1263 return FALSE;
1265 *target_size = LZSeek( file, 0, 2 );
1266 LZClose( file );
1268 return ret;
1271 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1273 DWORD *size = context;
1274 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1276 switch (notification)
1278 case SPFILENOTIFY_FILEINCABINET:
1280 *size = info->FileSize;
1281 return FILEOP_SKIP;
1283 default: return NO_ERROR;
1287 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1289 DWORD size;
1290 BOOL ret = TRUE;
1292 if (source_size)
1294 if (!get_file_size( source, &size )) ret = FALSE;
1295 else *source_size = size;
1297 if (target_size)
1299 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1301 return ret;
1304 /***********************************************************************
1305 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1307 * See SetupGetFileCompressionInfoExW.
1309 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1310 PDWORD source_size, PDWORD target_size, PUINT type )
1312 BOOL ret;
1313 WCHAR *nameW = NULL, *sourceW = NULL;
1314 DWORD nb_chars = 0;
1315 LPSTR nameA;
1317 TRACE("%s, %p, %ld, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1318 source_size, target_size, type);
1320 if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1322 if (name)
1324 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1325 if (!(nameW = malloc( nb_chars * sizeof(WCHAR) )))
1327 MyFree( sourceW );
1328 return FALSE;
1331 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1332 if (ret)
1334 if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1336 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1337 else
1339 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1340 ret = FALSE;
1342 MyFree( nameA );
1345 if (required) *required = nb_chars;
1346 free( nameW );
1347 MyFree( sourceW );
1349 return ret;
1352 /***********************************************************************
1353 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1355 * Get compression type and compressed/uncompressed sizes of a given file.
1357 * PARAMS
1358 * source [I] File to examine.
1359 * name [O] Actual filename used.
1360 * len [I] Length in characters of 'name' buffer.
1361 * required [O] Number of characters written to 'name'.
1362 * source_size [O] Size of compressed file.
1363 * target_size [O] Size of uncompressed file.
1364 * type [O] Compression type.
1366 * RETURNS
1367 * Success: TRUE
1368 * Failure: FALSE
1370 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1371 PDWORD source_size, PDWORD target_size, PUINT type )
1373 UINT comp;
1374 BOOL ret = FALSE;
1375 DWORD source_len;
1377 TRACE("%s, %p, %ld, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1378 source_size, target_size, type);
1380 if (!source) return FALSE;
1382 source_len = lstrlenW( source ) + 1;
1383 if (required) *required = source_len;
1384 if (name && len >= source_len)
1386 lstrcpyW( name, source );
1387 ret = TRUE;
1389 else return FALSE;
1391 comp = detect_compression_type( source );
1392 if (type) *type = comp;
1394 switch (comp)
1396 case FILE_COMPRESSION_MSZIP:
1397 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1398 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1399 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1400 default: break;
1402 return ret;
1405 /***********************************************************************
1406 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1408 * See SetupGetFileCompressionInfoW.
1410 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1411 PDWORD target_size, PUINT type )
1413 BOOL ret;
1414 DWORD error, required;
1415 LPSTR actual_name;
1417 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1419 if (!source || !name || !source_size || !target_size || !type)
1420 return ERROR_INVALID_PARAMETER;
1422 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1423 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1425 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1426 source_size, target_size, type );
1427 if (!ret)
1429 error = GetLastError();
1430 MyFree( actual_name );
1431 return error;
1433 *name = actual_name;
1434 return ERROR_SUCCESS;
1437 /***********************************************************************
1438 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1440 * Get compression type and compressed/uncompressed sizes of a given file.
1442 * PARAMS
1443 * source [I] File to examine.
1444 * name [O] Actual filename used.
1445 * source_size [O] Size of compressed file.
1446 * target_size [O] Size of uncompressed file.
1447 * type [O] Compression type.
1449 * RETURNS
1450 * Success: ERROR_SUCCESS
1451 * Failure: Win32 error code.
1453 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1454 PDWORD target_size, PUINT type )
1456 BOOL ret;
1457 DWORD error, required;
1458 LPWSTR actual_name;
1460 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1462 if (!source || !name || !source_size || !target_size || !type)
1463 return ERROR_INVALID_PARAMETER;
1465 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1466 if (!(actual_name = MyMalloc( required * sizeof(WCHAR) )))
1467 return ERROR_NOT_ENOUGH_MEMORY;
1469 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1470 source_size, target_size, type );
1471 if (!ret)
1473 error = GetLastError();
1474 MyFree( actual_name );
1475 return error;
1477 *name = actual_name;
1478 return ERROR_SUCCESS;
1481 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1483 DWORD ret;
1484 LONG error;
1485 INT src, dst;
1486 OFSTRUCT sof, dof;
1488 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1490 ERR("cannot open source file for reading\n");
1491 return ERROR_FILE_NOT_FOUND;
1493 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1495 ERR("cannot open target file for writing\n");
1496 LZClose( src );
1497 return ERROR_FILE_NOT_FOUND;
1499 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1500 else
1502 WARN("failed to decompress file %ld\n", error);
1503 ret = ERROR_INVALID_DATA;
1506 LZClose( src );
1507 LZClose( dst );
1508 return ret;
1511 struct callback_context
1513 BOOL has_extracted;
1514 LPCWSTR target;
1517 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1519 struct callback_context *context_info = context;
1520 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1522 switch (notification)
1524 case SPFILENOTIFY_FILEINCABINET:
1526 if (context_info->has_extracted)
1527 return FILEOP_ABORT;
1529 TRACE("Requesting extraction of cabinet file %s\n",
1530 wine_dbgstr_w(info->NameInCabinet));
1531 lstrcpyW( info->FullTargetName, context_info->target );
1532 context_info->has_extracted = TRUE;
1533 return FILEOP_DOIT;
1535 default: return NO_ERROR;
1539 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1541 struct callback_context context = {0, target};
1542 BOOL ret;
1544 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1546 if (ret) return ERROR_SUCCESS;
1547 else return GetLastError();
1550 /***********************************************************************
1551 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1553 * See SetupDecompressOrCopyFileW.
1555 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1557 DWORD ret = 0;
1558 WCHAR *sourceW = NULL, *targetW = NULL;
1560 if (source && !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1561 if (target && !(targetW = MultiByteToUnicode( target, CP_ACP )))
1563 MyFree( sourceW );
1564 return ERROR_NOT_ENOUGH_MEMORY;
1567 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1569 MyFree( sourceW );
1570 MyFree( targetW );
1572 return ret;
1575 /***********************************************************************
1576 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1578 * Copy a file and decompress it if needed.
1580 * PARAMS
1581 * source [I] File to copy.
1582 * target [I] Filename of the copy.
1583 * type [I] Compression type.
1585 * RETURNS
1586 * Success: ERROR_SUCCESS
1587 * Failure: Win32 error code.
1589 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1591 UINT comp;
1592 DWORD ret = ERROR_INVALID_PARAMETER;
1594 TRACE("(%s, %s, %p)\n", debugstr_w(source), debugstr_w(target), type);
1596 if (!source || !target) return ERROR_INVALID_PARAMETER;
1598 if (!type)
1600 comp = detect_compression_type( source );
1601 TRACE("Detected compression type %u\n", comp);
1603 else
1605 comp = *type;
1606 TRACE("Using specified compression type %u\n", comp);
1609 switch (comp)
1611 case FILE_COMPRESSION_NONE:
1612 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1613 else ret = GetLastError();
1614 break;
1615 case FILE_COMPRESSION_WINLZA:
1616 ret = decompress_file_lz( source, target );
1617 break;
1618 case FILE_COMPRESSION_NTCAB:
1619 case FILE_COMPRESSION_MSZIP:
1620 ret = decompress_file_cab( source, target );
1621 break;
1622 default:
1623 WARN("unknown compression type %d\n", comp);
1624 break;
1627 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1628 return ret;
1631 static BOOL non_interactive_mode;
1633 /***********************************************************************
1634 * SetupGetNonInteractiveMode (SETUPAPI.@)
1636 BOOL WINAPI SetupGetNonInteractiveMode( void )
1638 FIXME("\n");
1639 return non_interactive_mode;
1642 /***********************************************************************
1643 * SetupSetNonInteractiveMode (SETUPAPI.@)
1645 BOOL WINAPI SetupSetNonInteractiveMode( BOOL flag )
1647 BOOL ret = non_interactive_mode;
1649 FIXME("%d\n", flag);
1651 non_interactive_mode = flag;
1652 return ret;
1655 /***********************************************************************
1656 * SetupCloseLog(SETUPAPI.@)
1658 void WINAPI SetupCloseLog(void)
1660 EnterCriticalSection(&setupapi_cs);
1662 CloseHandle(setupact);
1663 setupact = INVALID_HANDLE_VALUE;
1665 CloseHandle(setuperr);
1666 setuperr = INVALID_HANDLE_VALUE;
1668 LeaveCriticalSection(&setupapi_cs);
1671 /***********************************************************************
1672 * SetupOpenLog(SETUPAPI.@)
1674 BOOL WINAPI SetupOpenLog(BOOL reserved)
1676 WCHAR path[MAX_PATH];
1678 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
1679 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
1681 EnterCriticalSection(&setupapi_cs);
1683 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
1685 LeaveCriticalSection(&setupapi_cs);
1686 return TRUE;
1689 GetWindowsDirectoryW(path, MAX_PATH);
1690 lstrcatW(path, setupactlog);
1692 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1693 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1694 if (setupact == INVALID_HANDLE_VALUE)
1696 LeaveCriticalSection(&setupapi_cs);
1697 return FALSE;
1700 SetFilePointer(setupact, 0, NULL, FILE_END);
1702 GetWindowsDirectoryW(path, MAX_PATH);
1703 lstrcatW(path, setuperrlog);
1705 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1706 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1707 if (setuperr == INVALID_HANDLE_VALUE)
1709 CloseHandle(setupact);
1710 setupact = INVALID_HANDLE_VALUE;
1711 LeaveCriticalSection(&setupapi_cs);
1712 return FALSE;
1715 SetFilePointer(setuperr, 0, NULL, FILE_END);
1717 LeaveCriticalSection(&setupapi_cs);
1719 return TRUE;
1722 /***********************************************************************
1723 * SetupLogErrorA(SETUPAPI.@)
1725 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
1727 static const char null[] = "(null)";
1728 BOOL ret;
1729 DWORD written;
1730 DWORD len;
1732 EnterCriticalSection(&setupapi_cs);
1734 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
1736 SetLastError(ERROR_FILE_INVALID);
1737 ret = FALSE;
1738 goto done;
1741 if (message == NULL)
1742 message = null;
1744 len = lstrlenA(message);
1746 ret = WriteFile(setupact, message, len, &written, NULL);
1747 if (!ret)
1748 goto done;
1750 if (severity >= LogSevMaximum)
1752 ret = FALSE;
1753 goto done;
1756 if (severity > LogSevInformation)
1757 ret = WriteFile(setuperr, message, len, &written, NULL);
1759 done:
1760 LeaveCriticalSection(&setupapi_cs);
1761 return ret;
1764 /***********************************************************************
1765 * SetupLogErrorW(SETUPAPI.@)
1767 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
1769 LPSTR msg = NULL;
1770 DWORD len;
1771 BOOL ret;
1773 if (message)
1775 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
1776 msg = malloc(len);
1777 if (msg == NULL)
1779 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1780 return FALSE;
1782 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
1785 /* This is the normal way to proceed. The log files are ANSI files
1786 * and W is to be converted.
1788 ret = SetupLogErrorA(msg, severity);
1790 free(msg);
1791 return ret;
1794 /***********************************************************************
1795 * CM_Get_Version (SETUPAPI.@)
1797 WORD WINAPI CM_Get_Version(void)
1799 TRACE("()\n");
1800 return 0x0400;