ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

msi.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of the Microsoft Installer (msi.dll)
00003  *
00004  * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 
00023 #define COBJMACROS
00024 #define NONAMELESSUNION
00025 
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "winreg.h"
00029 #include "winnls.h"
00030 #include "shlwapi.h"
00031 #include "msi.h"
00032 #include "msidefs.h"
00033 #include "msiquery.h"
00034 #include "msipriv.h"
00035 #include "msiserver.h"
00036 #include "wincrypt.h"
00037 #include "winver.h"
00038 #include "winuser.h"
00039 #include "shlobj.h"
00040 #include "shobjidl.h"
00041 #include "objidl.h"
00042 #include "wintrust.h"
00043 #include "softpub.h"
00044 
00045 #include "initguid.h"
00046 #include "msxml2.h"
00047 
00048 #include "wine/debug.h"
00049 #include "wine/unicode.h"
00050 
00051 WINE_DEFAULT_DEBUG_CHANNEL(msi);
00052 
00053 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
00054 
00055 UINT msi_locate_product(LPCWSTR szProduct, MSIINSTALLCONTEXT *context)
00056 {
00057     HKEY hkey = NULL;
00058 
00059     *context = MSIINSTALLCONTEXT_NONE;
00060     if (!szProduct) return ERROR_UNKNOWN_PRODUCT;
00061 
00062     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
00063                               &hkey, FALSE) == ERROR_SUCCESS)
00064         *context = MSIINSTALLCONTEXT_USERMANAGED;
00065     else if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
00066                                    &hkey, FALSE) == ERROR_SUCCESS)
00067         *context = MSIINSTALLCONTEXT_MACHINE;
00068     else if (MSIREG_OpenProductKey(szProduct, NULL,
00069                                    MSIINSTALLCONTEXT_USERUNMANAGED,
00070                                    &hkey, FALSE) == ERROR_SUCCESS)
00071         *context = MSIINSTALLCONTEXT_USERUNMANAGED;
00072 
00073     RegCloseKey(hkey);
00074 
00075     if (*context == MSIINSTALLCONTEXT_NONE)
00076         return ERROR_UNKNOWN_PRODUCT;
00077 
00078     return ERROR_SUCCESS;
00079 }
00080 
00081 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
00082 {
00083     UINT r;
00084     LPWSTR szwProd = NULL;
00085 
00086     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
00087 
00088     if( szProduct )
00089     {
00090         szwProd = strdupAtoW( szProduct );
00091         if( !szwProd )
00092             return ERROR_OUTOFMEMORY;
00093     }
00094 
00095     r = MsiOpenProductW( szwProd, phProduct );
00096 
00097     msi_free( szwProd );
00098 
00099     return r;
00100 }
00101 
00102 static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package)
00103 {
00104     UINT r;
00105     HKEY props;
00106     LPWSTR path;
00107     MSIINSTALLCONTEXT context;
00108 
00109     static const WCHAR managed[] = {
00110         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0};
00111     static const WCHAR local[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
00112 
00113     TRACE("%s %p\n", debugstr_w(szProduct), package);
00114 
00115     r = msi_locate_product(szProduct, &context);
00116     if (r != ERROR_SUCCESS)
00117         return r;
00118 
00119     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &props, FALSE);
00120     if (r != ERROR_SUCCESS)
00121         return ERROR_UNKNOWN_PRODUCT;
00122 
00123     if (context == MSIINSTALLCONTEXT_USERMANAGED)
00124         path = msi_reg_get_val_str(props, managed);
00125     else
00126         path = msi_reg_get_val_str(props, local);
00127 
00128     r = ERROR_UNKNOWN_PRODUCT;
00129 
00130     if (!path || GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
00131         goto done;
00132 
00133     if (PathIsRelativeW(path))
00134     {
00135         r = ERROR_INSTALL_PACKAGE_OPEN_FAILED;
00136         goto done;
00137     }
00138 
00139     r = MSI_OpenPackageW(path, package);
00140 
00141 done:
00142     RegCloseKey(props);
00143     msi_free(path);
00144     return r;
00145 }
00146 
00147 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
00148 {
00149     MSIPACKAGE *package = NULL;
00150     WCHAR squished_pc[GUID_SIZE];
00151     UINT r;
00152 
00153     if (!szProduct || !squash_guid(szProduct, squished_pc))
00154         return ERROR_INVALID_PARAMETER;
00155 
00156     if (!phProduct)
00157         return ERROR_INVALID_PARAMETER;
00158 
00159     r = MSI_OpenProductW(szProduct, &package);
00160     if (r != ERROR_SUCCESS)
00161         return r;
00162 
00163     *phProduct = alloc_msihandle(&package->hdr);
00164     if (!*phProduct)
00165         r = ERROR_NOT_ENOUGH_MEMORY;
00166 
00167     msiobj_release(&package->hdr);
00168     return r;
00169 }
00170 
00171 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
00172                 LPCSTR szTransforms, LANGID lgidLanguage)
00173 {
00174     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
00175           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
00176     return ERROR_CALL_NOT_IMPLEMENTED;
00177 }
00178 
00179 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
00180                 LPCWSTR szTransforms, LANGID lgidLanguage)
00181 {
00182     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
00183           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
00184     return ERROR_CALL_NOT_IMPLEMENTED;
00185 }
00186 
00187 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
00188       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
00189 {
00190     FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath),
00191           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
00192           lgidLanguage, dwPlatform, dwOptions);
00193     return ERROR_CALL_NOT_IMPLEMENTED;
00194 }
00195 
00196 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
00197       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
00198 {
00199     FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath),
00200           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
00201           lgidLanguage, dwPlatform, dwOptions);
00202     return ERROR_CALL_NOT_IMPLEMENTED;
00203 }
00204 
00205 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
00206 {
00207     LPWSTR szwPath = NULL, szwCommand = NULL;
00208     UINT r = ERROR_OUTOFMEMORY;
00209 
00210     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
00211 
00212     if( szPackagePath )
00213     {
00214         szwPath = strdupAtoW( szPackagePath );
00215         if( !szwPath )
00216             goto end;
00217     }
00218 
00219     if( szCommandLine )
00220     {
00221         szwCommand = strdupAtoW( szCommandLine );
00222         if( !szwCommand )
00223             goto end;
00224     }
00225 
00226     r = MsiInstallProductW( szwPath, szwCommand );
00227 
00228 end:
00229     msi_free( szwPath );
00230     msi_free( szwCommand );
00231 
00232     return r;
00233 }
00234 
00235 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
00236 {
00237     MSIPACKAGE *package = NULL;
00238     UINT r;
00239 
00240     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
00241 
00242     if (!szPackagePath)
00243         return ERROR_INVALID_PARAMETER;
00244 
00245     if (!*szPackagePath)
00246         return ERROR_PATH_NOT_FOUND;
00247 
00248     r = MSI_OpenPackageW( szPackagePath, &package );
00249     if (r == ERROR_SUCCESS)
00250     {
00251         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
00252         msiobj_release( &package->hdr );
00253     }
00254 
00255     return r;
00256 }
00257 
00258 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
00259 {
00260     LPWSTR wszProduct;
00261     UINT rc;
00262 
00263     TRACE("%s %08x\n", debugstr_a(szProduct), dwReinstallMode);
00264 
00265     wszProduct = strdupAtoW(szProduct);
00266 
00267     rc = MsiReinstallProductW(wszProduct, dwReinstallMode);
00268 
00269     msi_free(wszProduct);
00270     return rc;
00271 }
00272 
00273 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
00274 {
00275     TRACE("%s %08x\n", debugstr_w(szProduct), dwReinstallMode);
00276 
00277     return MsiReinstallFeatureW(szProduct, szAll, dwReinstallMode);
00278 }
00279 
00280 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
00281         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
00282 {
00283     LPWSTR patch_package = NULL;
00284     LPWSTR install_package = NULL;
00285     LPWSTR command_line = NULL;
00286     UINT r = ERROR_OUTOFMEMORY;
00287 
00288     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
00289           eInstallType, debugstr_a(szCommandLine));
00290 
00291     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
00292         goto done;
00293 
00294     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
00295         goto done;
00296 
00297     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
00298         goto done;
00299 
00300     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
00301 
00302 done:
00303     msi_free(patch_package);
00304     msi_free(install_package);
00305     msi_free(command_line);
00306 
00307     return r;
00308 }
00309 
00310 static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes )
00311 {
00312     MSIHANDLE patch, info = 0;
00313     UINT r, type;
00314     DWORD size;
00315     static WCHAR empty[] = {0};
00316     WCHAR *codes = NULL;
00317 
00318     r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
00319     if (r != ERROR_SUCCESS)
00320         return r;
00321 
00322     r = MsiGetSummaryInformationW( patch, NULL, 0, &info );
00323     if (r != ERROR_SUCCESS)
00324         goto done;
00325 
00326     size = 0;
00327     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, empty, &size );
00328     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
00329     {
00330         ERR("Failed to read product codes from patch\n");
00331         r = ERROR_FUNCTION_FAILED;
00332         goto done;
00333     }
00334 
00335     codes = msi_alloc( ++size * sizeof(WCHAR) );
00336     if (!codes)
00337     {
00338         r = ERROR_OUTOFMEMORY;
00339         goto done;
00340     }
00341 
00342     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, codes, &size );
00343     if (r == ERROR_SUCCESS)
00344         *product_codes = msi_split_string( codes, ';' );
00345 
00346 done:
00347     MsiCloseHandle( info );
00348     MsiCloseHandle( patch );
00349     msi_free( codes );
00350     return r;
00351 }
00352 
00353 static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
00354 {
00355     UINT i, r = ERROR_FUNCTION_FAILED;
00356     DWORD size;
00357     LPCWSTR cmd_ptr = szCommandLine;
00358     LPWSTR cmd, *codes = NULL;
00359     BOOL succeeded = FALSE;
00360 
00361     static const WCHAR fmt[] = {'%','s',' ','P','A','T','C','H','=','"','%','s','"',0};
00362     static WCHAR empty[] = {0};
00363 
00364     if (!szPatchPackage || !szPatchPackage[0])
00365         return ERROR_INVALID_PARAMETER;
00366 
00367     if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes )))
00368         return r;
00369 
00370     if (!szCommandLine)
00371         cmd_ptr = empty;
00372 
00373     size = strlenW(cmd_ptr) + strlenW(fmt) + strlenW(szPatchPackage) + 1;
00374     cmd = msi_alloc(size * sizeof(WCHAR));
00375     if (!cmd)
00376     {
00377         msi_free(codes);
00378         return ERROR_OUTOFMEMORY;
00379     }
00380     sprintfW(cmd, fmt, cmd_ptr, szPatchPackage);
00381 
00382     if (szProductCode)
00383         r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
00384     else
00385     {
00386         for (i = 0; codes[i]; i++)
00387         {
00388             r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
00389             if (r == ERROR_SUCCESS)
00390             {
00391                 TRACE("patch applied\n");
00392                 succeeded = TRUE;
00393             }
00394         }
00395 
00396         if (succeeded)
00397             r = ERROR_SUCCESS;
00398     }
00399 
00400     msi_free(cmd);
00401     msi_free(codes);
00402     return r;
00403 }
00404 
00405 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
00406          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
00407 {
00408     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
00409           eInstallType, debugstr_w(szCommandLine));
00410 
00411     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
00412         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
00413     {
00414         FIXME("Only reading target products from patch\n");
00415         return ERROR_CALL_NOT_IMPLEMENTED;
00416     }
00417 
00418     return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine);
00419 }
00420 
00421 UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,
00422         LPCSTR szProductCode, LPCSTR szPropertiesList)
00423 {
00424     LPWSTR patch_packages = NULL;
00425     LPWSTR product_code = NULL;
00426     LPWSTR properties_list = NULL;
00427     UINT r = ERROR_OUTOFMEMORY;
00428 
00429     TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode),
00430           debugstr_a(szPropertiesList));
00431 
00432     if (!szPatchPackages || !szPatchPackages[0])
00433         return ERROR_INVALID_PARAMETER;
00434 
00435     if (!(patch_packages = strdupAtoW(szPatchPackages)))
00436         return ERROR_OUTOFMEMORY;
00437 
00438     if (szProductCode && !(product_code = strdupAtoW(szProductCode)))
00439         goto done;
00440 
00441     if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList)))
00442         goto done;
00443 
00444     r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list);
00445 
00446 done:
00447     msi_free(patch_packages);
00448     msi_free(product_code);
00449     msi_free(properties_list);
00450 
00451     return r;
00452 }
00453 
00454 UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
00455         LPCWSTR szProductCode, LPCWSTR szPropertiesList)
00456 {
00457     UINT r = ERROR_SUCCESS;
00458     LPCWSTR beg, end;
00459 
00460     TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode),
00461           debugstr_w(szPropertiesList));
00462 
00463     if (!szPatchPackages || !szPatchPackages[0])
00464         return ERROR_INVALID_PARAMETER;
00465 
00466     beg = end = szPatchPackages;
00467     while (*beg)
00468     {
00469         DWORD len;
00470         LPWSTR patch;
00471 
00472         while (*beg == ' ') beg++;
00473         while (*end && *end != ';') end++;
00474 
00475         len = end - beg;
00476         while (len && beg[len - 1] == ' ') len--;
00477 
00478         if (!len) return ERROR_INVALID_NAME;
00479 
00480         patch = msi_alloc((len + 1) * sizeof(WCHAR));
00481         if (!patch)
00482             return ERROR_OUTOFMEMORY;
00483 
00484         memcpy(patch, beg, len * sizeof(WCHAR));
00485         patch[len] = '\0';
00486 
00487         r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
00488         msi_free(patch);
00489 
00490         if (r != ERROR_SUCCESS)
00491             break;
00492 
00493         beg = ++end;
00494     }
00495     return r;
00496 }
00497 
00498 static void free_patchinfo( DWORD count, MSIPATCHSEQUENCEINFOW *info )
00499 {
00500     DWORD i;
00501     for (i = 0; i < count; i++) msi_free( (WCHAR *)info[i].szPatchData );
00502     msi_free( info );
00503 }
00504 
00505 static MSIPATCHSEQUENCEINFOW *patchinfoAtoW( DWORD count, const MSIPATCHSEQUENCEINFOA *info )
00506 {
00507     DWORD i;
00508     MSIPATCHSEQUENCEINFOW *ret;
00509 
00510     if (!(ret = msi_alloc( count * sizeof(MSIPATCHSEQUENCEINFOW) ))) return NULL;
00511     for (i = 0; i < count; i++)
00512     {
00513         if (info[i].szPatchData && !(ret[i].szPatchData = strdupAtoW( info[i].szPatchData )))
00514         {
00515             free_patchinfo( i, ret );
00516             return NULL;
00517         }
00518         ret[i].ePatchDataType = info[i].ePatchDataType;
00519         ret[i].dwOrder = info[i].dwOrder;
00520         ret[i].uStatus = info[i].uStatus;
00521     }
00522     return ret;
00523 }
00524 
00525 UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath,
00526         DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOA pPatchInfo)
00527 {
00528     UINT i, r;
00529     WCHAR *package_path = NULL;
00530     MSIPATCHSEQUENCEINFOW *psi;
00531 
00532     TRACE("%s, %u, %p\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo);
00533 
00534     if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
00535         return ERROR_OUTOFMEMORY;
00536 
00537     if (!(psi = patchinfoAtoW( cPatchInfo, pPatchInfo )))
00538     {
00539         msi_free( package_path );
00540         return ERROR_OUTOFMEMORY;
00541     }
00542     r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
00543     if (r == ERROR_SUCCESS)
00544     {
00545         for (i = 0; i < cPatchInfo; i++)
00546         {
00547             pPatchInfo[i].dwOrder = psi[i].dwOrder;
00548             pPatchInfo[i].uStatus = psi[i].uStatus;
00549         }
00550     }
00551     msi_free( package_path );
00552     free_patchinfo( cPatchInfo, psi );
00553     return r;
00554 }
00555 
00556 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
00557 {
00558     MSISUMMARYINFO *si;
00559     MSIDATABASE *patch_db;
00560     UINT r = ERROR_SUCCESS;
00561 
00562     r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
00563     if (r != ERROR_SUCCESS)
00564     {
00565         WARN("failed to open patch file %s\n", debugstr_w(patch));
00566         return r;
00567     }
00568 
00569     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
00570     if (!si)
00571     {
00572         msiobj_release( &patch_db->hdr );
00573         return ERROR_FUNCTION_FAILED;
00574     }
00575 
00576     r = msi_check_patch_applicable( package, si );
00577     if (r != ERROR_SUCCESS)
00578         TRACE("patch not applicable\n");
00579 
00580     msiobj_release( &patch_db->hdr );
00581     msiobj_release( &si->hdr );
00582     return r;
00583 }
00584 
00585 /* IXMLDOMDocument should be set to XPath mode already */
00586 static UINT MSI_ApplicablePatchXML( MSIPACKAGE *package, IXMLDOMDocument *desc )
00587 {
00588     static const WCHAR queryW[] = {'M','s','i','P','a','t','c','h','/',
00589                                    'T','a','r','g','e','t','P','r','o','d','u','c','t','/',
00590                                    'T','a','r','g','e','t','P','r','o','d','u','c','t','C','o','d','e',0};
00591     UINT r = ERROR_FUNCTION_FAILED;
00592     IXMLDOMNodeList *list;
00593     LPWSTR product_code;
00594     IXMLDOMNode *node;
00595     HRESULT hr;
00596     BSTR s;
00597 
00598     product_code = msi_dup_property( package->db, szProductCode );
00599     if (!product_code)
00600     {
00601         /* FIXME: the property ProductCode should be written into the DB somewhere */
00602         ERR("no product code to check\n");
00603         return ERROR_SUCCESS;
00604     }
00605 
00606     s = SysAllocString(queryW);
00607     hr = IXMLDOMDocument_selectNodes( desc, s, &list );
00608     SysFreeString(s);
00609     if (hr != S_OK)
00610         return ERROR_INVALID_PATCH_XML;
00611 
00612     while (IXMLDOMNodeList_nextNode( list, &node ) == S_OK && r != ERROR_SUCCESS)
00613     {
00614         hr = IXMLDOMNode_get_text( node, &s );
00615         IXMLDOMNode_Release( node );
00616         if (hr == S_OK)
00617         {
00618             if (!strcmpW( s, product_code )) r = ERROR_SUCCESS;
00619             SysFreeString( s );
00620         }
00621     }
00622     IXMLDOMNodeList_Release( list );
00623 
00624     if (r != ERROR_SUCCESS)
00625         TRACE("patch not applicable\n");
00626 
00627     msi_free( product_code );
00628     return r;
00629 }
00630 
00631 static UINT determine_patch_sequence( MSIPACKAGE *package, DWORD count, MSIPATCHSEQUENCEINFOW *info )
00632 {
00633     IXMLDOMDocument *desc = NULL;
00634     DWORD i;
00635 
00636     if (count > 1)
00637         FIXME("patch ordering not supported\n");
00638 
00639     for (i = 0; i < count; i++)
00640     {
00641         switch (info[i].ePatchDataType)
00642         {
00643         case MSIPATCH_DATATYPE_PATCHFILE:
00644         {
00645             if (MSI_ApplicablePatchW( package, info[i].szPatchData ) != ERROR_SUCCESS)
00646             {
00647                 info[i].dwOrder = ~0u;
00648                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
00649             }
00650             else
00651             {
00652                 info[i].dwOrder = i;
00653                 info[i].uStatus = ERROR_SUCCESS;
00654             }
00655             break;
00656         }
00657         case MSIPATCH_DATATYPE_XMLPATH:
00658         case MSIPATCH_DATATYPE_XMLBLOB:
00659         {
00660             VARIANT_BOOL b;
00661             HRESULT hr;
00662             BSTR s;
00663 
00664             if (!desc)
00665             {
00666                 hr = CoCreateInstance( &CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
00667                     &IID_IXMLDOMDocument, (void**)&desc );
00668                 if (hr != S_OK)
00669                 {
00670                     ERR("failed to create DOMDocument30 instance, 0x%08x\n", hr);
00671                     return ERROR_FUNCTION_FAILED;
00672                 }
00673             }
00674 
00675             s = SysAllocString( info[i].szPatchData );
00676             if (info[i].ePatchDataType == MSIPATCH_DATATYPE_XMLPATH)
00677             {
00678                 VARIANT src;
00679 
00680                 V_VT(&src) = VT_BSTR;
00681                 V_BSTR(&src) = s;
00682                 hr = IXMLDOMDocument_load( desc, src, &b );
00683             }
00684             else
00685                 hr = IXMLDOMDocument_loadXML( desc, s, &b );
00686             SysFreeString( s );
00687             if ( hr != S_OK )
00688             {
00689                 ERR("failed to parse patch description\n");
00690                 IXMLDOMDocument_Release( desc );
00691                 break;
00692             }
00693 
00694             if (MSI_ApplicablePatchXML( package, desc ) != ERROR_SUCCESS)
00695             {
00696                 info[i].dwOrder = ~0u;
00697                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
00698             }
00699             else
00700             {
00701                 info[i].dwOrder = i;
00702                 info[i].uStatus = ERROR_SUCCESS;
00703             }
00704             break;
00705         }
00706         default:
00707         {
00708             FIXME("unknown patch data type %u\n", info[i].ePatchDataType);
00709             info[i].dwOrder = i;
00710             info[i].uStatus = ERROR_SUCCESS;
00711             break;
00712         }
00713         }
00714 
00715         TRACE("szPatchData: %s\n", debugstr_w(info[i].szPatchData));
00716         TRACE("ePatchDataType: %u\n", info[i].ePatchDataType);
00717         TRACE("dwOrder: %u\n", info[i].dwOrder);
00718         TRACE("uStatus: %u\n", info[i].uStatus);
00719     }
00720 
00721     if (desc) IXMLDOMDocument_Release( desc );
00722 
00723     return ERROR_SUCCESS;
00724 }
00725 
00726 UINT WINAPI MsiDetermineApplicablePatchesW(LPCWSTR szProductPackagePath,
00727         DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOW pPatchInfo)
00728 {
00729     UINT r;
00730     MSIPACKAGE *package;
00731 
00732     TRACE("%s, %u, %p\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo);
00733 
00734     r = MSI_OpenPackageW( szProductPackagePath, &package );
00735     if (r != ERROR_SUCCESS)
00736     {
00737         ERR("failed to open package %u\n", r);
00738         return r;
00739     }
00740     r = determine_patch_sequence( package, cPatchInfo, pPatchInfo );
00741     msiobj_release( &package->hdr );
00742     return r;
00743 }
00744 
00745 UINT WINAPI MsiDeterminePatchSequenceA( LPCSTR product, LPCSTR usersid,
00746     MSIINSTALLCONTEXT context, DWORD count, PMSIPATCHSEQUENCEINFOA patchinfo )
00747 {
00748     UINT i, r;
00749     WCHAR *productW, *usersidW = NULL;
00750     MSIPATCHSEQUENCEINFOW *patchinfoW;
00751 
00752     TRACE("%s, %s, %d, %d, %p\n", debugstr_a(product), debugstr_a(usersid),
00753           context, count, patchinfo);
00754 
00755     if (!product) return ERROR_INVALID_PARAMETER;
00756     if (!(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
00757     if (usersid && !(usersidW = strdupAtoW( usersid )))
00758     {
00759         msi_free( productW );
00760         return ERROR_OUTOFMEMORY;
00761     }
00762     if (!(patchinfoW = patchinfoAtoW( count, patchinfo )))
00763     {
00764         msi_free( productW );
00765         msi_free( usersidW );
00766         return ERROR_OUTOFMEMORY;
00767     }
00768     r = MsiDeterminePatchSequenceW( productW, usersidW, context, count, patchinfoW );
00769     if (r == ERROR_SUCCESS)
00770     {
00771         for (i = 0; i < count; i++)
00772         {
00773             patchinfo[i].dwOrder = patchinfoW[i].dwOrder;
00774             patchinfo[i].uStatus = patchinfoW[i].uStatus;
00775         }
00776     }
00777     msi_free( productW );
00778     msi_free( usersidW );
00779     free_patchinfo( count, patchinfoW );
00780     return r;
00781 }
00782 
00783 static UINT open_package( const WCHAR *product, const WCHAR *usersid,
00784                           MSIINSTALLCONTEXT context, MSIPACKAGE **package )
00785 {
00786     UINT r;
00787     HKEY props;
00788     WCHAR *localpath, sourcepath[MAX_PATH], filename[MAX_PATH];
00789 
00790     r = MSIREG_OpenInstallProps( product, context, usersid, &props, FALSE );
00791     if (r != ERROR_SUCCESS) return ERROR_BAD_CONFIGURATION;
00792 
00793     if ((localpath = msi_reg_get_val_str( props, szLocalPackage )))
00794     {
00795         strcpyW( sourcepath, localpath );
00796         msi_free( localpath );
00797     }
00798     RegCloseKey( props );
00799     if (!localpath || GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
00800     {
00801         DWORD sz = sizeof(sourcepath);
00802         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
00803                                INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
00804         sz = sizeof(filename);
00805         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
00806                                INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
00807         strcatW( sourcepath, filename );
00808     }
00809     if (GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
00810         return ERROR_INSTALL_SOURCE_ABSENT;
00811 
00812     return MSI_OpenPackageW( sourcepath, package );
00813 }
00814 
00815 UINT WINAPI MsiDeterminePatchSequenceW( LPCWSTR product, LPCWSTR usersid,
00816     MSIINSTALLCONTEXT context, DWORD count, PMSIPATCHSEQUENCEINFOW patchinfo )
00817 {
00818     UINT r;
00819     MSIPACKAGE *package;
00820 
00821     TRACE("%s, %s, %d, %d, %p\n", debugstr_w(product), debugstr_w(usersid),
00822           context, count, patchinfo);
00823 
00824     if (!product) return ERROR_INVALID_PARAMETER;
00825     r = open_package( product, usersid, context, &package );
00826     if (r != ERROR_SUCCESS) return r;
00827 
00828     r = determine_patch_sequence( package, count, patchinfo );
00829     msiobj_release( &package->hdr );
00830     return r;
00831 }
00832 
00833 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
00834                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
00835 {
00836     MSIPACKAGE* package = NULL;
00837     MSIINSTALLCONTEXT context;
00838     UINT r;
00839     DWORD sz;
00840     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
00841     LPWSTR commandline;
00842 
00843     static const WCHAR szInstalled[] = {
00844         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
00845     static const WCHAR szMaxInstallLevel[] = {
00846         ' ','I','N','S','T','A','L','L','L','E','V','E','L','=','3','2','7','6','7',0};
00847     static const WCHAR szRemoveAll[] = {
00848         ' ','R','E','M','O','V','E','=','A','L','L',0};
00849     static const WCHAR szMachine[] = {
00850         ' ','A','L','L','U','S','E','R','S','=','1',0};
00851 
00852     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
00853           debugstr_w(szCommandLine));
00854 
00855     if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1)
00856         return ERROR_INVALID_PARAMETER;
00857 
00858     if (eInstallState == INSTALLSTATE_ADVERTISED ||
00859         eInstallState == INSTALLSTATE_SOURCE)
00860     {
00861         FIXME("State %d not implemented\n", eInstallState);
00862         return ERROR_CALL_NOT_IMPLEMENTED;
00863     }
00864 
00865     r = msi_locate_product(szProduct, &context);
00866     if (r != ERROR_SUCCESS)
00867         return r;
00868 
00869     r = open_package(szProduct, NULL, context, &package);
00870     if (r != ERROR_SUCCESS)
00871         return r;
00872 
00873     sz = lstrlenW(szInstalled) + 1;
00874 
00875     if (szCommandLine)
00876         sz += lstrlenW(szCommandLine);
00877 
00878     if (eInstallState != INSTALLSTATE_DEFAULT)
00879         sz += lstrlenW(szMaxInstallLevel);
00880 
00881     if (eInstallState == INSTALLSTATE_ABSENT)
00882         sz += lstrlenW(szRemoveAll);
00883 
00884     if (context == MSIINSTALLCONTEXT_MACHINE)
00885         sz += lstrlenW(szMachine);
00886 
00887     commandline = msi_alloc(sz * sizeof(WCHAR));
00888     if (!commandline)
00889     {
00890         r = ERROR_OUTOFMEMORY;
00891         goto end;
00892     }
00893 
00894     commandline[0] = 0;
00895     if (szCommandLine)
00896         lstrcpyW(commandline,szCommandLine);
00897 
00898     if (eInstallState != INSTALLSTATE_DEFAULT)
00899         lstrcatW(commandline, szMaxInstallLevel);
00900 
00901     if (eInstallState == INSTALLSTATE_ABSENT)
00902         lstrcatW(commandline, szRemoveAll);
00903 
00904     if (context == MSIINSTALLCONTEXT_MACHINE)
00905         lstrcatW(commandline, szMachine);
00906 
00907     sz = sizeof(sourcepath);
00908     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
00909                           INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
00910 
00911     sz = sizeof(filename);
00912     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
00913                           INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
00914 
00915     strcatW(sourcepath, filename);
00916 
00917     r = MSI_InstallPackage( package, sourcepath, commandline );
00918 
00919     msi_free(commandline);
00920 
00921 end:
00922     msiobj_release( &package->hdr );
00923 
00924     return r;
00925 }
00926 
00927 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
00928                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
00929 {
00930     LPWSTR szwProduct = NULL;
00931     LPWSTR szwCommandLine = NULL;
00932     UINT r = ERROR_OUTOFMEMORY;
00933 
00934     if( szProduct )
00935     {
00936         szwProduct = strdupAtoW( szProduct );
00937         if( !szwProduct )
00938             goto end;
00939     }
00940 
00941     if( szCommandLine)
00942     {
00943         szwCommandLine = strdupAtoW( szCommandLine );
00944         if( !szwCommandLine)
00945             goto end;
00946     }
00947 
00948     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
00949                                 szwCommandLine );
00950 end:
00951     msi_free( szwProduct );
00952     msi_free( szwCommandLine);
00953 
00954     return r;
00955 }
00956 
00957 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
00958                                  INSTALLSTATE eInstallState)
00959 {
00960     LPWSTR szwProduct = NULL;
00961     UINT r;
00962 
00963     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
00964 
00965     if( szProduct )
00966     {
00967         szwProduct = strdupAtoW( szProduct );
00968         if( !szwProduct )
00969             return ERROR_OUTOFMEMORY;
00970     }
00971 
00972     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
00973     msi_free( szwProduct );
00974 
00975     return r;
00976 }
00977 
00978 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
00979                                  INSTALLSTATE eInstallState)
00980 {
00981     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
00982 }
00983 
00984 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
00985 {
00986     LPWSTR szwComponent = NULL;
00987     UINT r;
00988     WCHAR szwBuffer[GUID_SIZE];
00989 
00990     TRACE("%s %p\n", debugstr_a(szComponent), szBuffer);
00991 
00992     if( szComponent )
00993     {
00994         szwComponent = strdupAtoW( szComponent );
00995         if( !szwComponent )
00996             return ERROR_OUTOFMEMORY;
00997     }
00998 
00999     *szwBuffer = '\0';
01000     r = MsiGetProductCodeW( szwComponent, szwBuffer );
01001 
01002     if(*szwBuffer)
01003         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
01004 
01005     msi_free( szwComponent );
01006 
01007     return r;
01008 }
01009 
01010 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
01011 {
01012     UINT rc, index;
01013     HKEY compkey, prodkey;
01014     WCHAR squished_comp[GUID_SIZE];
01015     WCHAR squished_prod[GUID_SIZE];
01016     DWORD sz = GUID_SIZE;
01017 
01018     TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
01019 
01020     if (!szComponent || !*szComponent)
01021         return ERROR_INVALID_PARAMETER;
01022 
01023     if (!squash_guid(szComponent, squished_comp))
01024         return ERROR_INVALID_PARAMETER;
01025 
01026     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &compkey, FALSE) != ERROR_SUCCESS &&
01027         MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &compkey, FALSE) != ERROR_SUCCESS)
01028     {
01029         return ERROR_UNKNOWN_COMPONENT;
01030     }
01031 
01032     rc = RegEnumValueW(compkey, 0, squished_prod, &sz, NULL, NULL, NULL, NULL);
01033     if (rc != ERROR_SUCCESS)
01034     {
01035         RegCloseKey(compkey);
01036         return ERROR_UNKNOWN_COMPONENT;
01037     }
01038 
01039     /* check simple case, only one product */
01040     rc = RegEnumValueW(compkey, 1, squished_prod, &sz, NULL, NULL, NULL, NULL);
01041     if (rc == ERROR_NO_MORE_ITEMS)
01042     {
01043         rc = ERROR_SUCCESS;
01044         goto done;
01045     }
01046 
01047     index = 0;
01048     while ((rc = RegEnumValueW(compkey, index, squished_prod, &sz,
01049            NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS)
01050     {
01051         index++;
01052         sz = GUID_SIZE;
01053         unsquash_guid(squished_prod, szBuffer);
01054 
01055         if (MSIREG_OpenProductKey(szBuffer, NULL,
01056                                   MSIINSTALLCONTEXT_USERMANAGED,
01057                                   &prodkey, FALSE) == ERROR_SUCCESS ||
01058             MSIREG_OpenProductKey(szBuffer, NULL,
01059                                   MSIINSTALLCONTEXT_USERUNMANAGED,
01060                                   &prodkey, FALSE) == ERROR_SUCCESS ||
01061             MSIREG_OpenProductKey(szBuffer, NULL,
01062                                   MSIINSTALLCONTEXT_MACHINE,
01063                                   &prodkey, FALSE) == ERROR_SUCCESS)
01064         {
01065             RegCloseKey(prodkey);
01066             rc = ERROR_SUCCESS;
01067             goto done;
01068         }
01069     }
01070 
01071     rc = ERROR_INSTALL_FAILURE;
01072 
01073 done:
01074     RegCloseKey(compkey);
01075     unsquash_guid(squished_prod, szBuffer);
01076     return rc;
01077 }
01078 
01079 static LPWSTR msi_reg_get_value(HKEY hkey, LPCWSTR name, DWORD *type)
01080 {
01081     DWORD dval;
01082     LONG res;
01083     WCHAR temp[20];
01084 
01085     static const WCHAR format[] = {'%','d',0};
01086 
01087     res = RegQueryValueExW(hkey, name, NULL, type, NULL, NULL);
01088     if (res != ERROR_SUCCESS)
01089         return NULL;
01090 
01091     if (*type == REG_SZ)
01092         return msi_reg_get_val_str(hkey, name);
01093 
01094     if (!msi_reg_get_val_dword(hkey, name, &dval))
01095         return NULL;
01096 
01097     sprintfW(temp, format, dval);
01098     return strdupW(temp);
01099 }
01100 
01101 static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
01102                                awstring *szValue, LPDWORD pcchValueBuf)
01103 {
01104     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
01105     UINT r = ERROR_UNKNOWN_PROPERTY;
01106     HKEY prodkey, userdata, source;
01107     LPWSTR val = NULL;
01108     WCHAR squished_pc[GUID_SIZE];
01109     WCHAR packagecode[GUID_SIZE];
01110     BOOL badconfig = FALSE;
01111     LONG res;
01112     DWORD type = REG_NONE;
01113 
01114     static WCHAR empty[] = {0};
01115     static const WCHAR sourcelist[] = {
01116         'S','o','u','r','c','e','L','i','s','t',0};
01117     static const WCHAR display_name[] = {
01118         'D','i','s','p','l','a','y','N','a','m','e',0};
01119     static const WCHAR display_version[] = {
01120         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
01121     static const WCHAR assignment[] = {
01122         'A','s','s','i','g','n','m','e','n','t',0};
01123 
01124     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
01125           debugstr_w(szAttribute), szValue, pcchValueBuf);
01126 
01127     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
01128         return ERROR_INVALID_PARAMETER;
01129 
01130     if (!squash_guid(szProduct, squished_pc))
01131         return ERROR_INVALID_PARAMETER;
01132 
01133     if ((r = MSIREG_OpenProductKey(szProduct, NULL,
01134                                    MSIINSTALLCONTEXT_USERMANAGED,
01135                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
01136         (r = MSIREG_OpenProductKey(szProduct, NULL,
01137                                    MSIINSTALLCONTEXT_USERUNMANAGED,
01138                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
01139         (r = MSIREG_OpenProductKey(szProduct, NULL,
01140                                    MSIINSTALLCONTEXT_MACHINE,
01141                                     &prodkey, FALSE)) == ERROR_SUCCESS)
01142     {
01143         context = MSIINSTALLCONTEXT_MACHINE;
01144     }
01145 
01146     MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
01147 
01148     if (!strcmpW( szAttribute, INSTALLPROPERTY_HELPLINKW ) ||
01149         !strcmpW( szAttribute, INSTALLPROPERTY_HELPTELEPHONEW ) ||
01150         !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLDATEW ) ||
01151         !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
01152         !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
01153         !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLSOURCEW ) ||
01154         !strcmpW( szAttribute, INSTALLPROPERTY_LOCALPACKAGEW ) ||
01155         !strcmpW( szAttribute, INSTALLPROPERTY_PUBLISHERW ) ||
01156         !strcmpW( szAttribute, INSTALLPROPERTY_URLINFOABOUTW ) ||
01157         !strcmpW( szAttribute, INSTALLPROPERTY_URLUPDATEINFOW ) ||
01158         !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMINORW ) ||
01159         !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMAJORW ) ||
01160         !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ) ||
01161         !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTIDW ) ||
01162         !strcmpW( szAttribute, INSTALLPROPERTY_REGCOMPANYW ) ||
01163         !strcmpW( szAttribute, INSTALLPROPERTY_REGOWNERW ))
01164     {
01165         if (!prodkey)
01166         {
01167             r = ERROR_UNKNOWN_PRODUCT;
01168             goto done;
01169         }
01170 
01171         if (!userdata)
01172             return ERROR_UNKNOWN_PROPERTY;
01173 
01174         if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
01175             szAttribute = display_name;
01176         else if (!strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
01177             szAttribute = display_version;
01178 
01179         val = msi_reg_get_value(userdata, szAttribute, &type);
01180         if (!val)
01181             val = empty;
01182     }
01183     else if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTANCETYPEW ) ||
01184              !strcmpW( szAttribute, INSTALLPROPERTY_TRANSFORMSW ) ||
01185              !strcmpW( szAttribute, INSTALLPROPERTY_LANGUAGEW ) ||
01186              !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTNAMEW ) ||
01187              !strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ) ||
01188              !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ) ||
01189              !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONW ) ||
01190              !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTICONW ) ||
01191              !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ) ||
01192              !strcmpW( szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
01193     {
01194         if (!prodkey)
01195         {
01196             r = ERROR_UNKNOWN_PRODUCT;
01197             goto done;
01198         }
01199 
01200         if (!strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
01201             szAttribute = assignment;
01202 
01203         if (!strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ))
01204         {
01205             res = RegOpenKeyW(prodkey, sourcelist, &source);
01206             if (res != ERROR_SUCCESS)
01207             {
01208                 r = ERROR_UNKNOWN_PRODUCT;
01209                 goto done;
01210             }
01211 
01212             val = msi_reg_get_value(source, szAttribute, &type);
01213             if (!val)
01214                 val = empty;
01215 
01216             RegCloseKey(source);
01217         }
01218         else
01219         {
01220             val = msi_reg_get_value(prodkey, szAttribute, &type);
01221             if (!val)
01222                 val = empty;
01223         }
01224 
01225         if (val != empty && type != REG_DWORD &&
01226             !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
01227         {
01228             if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
01229                 badconfig = TRUE;
01230             else
01231             {
01232                 unsquash_guid(val, packagecode);
01233                 msi_free(val);
01234                 val = strdupW(packagecode);
01235             }
01236         }
01237     }
01238 
01239     if (!val)
01240     {
01241         r = ERROR_UNKNOWN_PROPERTY;
01242         goto done;
01243     }
01244 
01245     if (pcchValueBuf)
01246     {
01247         /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
01248          * out.  Also, *pcchValueBuf may be uninitialized in this case, so we
01249          * can't rely on its value.
01250          */
01251         if (szValue->str.a || szValue->str.w)
01252         {
01253             DWORD size = *pcchValueBuf;
01254             if (strlenW(val) < size)
01255                 r = msi_strcpy_to_awstring(val, szValue, &size);
01256             else
01257             {
01258                 r = ERROR_MORE_DATA;
01259             }
01260         }
01261 
01262         if (!badconfig)
01263             *pcchValueBuf = lstrlenW(val);
01264     }
01265 
01266     if (badconfig)
01267         r = ERROR_BAD_CONFIGURATION;
01268 
01269     if (val != empty)
01270         msi_free(val);
01271 
01272 done:
01273     RegCloseKey(prodkey);
01274     RegCloseKey(userdata);
01275     return r;
01276 }
01277 
01278 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
01279                                LPSTR szBuffer, LPDWORD pcchValueBuf)
01280 {
01281     LPWSTR szwProduct, szwAttribute = NULL;
01282     UINT r = ERROR_OUTOFMEMORY;
01283     awstring buffer;
01284 
01285     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
01286           szBuffer, pcchValueBuf);
01287 
01288     szwProduct = strdupAtoW( szProduct );
01289     if( szProduct && !szwProduct )
01290         goto end;
01291 
01292     szwAttribute = strdupAtoW( szAttribute );
01293     if( szAttribute && !szwAttribute )
01294         goto end;
01295 
01296     buffer.unicode = FALSE;
01297     buffer.str.a = szBuffer;
01298 
01299     r = MSI_GetProductInfo( szwProduct, szwAttribute,
01300                             &buffer, pcchValueBuf );
01301 
01302 end:
01303     msi_free( szwProduct );
01304     msi_free( szwAttribute );
01305 
01306     return r;
01307 }
01308 
01309 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
01310                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
01311 {
01312     awstring buffer;
01313 
01314     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
01315           szBuffer, pcchValueBuf);
01316 
01317     buffer.unicode = TRUE;
01318     buffer.str.w = szBuffer;
01319 
01320     return MSI_GetProductInfo( szProduct, szAttribute,
01321                                &buffer, pcchValueBuf );
01322 }
01323 
01324 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
01325                                  MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
01326                                  LPSTR szValue, LPDWORD pcchValue)
01327 {
01328     LPWSTR product = NULL;
01329     LPWSTR usersid = NULL;
01330     LPWSTR property = NULL;
01331     LPWSTR value = NULL;
01332     DWORD len = 0;
01333     UINT r;
01334 
01335     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
01336           debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
01337            szValue, pcchValue);
01338 
01339     if (szValue && !pcchValue)
01340         return ERROR_INVALID_PARAMETER;
01341 
01342     if (szProductCode) product = strdupAtoW(szProductCode);
01343     if (szUserSid) usersid = strdupAtoW(szUserSid);
01344     if (szProperty) property = strdupAtoW(szProperty);
01345 
01346     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
01347                              NULL, &len);
01348     if (r != ERROR_SUCCESS)
01349         goto done;
01350 
01351     value = msi_alloc(++len * sizeof(WCHAR));
01352     if (!value)
01353     {
01354         r = ERROR_OUTOFMEMORY;
01355         goto done;
01356     }
01357 
01358     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
01359                              value, &len);
01360     if (r != ERROR_SUCCESS)
01361         goto done;
01362 
01363     if (!pcchValue)
01364         goto done;
01365 
01366     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
01367     if (*pcchValue >= len)
01368         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
01369     else if (szValue)
01370     {
01371         r = ERROR_MORE_DATA;
01372         if (*pcchValue > 0)
01373             *szValue = '\0';
01374     }
01375 
01376     if (*pcchValue <= len || !szValue)
01377         len = len * sizeof(WCHAR) - 1;
01378 
01379     *pcchValue = len - 1;
01380 
01381 done:
01382     msi_free(product);
01383     msi_free(usersid);
01384     msi_free(property);
01385     msi_free(value);
01386 
01387     return r;
01388 }
01389 
01390 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
01391 {
01392     UINT r = ERROR_SUCCESS;
01393 
01394     if (!val)
01395         return ERROR_UNKNOWN_PROPERTY;
01396 
01397     if (out)
01398     {
01399         if (strlenW(val) >= *size)
01400         {
01401             r = ERROR_MORE_DATA;
01402             if (*size > 0)
01403                 *out = '\0';
01404         }
01405         else
01406             lstrcpyW(out, val);
01407     }
01408 
01409     if (size)
01410         *size = lstrlenW(val);
01411 
01412     return r;
01413 }
01414 
01415 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
01416                                  MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
01417                                  LPWSTR szValue, LPDWORD pcchValue)
01418 {
01419     WCHAR squished_pc[GUID_SIZE];
01420     LPWSTR val = NULL;
01421     LPCWSTR package = NULL;
01422     HKEY props = NULL, prod;
01423     HKEY classes = NULL, managed;
01424     HKEY hkey = NULL;
01425     DWORD type;
01426     UINT r = ERROR_UNKNOWN_PRODUCT;
01427 
01428     static const WCHAR five[] = {'5',0};
01429     static const WCHAR displayname[] = {
01430         'D','i','s','p','l','a','y','N','a','m','e',0};
01431     static const WCHAR displayversion[] = {
01432         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
01433     static const WCHAR managed_local_package[] = {
01434         'M','a','n','a','g','e','d','L','o','c','a','l',
01435         'P','a','c','k','a','g','e',0};
01436 
01437     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
01438           debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
01439            szValue, pcchValue);
01440 
01441     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
01442         return ERROR_INVALID_PARAMETER;
01443 
01444     if (szValue && !pcchValue)
01445         return ERROR_INVALID_PARAMETER;
01446 
01447     if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
01448         dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
01449         dwContext != MSIINSTALLCONTEXT_MACHINE)
01450         return ERROR_INVALID_PARAMETER;
01451 
01452     if (!szProperty || !*szProperty)
01453         return ERROR_INVALID_PARAMETER;
01454 
01455     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
01456         return ERROR_INVALID_PARAMETER;
01457 
01458     /* FIXME: dwContext is provided, no need to search for it */
01459     MSIREG_OpenProductKey(szProductCode, NULL,MSIINSTALLCONTEXT_USERMANAGED,
01460                           &managed, FALSE);
01461     MSIREG_OpenProductKey(szProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
01462                           &prod, FALSE);
01463 
01464     MSIREG_OpenInstallProps(szProductCode, dwContext, NULL, &props, FALSE);
01465 
01466     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
01467     {
01468         package = INSTALLPROPERTY_LOCALPACKAGEW;
01469 
01470         if (!props && !prod)
01471             goto done;
01472     }
01473     else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
01474     {
01475         package = managed_local_package;
01476 
01477         if (!props && !managed)
01478             goto done;
01479     }
01480     else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
01481     {
01482         package = INSTALLPROPERTY_LOCALPACKAGEW;
01483         MSIREG_OpenProductKey(szProductCode, NULL, dwContext, &classes, FALSE);
01484 
01485         if (!props && !classes)
01486             goto done;
01487     }
01488 
01489     if (!strcmpW( szProperty, INSTALLPROPERTY_HELPLINKW ) ||
01490         !strcmpW( szProperty, INSTALLPROPERTY_HELPTELEPHONEW ) ||
01491         !strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ) ||
01492         !strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
01493         !strcmpW( szProperty, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
01494         !strcmpW( szProperty, INSTALLPROPERTY_INSTALLSOURCEW ) ||
01495         !strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ) ||
01496         !strcmpW( szProperty, INSTALLPROPERTY_PUBLISHERW ) ||
01497         !strcmpW( szProperty, INSTALLPROPERTY_URLINFOABOUTW ) ||
01498         !strcmpW( szProperty, INSTALLPROPERTY_URLUPDATEINFOW ) ||
01499         !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMINORW ) ||
01500         !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMAJORW ) ||
01501         !strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ) ||
01502         !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTIDW ) ||
01503         !strcmpW( szProperty, INSTALLPROPERTY_REGCOMPANYW ) ||
01504         !strcmpW( szProperty, INSTALLPROPERTY_REGOWNERW ) ||
01505         !strcmpW( szProperty, INSTALLPROPERTY_INSTANCETYPEW ))
01506     {
01507         val = msi_reg_get_value(props, package, &type);
01508         if (!val)
01509         {
01510             if (prod || classes)
01511                 r = ERROR_UNKNOWN_PROPERTY;
01512 
01513             goto done;
01514         }
01515 
01516         msi_free(val);
01517 
01518         if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
01519             szProperty = displayname;
01520         else if (!strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ))
01521             szProperty = displayversion;
01522 
01523         val = msi_reg_get_value(props, szProperty, &type);
01524         if (!val)
01525             val = strdupW(szEmpty);
01526 
01527         r = msi_copy_outval(val, szValue, pcchValue);
01528     }
01529     else if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ) ||
01530              !strcmpW( szProperty, INSTALLPROPERTY_LANGUAGEW ) ||
01531              !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTNAMEW ) ||
01532              !strcmpW( szProperty, INSTALLPROPERTY_PACKAGECODEW ) ||
01533              !strcmpW( szProperty, INSTALLPROPERTY_VERSIONW ) ||
01534              !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTICONW ) ||
01535              !strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ) ||
01536              !strcmpW( szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
01537     {
01538         if (!prod && !classes)
01539             goto done;
01540 
01541         if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
01542             hkey = prod;
01543         else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
01544             hkey = managed;
01545         else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
01546             hkey = classes;
01547 
01548         val = msi_reg_get_value(hkey, szProperty, &type);
01549         if (!val)
01550             val = strdupW(szEmpty);
01551 
01552         r = msi_copy_outval(val, szValue, pcchValue);
01553     }
01554     else if (!strcmpW( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
01555     {
01556         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
01557         {
01558             if (props)
01559             {
01560                 val = msi_reg_get_value(props, package, &type);
01561                 if (!val)
01562                     goto done;
01563 
01564                 msi_free(val);
01565                 val = strdupW(five);
01566             }
01567             else
01568                 val = strdupW(szOne);
01569 
01570             r = msi_copy_outval(val, szValue, pcchValue);
01571             goto done;
01572         }
01573         else if (props && (val = msi_reg_get_value(props, package, &type)))
01574         {
01575             msi_free(val);
01576             val = strdupW(five);
01577             r = msi_copy_outval(val, szValue, pcchValue);
01578             goto done;
01579         }
01580 
01581         if (prod || managed)
01582             val = strdupW(szOne);
01583         else
01584             goto done;
01585 
01586         r = msi_copy_outval(val, szValue, pcchValue);
01587     }
01588     else if (!strcmpW( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
01589     {
01590         if (!prod && !classes)
01591             goto done;
01592 
01593         /* FIXME */
01594         val = strdupW(szEmpty);
01595         r = msi_copy_outval(val, szValue, pcchValue);
01596     }
01597     else
01598         r = ERROR_UNKNOWN_PROPERTY;
01599 
01600 done:
01601     RegCloseKey(props);
01602     RegCloseKey(prod);
01603     RegCloseKey(managed);
01604     RegCloseKey(classes);
01605     msi_free(val);
01606 
01607     return r;
01608 }
01609 
01610 UINT WINAPI MsiGetPatchInfoExA(LPCSTR szPatchCode, LPCSTR szProductCode,
01611                                LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
01612                                LPCSTR szProperty, LPSTR lpValue, DWORD *pcchValue)
01613 {
01614     LPWSTR patch = NULL, product = NULL, usersid = NULL;
01615     LPWSTR property = NULL, val = NULL;
01616     DWORD len;
01617     UINT r;
01618 
01619     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_a(szPatchCode),
01620           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext,
01621           debugstr_a(szProperty), lpValue, pcchValue);
01622 
01623     if (lpValue && !pcchValue)
01624         return ERROR_INVALID_PARAMETER;
01625 
01626     if (szPatchCode) patch = strdupAtoW(szPatchCode);
01627     if (szProductCode) product = strdupAtoW(szProductCode);
01628     if (szUserSid) usersid = strdupAtoW(szUserSid);
01629     if (szProperty) property = strdupAtoW(szProperty);
01630 
01631     len = 0;
01632     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
01633                            NULL, &len);
01634     if (r != ERROR_SUCCESS)
01635         goto done;
01636 
01637     val = msi_alloc(++len * sizeof(WCHAR));
01638     if (!val)
01639     {
01640         r = ERROR_OUTOFMEMORY;
01641         goto done;
01642     }
01643 
01644     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
01645                            val, &len);
01646     if (r != ERROR_SUCCESS || !pcchValue)
01647         goto done;
01648 
01649     if (lpValue)
01650         WideCharToMultiByte(CP_ACP, 0, val, -1, lpValue,
01651                             *pcchValue - 1, NULL, NULL);
01652 
01653     len = lstrlenW(val);
01654     if ((*val && *pcchValue < len + 1) || !lpValue)
01655     {
01656         if (lpValue)
01657         {
01658             r = ERROR_MORE_DATA;
01659             lpValue[*pcchValue - 1] = '\0';
01660         }
01661 
01662         *pcchValue = len * sizeof(WCHAR);
01663     }
01664     else
01665         *pcchValue = len;
01666 
01667 done:
01668     msi_free(val);
01669     msi_free(patch);
01670     msi_free(product);
01671     msi_free(usersid);
01672     msi_free(property);
01673 
01674     return r;
01675 }
01676 
01677 UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
01678                                LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
01679                                LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
01680 {
01681     WCHAR squished_pc[GUID_SIZE];
01682     WCHAR squished_patch[GUID_SIZE];
01683     HKEY udprod = 0, prod = 0, props = 0;
01684     HKEY patch = 0, patches = 0;
01685     HKEY udpatch = 0, datakey = 0;
01686     HKEY prodpatches = 0;
01687     LPWSTR val = NULL;
01688     UINT r = ERROR_UNKNOWN_PRODUCT;
01689     DWORD len;
01690     LONG res;
01691 
01692     static const WCHAR szManagedPackage[] = {'M','a','n','a','g','e','d',
01693         'L','o','c','a','l','P','a','c','k','a','g','e',0};
01694 
01695     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_w(szPatchCode),
01696           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext,
01697           debugstr_w(szProperty), lpValue, pcchValue);
01698 
01699     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
01700         return ERROR_INVALID_PARAMETER;
01701 
01702     if (!szPatchCode || !squash_guid(szPatchCode, squished_patch))
01703         return ERROR_INVALID_PARAMETER;
01704 
01705     if (!szProperty)
01706         return ERROR_INVALID_PARAMETER;
01707 
01708     if (lpValue && !pcchValue)
01709         return ERROR_INVALID_PARAMETER;
01710 
01711     if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
01712         dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
01713         dwContext != MSIINSTALLCONTEXT_MACHINE)
01714         return ERROR_INVALID_PARAMETER;
01715 
01716     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
01717         return ERROR_INVALID_PARAMETER;
01718 
01719     if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
01720         return ERROR_INVALID_PARAMETER;
01721 
01722     if (MSIREG_OpenUserDataProductKey(szProductCode, dwContext, NULL,
01723                                       &udprod, FALSE) != ERROR_SUCCESS)
01724         goto done;
01725 
01726     if (MSIREG_OpenInstallProps(szProductCode, dwContext, NULL,
01727                                 &props, FALSE) != ERROR_SUCCESS)
01728         goto done;
01729 
01730     r = ERROR_UNKNOWN_PATCH;
01731 
01732     res = RegOpenKeyExW(udprod, szPatches, 0, KEY_WOW64_64KEY|KEY_READ, &patches);
01733     if (res != ERROR_SUCCESS)
01734         goto done;
01735 
01736     res = RegOpenKeyExW(patches, squished_patch, 0, KEY_WOW64_64KEY|KEY_READ, &patch);
01737     if (res != ERROR_SUCCESS)
01738         goto done;
01739 
01740     if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ))
01741     {
01742         if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
01743                                   &prod, FALSE) != ERROR_SUCCESS)
01744             goto done;
01745 
01746         res = RegOpenKeyExW(prod, szPatches, 0, KEY_WOW64_64KEY|KEY_ALL_ACCESS, &prodpatches);
01747         if (res != ERROR_SUCCESS)
01748             goto done;
01749 
01750         datakey = prodpatches;
01751         szProperty = squished_patch;
01752     }
01753     else
01754     {
01755         if (MSIREG_OpenUserDataPatchKey(szPatchCode, dwContext,
01756                                         &udpatch, FALSE) != ERROR_SUCCESS)
01757             goto done;
01758 
01759         if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
01760         {
01761             if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
01762                 szProperty = szManagedPackage;
01763             datakey = udpatch;
01764         }
01765         else if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ))
01766         {
01767             datakey = patch;
01768             szProperty = szInstalled;
01769         }
01770         else if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
01771         {
01772             datakey = udpatch;
01773         }
01774         else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
01775                  !strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
01776                  !strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
01777                  !strcmpW( szProperty, INSTALLPROPERTY_MOREINFOURLW ))
01778         {
01779             datakey = patch;
01780         }
01781         else
01782         {
01783             r = ERROR_UNKNOWN_PROPERTY;
01784             goto done;
01785         }
01786     }
01787 
01788     val = msi_reg_get_val_str(datakey, szProperty);
01789     if (!val)
01790         val = strdupW(szEmpty);
01791 
01792     r = ERROR_SUCCESS;
01793 
01794     if (!pcchValue)
01795         goto done;
01796 
01797     if (lpValue)
01798         lstrcpynW(lpValue, val, *pcchValue);
01799 
01800     len = lstrlenW(val);
01801     if ((*val && *pcchValue < len + 1) || !lpValue)
01802     {
01803         if (lpValue)
01804             r = ERROR_MORE_DATA;
01805 
01806         *pcchValue = len * sizeof(WCHAR);
01807     }
01808 
01809     *pcchValue = len;
01810 
01811 done:
01812     msi_free(val);
01813     RegCloseKey(prodpatches);
01814     RegCloseKey(prod);
01815     RegCloseKey(patch);
01816     RegCloseKey(patches);
01817     RegCloseKey(udpatch);
01818     RegCloseKey(props);
01819     RegCloseKey(udprod);
01820 
01821     return r;
01822 }
01823 
01824 UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen )
01825 {
01826     UINT r = ERROR_OUTOFMEMORY;
01827     DWORD size;
01828     LPWSTR patchW = NULL, attrW = NULL, bufferW = NULL;
01829 
01830     TRACE("%s %s %p %p\n", debugstr_a(patch), debugstr_a(attr), buffer, buflen);
01831 
01832     if (!patch || !attr)
01833         return ERROR_INVALID_PARAMETER;
01834 
01835     if (!(patchW = strdupAtoW( patch )))
01836         goto done;
01837 
01838     if (!(attrW = strdupAtoW( attr )))
01839         goto done;
01840 
01841     size = 0;
01842     r = MsiGetPatchInfoW( patchW, attrW, NULL, &size );
01843     if (r != ERROR_SUCCESS)
01844         goto done;
01845 
01846     size++;
01847     if (!(bufferW = msi_alloc( size * sizeof(WCHAR) )))
01848     {
01849         r = ERROR_OUTOFMEMORY;
01850         goto done;
01851     }
01852 
01853     r = MsiGetPatchInfoW( patchW, attrW, bufferW, &size );
01854     if (r == ERROR_SUCCESS)
01855     {
01856         int len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
01857         if (len > *buflen)
01858             r = ERROR_MORE_DATA;
01859         else if (buffer)
01860             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL );
01861 
01862         *buflen = len - 1;
01863     }
01864 
01865 done:
01866     msi_free( patchW );
01867     msi_free( attrW );
01868     msi_free( bufferW );
01869     return r;
01870 }
01871 
01872 UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen )
01873 {
01874     UINT r;
01875     WCHAR product[GUID_SIZE];
01876     DWORD index;
01877 
01878     TRACE("%s %s %p %p\n", debugstr_w(patch), debugstr_w(attr), buffer, buflen);
01879 
01880     if (!patch || !attr)
01881         return ERROR_INVALID_PARAMETER;
01882 
01883     if (strcmpW( INSTALLPROPERTY_LOCALPACKAGEW, attr ))
01884         return ERROR_UNKNOWN_PROPERTY;
01885 
01886     index = 0;
01887     while (1)
01888     {
01889         r = MsiEnumProductsW( index, product );
01890         if (r != ERROR_SUCCESS)
01891             break;
01892 
01893         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERMANAGED, attr, buffer, buflen );
01894         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
01895             return r;
01896 
01897         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, attr, buffer, buflen );
01898         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
01899             return r;
01900 
01901         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_MACHINE, attr, buffer, buflen );
01902         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
01903             return r;
01904 
01905         index++;
01906     }
01907 
01908     return ERROR_UNKNOWN_PRODUCT;
01909 }
01910 
01911 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
01912 {
01913     LPWSTR szwLogFile = NULL;
01914     UINT r;
01915 
01916     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
01917 
01918     if( szLogFile )
01919     {
01920         szwLogFile = strdupAtoW( szLogFile );
01921         if( !szwLogFile )
01922             return ERROR_OUTOFMEMORY;
01923     }
01924     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
01925     msi_free( szwLogFile );
01926     return r;
01927 }
01928 
01929 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
01930 {
01931     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
01932 
01933     msi_free(gszLogFile);
01934     gszLogFile = NULL;
01935     if (szLogFile)
01936     {
01937         HANDLE file;
01938 
01939         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
01940             DeleteFileW(szLogFile);
01941         file = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
01942                            FILE_ATTRIBUTE_NORMAL, NULL);
01943         if (file != INVALID_HANDLE_VALUE)
01944         {
01945             gszLogFile = strdupW(szLogFile);
01946             CloseHandle(file);
01947         }
01948         else
01949             ERR("Unable to enable log %s (%u)\n", debugstr_w(szLogFile), GetLastError());
01950     }
01951 
01952     return ERROR_SUCCESS;
01953 }
01954 
01955 UINT WINAPI MsiEnumComponentCostsA( MSIHANDLE handle, LPCSTR component, DWORD index,
01956                                     INSTALLSTATE state, LPSTR drive, DWORD *buflen,
01957                                     int *cost, int *temp )
01958 {
01959     UINT r;
01960     DWORD len;
01961     WCHAR *driveW, *componentW = NULL;
01962 
01963     TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_a(component), index,
01964           state, drive, buflen, cost, temp);
01965 
01966     if (!drive || !buflen) return ERROR_INVALID_PARAMETER;
01967     if (component && !(componentW = strdupAtoW( component ))) return ERROR_OUTOFMEMORY;
01968 
01969     len = *buflen;
01970     if (!(driveW = msi_alloc( len * sizeof(WCHAR) )))
01971     {
01972         msi_free( componentW );
01973         return ERROR_OUTOFMEMORY;
01974     }
01975     r = MsiEnumComponentCostsW( handle, componentW, index, state, driveW, buflen, cost, temp );
01976     if (!r)
01977     {
01978         WideCharToMultiByte( CP_ACP, 0, driveW, -1, drive, len, NULL, NULL );
01979     }
01980     msi_free( componentW );
01981     msi_free( driveW );
01982     return r;
01983 }
01984 
01985 static UINT set_drive( WCHAR *buffer, WCHAR letter )
01986 {
01987     buffer[0] = letter;
01988     buffer[1] = ':';
01989     buffer[2] = 0;
01990     return 2;
01991 }
01992 
01993 UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD index,
01994                                     INSTALLSTATE state, LPWSTR drive, DWORD *buflen,
01995                                     int *cost, int *temp )
01996 {
01997     UINT r = ERROR_NO_MORE_ITEMS;
01998     MSICOMPONENT *comp = NULL;
01999     MSIPACKAGE *package;
02000     MSIFILE *file;
02001     STATSTG stat = {0};
02002     WCHAR path[MAX_PATH];
02003 
02004     TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_w(component), index,
02005           state, drive, buflen, cost, temp);
02006 
02007     if (!drive || !buflen || !cost || !temp) return ERROR_INVALID_PARAMETER;
02008     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
02009     {
02010         HRESULT hr;
02011         IWineMsiRemotePackage *remote_package;
02012         BSTR bname = NULL;
02013 
02014         if (!(remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle )))
02015             return ERROR_INVALID_HANDLE;
02016 
02017         if (component && !(bname = SysAllocString( component )))
02018         {
02019             IWineMsiRemotePackage_Release( remote_package );
02020             return ERROR_OUTOFMEMORY;
02021         }
02022         hr = IWineMsiRemotePackage_EnumComponentCosts( remote_package, bname, index, state, drive, buflen, cost, temp );
02023         IWineMsiRemotePackage_Release( remote_package );
02024         SysFreeString( bname );
02025         if (FAILED(hr))
02026         {
02027             if (HRESULT_FACILITY(hr) == FACILITY_WIN32) return HRESULT_CODE(hr);
02028             return ERROR_FUNCTION_FAILED;
02029         }
02030         return ERROR_SUCCESS;
02031     }
02032 
02033     if (!msi_get_property_int( package->db, szCostingComplete, 0 ))
02034     {
02035         msiobj_release( &package->hdr );
02036         return ERROR_FUNCTION_NOT_CALLED;
02037     }
02038     if (component && component[0] && !(comp = msi_get_loaded_component( package, component )))
02039     {
02040         msiobj_release( &package->hdr );
02041         return ERROR_UNKNOWN_COMPONENT;
02042     }
02043     if (*buflen < 3)
02044     {
02045         *buflen = 2;
02046         msiobj_release( &package->hdr );
02047         return ERROR_MORE_DATA;
02048     }
02049     if (index)
02050     {
02051         msiobj_release( &package->hdr );
02052         return ERROR_NO_MORE_ITEMS;
02053     }
02054 
02055     drive[0] = 0;
02056     *cost = *temp = 0;
02057     GetWindowsDirectoryW( path, MAX_PATH );
02058     if (component && component[0])
02059     {
02060         if (comp->assembly && !comp->assembly->application) *temp = comp->Cost;
02061         if (!comp->Enabled || !comp->KeyPath)
02062         {
02063             *cost = 0;
02064             *buflen = set_drive( drive, path[0] );
02065             r = ERROR_SUCCESS;
02066         }
02067         else if ((file = msi_get_loaded_file( package, comp->KeyPath )))
02068         {
02069             *cost = max( 8, comp->Cost / 512 );
02070             *buflen = set_drive( drive, file->TargetPath[0] );
02071             r = ERROR_SUCCESS;
02072         }
02073     }
02074     else if (IStorage_Stat( package->db->storage, &stat, STATFLAG_NONAME ) == S_OK)
02075     {
02076         *temp = max( 8, stat.cbSize.QuadPart / 512 );
02077         *buflen = set_drive( drive, path[0] );
02078         r = ERROR_SUCCESS;
02079     }
02080     msiobj_release( &package->hdr );
02081     return r;
02082 }
02083 
02084 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
02085                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
02086                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
02087 {
02088     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
02089     UINT r;
02090 
02091     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
02092           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
02093 
02094     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
02095         return ERROR_OUTOFMEMORY;
02096 
02097     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
02098             return ERROR_OUTOFMEMORY;
02099 
02100     if (szComponent && !(comp = strdupAtoW(szComponent)))
02101             return ERROR_OUTOFMEMORY;
02102 
02103     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
02104 
02105     msi_free(prodcode);
02106     msi_free(usersid);
02107     msi_free(comp);
02108 
02109     return r;
02110 }
02111 
02112 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
02113 {
02114     UINT r;
02115     HKEY hkey = NULL;
02116 
02117     r = MSIREG_OpenProductKey(prodcode, NULL, context, &hkey, FALSE);
02118     RegCloseKey(hkey);
02119     return (r == ERROR_SUCCESS);
02120 }
02121 
02122 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
02123 {
02124     LPCWSTR package;
02125     HKEY hkey;
02126     DWORD sz;
02127     LONG res;
02128     UINT r;
02129 
02130     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
02131     static const WCHAR managed_local_package[] = {
02132         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
02133     };
02134 
02135     r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
02136     if (r != ERROR_SUCCESS)
02137         return FALSE;
02138 
02139     if (context == MSIINSTALLCONTEXT_USERMANAGED)
02140         package = managed_local_package;
02141     else
02142         package = local_package;
02143 
02144     sz = 0;
02145     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
02146     RegCloseKey(hkey);
02147 
02148     return (res == ERROR_SUCCESS);
02149 }
02150 
02151 static UINT msi_comp_find_prodcode(LPWSTR squished_pc,
02152                                    MSIINSTALLCONTEXT context,
02153                                    LPCWSTR comp, LPWSTR val, DWORD *sz)
02154 {
02155     HKEY hkey;
02156     LONG res;
02157     UINT r;
02158 
02159     if (context == MSIINSTALLCONTEXT_MACHINE)
02160         r = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
02161     else
02162         r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
02163 
02164     if (r != ERROR_SUCCESS)
02165         return r;
02166 
02167     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, (BYTE *)val, sz);
02168     if (res != ERROR_SUCCESS)
02169         return res;
02170 
02171     RegCloseKey(hkey);
02172     return res;
02173 }
02174 
02175 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
02176                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
02177                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
02178 {
02179     WCHAR squished_pc[GUID_SIZE];
02180     BOOL found;
02181     DWORD sz;
02182 
02183     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
02184           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
02185 
02186     if (!pdwState || !szComponent)
02187         return ERROR_INVALID_PARAMETER;
02188 
02189     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
02190         return ERROR_INVALID_PARAMETER;
02191 
02192     if (!squash_guid(szProductCode, squished_pc))
02193         return ERROR_INVALID_PARAMETER;
02194 
02195     found = msi_comp_find_prod_key(szProductCode, dwContext);
02196 
02197     if (!msi_comp_find_package(szProductCode, dwContext))
02198     {
02199         if (found)
02200         {
02201             *pdwState = INSTALLSTATE_UNKNOWN;
02202             return ERROR_UNKNOWN_COMPONENT;
02203         }
02204 
02205         return ERROR_UNKNOWN_PRODUCT;
02206     }
02207 
02208     *pdwState = INSTALLSTATE_UNKNOWN;
02209 
02210     sz = 0;
02211     if (msi_comp_find_prodcode(squished_pc, dwContext, szComponent, NULL, &sz))
02212         return ERROR_UNKNOWN_COMPONENT;
02213 
02214     if (sz == 0)
02215         *pdwState = INSTALLSTATE_NOTUSED;
02216     else
02217     {
02218         WCHAR *val;
02219         UINT r;
02220 
02221         if (!(val = msi_alloc( sz ))) return ERROR_OUTOFMEMORY;
02222         if ((r = msi_comp_find_prodcode(squished_pc, dwContext, szComponent, val, &sz)))
02223             return r;
02224 
02225         if (lstrlenW(val) > 2 &&
02226             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9' && val[2] != ':')
02227         {
02228             *pdwState = INSTALLSTATE_SOURCE;
02229         }
02230         else
02231             *pdwState = INSTALLSTATE_LOCAL;
02232         msi_free( val );
02233     }
02234 
02235     TRACE("-> %d\n", *pdwState);
02236     return ERROR_SUCCESS;
02237 }
02238 
02239 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
02240 {
02241     LPWSTR szwProduct = NULL;
02242     INSTALLSTATE r;
02243 
02244     if( szProduct )
02245     {
02246          szwProduct = strdupAtoW( szProduct );
02247          if( !szwProduct )
02248              return ERROR_OUTOFMEMORY;
02249     }
02250     r = MsiQueryProductStateW( szwProduct );
02251     msi_free( szwProduct );
02252     return r;
02253 }
02254 
02255 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
02256 {
02257     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
02258     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
02259     HKEY prodkey = 0, userdata = 0;
02260     DWORD val;
02261     UINT r;
02262 
02263     TRACE("%s\n", debugstr_w(szProduct));
02264 
02265     if (!szProduct || !*szProduct)
02266         return INSTALLSTATE_INVALIDARG;
02267 
02268     if (lstrlenW(szProduct) != GUID_SIZE - 1)
02269         return INSTALLSTATE_INVALIDARG;
02270 
02271     if (szProduct[0] != '{' || szProduct[37] != '}')
02272         return INSTALLSTATE_UNKNOWN;
02273 
02274     SetLastError( ERROR_SUCCESS );
02275 
02276     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
02277                               &prodkey, FALSE) != ERROR_SUCCESS &&
02278         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
02279                               &prodkey, FALSE) != ERROR_SUCCESS &&
02280         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
02281                               &prodkey, FALSE) == ERROR_SUCCESS)
02282     {
02283         context = MSIINSTALLCONTEXT_MACHINE;
02284     }
02285 
02286     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
02287     if (r != ERROR_SUCCESS)
02288         goto done;
02289 
02290     if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
02291         goto done;
02292 
02293     if (val)
02294         state = INSTALLSTATE_DEFAULT;
02295     else
02296         state = INSTALLSTATE_UNKNOWN;
02297 
02298 done:
02299     if (!prodkey)
02300     {
02301         state = INSTALLSTATE_UNKNOWN;
02302 
02303         if (userdata)
02304             state = INSTALLSTATE_ABSENT;
02305     }
02306 
02307     RegCloseKey(prodkey);
02308     RegCloseKey(userdata);
02309     TRACE("-> %d\n", state);
02310     return state;
02311 }
02312 
02313 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
02314 {
02315     INSTALLUILEVEL old = gUILevel;
02316     HWND oldwnd = gUIhwnd;
02317 
02318     TRACE("%08x %p\n", dwUILevel, phWnd);
02319 
02320     gUILevel = dwUILevel;
02321     if (phWnd)
02322     {
02323         gUIhwnd = *phWnd;
02324         *phWnd = oldwnd;
02325     }
02326     return old;
02327 }
02328 
02329 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
02330                                   DWORD dwMessageFilter, LPVOID pvContext)
02331 {
02332     INSTALLUI_HANDLERA prev = gUIHandlerA;
02333 
02334     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
02335 
02336     gUIHandlerA = puiHandler;
02337     gUIHandlerW = NULL;
02338     gUIFilter   = dwMessageFilter;
02339     gUIContext  = pvContext;
02340 
02341     return prev;
02342 }
02343 
02344 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
02345                                   DWORD dwMessageFilter, LPVOID pvContext)
02346 {
02347     INSTALLUI_HANDLERW prev = gUIHandlerW;
02348 
02349     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
02350 
02351     gUIHandlerA = NULL;
02352     gUIHandlerW = puiHandler;
02353     gUIFilter   = dwMessageFilter;
02354     gUIContext  = pvContext;
02355 
02356     return prev;
02357 }
02358 
02359 /******************************************************************
02360  *  MsiLoadStringW            [MSI.@]
02361  *
02362  * Loads a string from MSI's string resources.
02363  *
02364  * PARAMS
02365  *
02366  *   handle        [I]  only -1 is handled currently
02367  *   id            [I]  id of the string to be loaded
02368  *   lpBuffer      [O]  buffer for the string to be written to
02369  *   nBufferMax    [I]  maximum size of the buffer in characters
02370  *   lang          [I]  the preferred language for the string
02371  *
02372  * RETURNS
02373  *
02374  *   If successful, this function returns the language id of the string loaded
02375  *   If the function fails, the function returns zero.
02376  *
02377  * NOTES
02378  *
02379  *   The type of the first parameter is unknown.  LoadString's prototype
02380  *  suggests that it might be a module handle.  I have made it an MSI handle
02381  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
02382  *  handle.  Maybe strings can be stored in an MSI database somehow.
02383  */
02384 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
02385                 int nBufferMax, LANGID lang )
02386 {
02387     HRSRC hres;
02388     HGLOBAL hResData;
02389     LPWSTR p;
02390     DWORD i, len;
02391 
02392     TRACE("%d %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
02393 
02394     if( handle != -1 )
02395         FIXME("don't know how to deal with handle = %08x\n", handle);
02396 
02397     if( !lang )
02398         lang = GetUserDefaultLangID();
02399 
02400     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
02401                             (LPWSTR)1, lang );
02402     if( !hres )
02403         return 0;
02404     hResData = LoadResource( msi_hInstance, hres );
02405     if( !hResData )
02406         return 0;
02407     p = LockResource( hResData );
02408     if( !p )
02409         return 0;
02410 
02411     for (i = 0; i < (id & 0xf); i++) p += *p + 1;
02412     len = *p;
02413 
02414     if( nBufferMax <= len )
02415         return 0;
02416 
02417     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
02418     lpBuffer[ len ] = 0;
02419 
02420     TRACE("found -> %s\n", debugstr_w(lpBuffer));
02421     return lang;
02422 }
02423 
02424 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
02425                 int nBufferMax, LANGID lang )
02426 {
02427     LPWSTR bufW;
02428     LANGID r;
02429     INT len;
02430 
02431     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
02432     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
02433     if( r )
02434     {
02435         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
02436         if( len <= nBufferMax )
02437             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
02438                                  lpBuffer, nBufferMax, NULL, NULL );
02439         else
02440             r = 0;
02441     }
02442     msi_free(bufW);
02443     return r;
02444 }
02445 
02446 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
02447                 LPDWORD pcchBuf)
02448 {
02449     char szProduct[GUID_SIZE];
02450 
02451     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
02452 
02453     if (!szComponent || !pcchBuf)
02454         return INSTALLSTATE_INVALIDARG;
02455 
02456     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
02457         return INSTALLSTATE_UNKNOWN;
02458 
02459     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
02460 }
02461 
02462 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
02463                 LPDWORD pcchBuf)
02464 {
02465     WCHAR szProduct[GUID_SIZE];
02466 
02467     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
02468 
02469     if (!szComponent || !pcchBuf)
02470         return INSTALLSTATE_INVALIDARG;
02471 
02472     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
02473         return INSTALLSTATE_UNKNOWN;
02474 
02475     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
02476 }
02477 
02478 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
02479                 WORD wLanguageId, DWORD f)
02480 {
02481     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
02482           uType, wLanguageId, f);
02483     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
02484 }
02485 
02486 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
02487                 WORD wLanguageId, DWORD f)
02488 {
02489     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
02490           uType, wLanguageId, f);
02491     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
02492 }
02493 
02494 UINT WINAPI MsiMessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
02495                 DWORD unknown, WORD wLanguageId, DWORD f)
02496 {
02497     FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_a(lpText),
02498             debugstr_a(lpCaption), uType, unknown, wLanguageId, f);
02499     return MessageBoxExA(hWnd, lpText, lpCaption, uType, wLanguageId);
02500 }
02501 
02502 UINT WINAPI MsiMessageBoxExW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
02503                 DWORD unknown, WORD wLanguageId, DWORD f)
02504 {
02505     FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_w(lpText),
02506             debugstr_w(lpCaption), uType, unknown, wLanguageId, f);
02507     return MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
02508 }
02509 
02510 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
02511                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
02512                 LPDWORD pcchPathBuf )
02513 {
02514     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
02515           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
02516           pcchPathBuf);
02517     return ERROR_CALL_NOT_IMPLEMENTED;
02518 }
02519 
02520 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
02521                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
02522                 LPDWORD pcchPathBuf )
02523 {
02524     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
02525           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
02526           pcchPathBuf);
02527     return ERROR_CALL_NOT_IMPLEMENTED;
02528 }
02529 
02530 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
02531                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
02532 {
02533     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
02534     return ERROR_CALL_NOT_IMPLEMENTED;
02535 }
02536 
02537 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
02538                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
02539 {
02540     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
02541     return ERROR_CALL_NOT_IMPLEMENTED;
02542 }
02543 
02544 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR path, DWORD flags, PCCERT_CONTEXT *cert,
02545                                                 LPBYTE hash, LPDWORD hashlen )
02546 {
02547     UINT r;
02548     WCHAR *pathW = NULL;
02549 
02550     TRACE("%s %08x %p %p %p\n", debugstr_a(path), flags, cert, hash, hashlen);
02551 
02552     if (path && !(pathW = strdupAtoW( path ))) return ERROR_OUTOFMEMORY;
02553     r = MsiGetFileSignatureInformationW( pathW, flags, cert, hash, hashlen );
02554     msi_free( pathW );
02555     return r;
02556 }
02557 
02558 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR path, DWORD flags, PCCERT_CONTEXT *cert,
02559                                                 LPBYTE hash, LPDWORD hashlen )
02560 {
02561     static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
02562     HRESULT hr;
02563     WINTRUST_DATA data;
02564     WINTRUST_FILE_INFO info;
02565     CRYPT_PROVIDER_SGNR *signer;
02566     CRYPT_PROVIDER_CERT *provider;
02567 
02568     TRACE("%s %08x %p %p %p\n", debugstr_w(path), flags, cert, hash, hashlen);
02569 
02570     if (!path || !cert) return E_INVALIDARG;
02571 
02572     info.cbStruct       = sizeof(info);
02573     info.pcwszFilePath  = path;
02574     info.hFile          = NULL;
02575     info.pgKnownSubject = NULL;
02576 
02577     data.cbStruct            = sizeof(data);
02578     data.pPolicyCallbackData = NULL;
02579     data.pSIPClientData      = NULL;
02580     data.dwUIChoice          = WTD_UI_NONE;
02581     data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
02582     data.dwUnionChoice       = WTD_CHOICE_FILE;
02583     data.u.pFile             = &info;
02584     data.dwStateAction       = WTD_STATEACTION_VERIFY;
02585     data.hWVTStateData       = NULL;
02586     data.pwszURLReference    = NULL;
02587     data.dwProvFlags         = 0;
02588     data.dwUIContext         = WTD_UICONTEXT_INSTALL;
02589     hr = WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
02590     *cert = NULL;
02591     if (FAILED(hr)) goto done;
02592 
02593     if (!(signer = WTHelperGetProvSignerFromChain( data.hWVTStateData, 0, FALSE, 0 )))
02594     {
02595         hr = TRUST_E_NOSIGNATURE;
02596         goto done;
02597     }
02598     if (hash)
02599     {
02600         DWORD len = signer->psSigner->EncryptedHash.cbData;
02601         if (*hashlen < len)
02602         {
02603             *hashlen = len;
02604             hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
02605             goto done;
02606         }
02607         memcpy( hash, signer->psSigner->EncryptedHash.pbData, len );
02608         *hashlen = len;
02609     }
02610     if (!(provider = WTHelperGetProvCertFromChain( signer, 0 )))
02611     {
02612         hr = TRUST_E_PROVIDER_UNKNOWN;
02613         goto done;
02614     }
02615     *cert = CertDuplicateCertificateContext( provider->pCert );
02616 
02617 done:
02618     data.dwStateAction = WTD_STATEACTION_CLOSE;
02619     WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
02620     return hr;
02621 }
02622 
02623 /******************************************************************
02624  * MsiGetProductPropertyA      [MSI.@]
02625  */
02626 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
02627                                    LPSTR szValue, LPDWORD pccbValue)
02628 {
02629     LPWSTR prop = NULL, val = NULL;
02630     DWORD len;
02631     UINT r;
02632 
02633     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
02634           szValue, pccbValue);
02635 
02636     if (szValue && !pccbValue)
02637         return ERROR_INVALID_PARAMETER;
02638 
02639     if (szProperty) prop = strdupAtoW(szProperty);
02640 
02641     len = 0;
02642     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
02643     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
02644         goto done;
02645 
02646     if (r == ERROR_SUCCESS)
02647     {
02648         if (szValue) *szValue = '\0';
02649         if (pccbValue) *pccbValue = 0;
02650         goto done;
02651     }
02652 
02653     val = msi_alloc(++len * sizeof(WCHAR));
02654     if (!val)
02655     {
02656         r = ERROR_OUTOFMEMORY;
02657         goto done;
02658     }
02659 
02660     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
02661     if (r != ERROR_SUCCESS)
02662         goto done;
02663 
02664     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
02665 
02666     if (szValue)
02667         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
02668                             *pccbValue, NULL, NULL);
02669 
02670     if (pccbValue)
02671     {
02672         if (len > *pccbValue)
02673             r = ERROR_MORE_DATA;
02674 
02675         *pccbValue = len - 1;
02676     }
02677 
02678 done:
02679     msi_free(prop);
02680     msi_free(val);
02681 
02682     return r;
02683 }
02684 
02685 /******************************************************************
02686  * MsiGetProductPropertyW      [MSI.@]
02687  */
02688 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
02689                                    LPWSTR szValue, LPDWORD pccbValue)
02690 {
02691     MSIPACKAGE *package;
02692     MSIQUERY *view = NULL;
02693     MSIRECORD *rec = NULL;
02694     LPCWSTR val;
02695     UINT r;
02696 
02697     static const WCHAR query[] = {
02698        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02699        '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
02700        '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
02701 
02702     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
02703           szValue, pccbValue);
02704 
02705     if (!szProperty)
02706         return ERROR_INVALID_PARAMETER;
02707 
02708     if (szValue && !pccbValue)
02709         return ERROR_INVALID_PARAMETER;
02710 
02711     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
02712     if (!package)
02713         return ERROR_INVALID_HANDLE;
02714 
02715     r = MSI_OpenQuery(package->db, &view, query, szProperty);
02716     if (r != ERROR_SUCCESS)
02717         goto done;
02718 
02719     r = MSI_ViewExecute(view, 0);
02720     if (r != ERROR_SUCCESS)
02721         goto done;
02722 
02723     r = MSI_ViewFetch(view, &rec);
02724     if (r != ERROR_SUCCESS)
02725         goto done;
02726 
02727     val = MSI_RecordGetString(rec, 2);
02728     if (!val)
02729         goto done;
02730 
02731     if (lstrlenW(val) >= *pccbValue)
02732     {
02733         lstrcpynW(szValue, val, *pccbValue);
02734         *pccbValue = lstrlenW(val);
02735         r = ERROR_MORE_DATA;
02736     }
02737     else
02738     {
02739         lstrcpyW(szValue, val);
02740         *pccbValue = lstrlenW(val);
02741         r = ERROR_SUCCESS;
02742     }
02743 
02744 done:
02745     if (view)
02746     {
02747         MSI_ViewClose(view);
02748         msiobj_release(&view->hdr);
02749         if (rec) msiobj_release(&rec->hdr);
02750     }
02751 
02752     if (!rec)
02753     {
02754         if (szValue) *szValue = '\0';
02755         if (pccbValue) *pccbValue = 0;
02756         r = ERROR_SUCCESS;
02757     }
02758 
02759     msiobj_release(&package->hdr);
02760     return r;
02761 }
02762 
02763 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
02764 {
02765     UINT r;
02766     LPWSTR szPack = NULL;
02767 
02768     TRACE("%s\n", debugstr_a(szPackage) );
02769 
02770     if( szPackage )
02771     {
02772         szPack = strdupAtoW( szPackage );
02773         if( !szPack )
02774             return ERROR_OUTOFMEMORY;
02775     }
02776 
02777     r = MsiVerifyPackageW( szPack );
02778 
02779     msi_free( szPack );
02780 
02781     return r;
02782 }
02783 
02784 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
02785 {
02786     MSIHANDLE handle;
02787     UINT r;
02788 
02789     TRACE("%s\n", debugstr_w(szPackage) );
02790 
02791     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
02792     MsiCloseHandle( handle );
02793 
02794     return r;
02795 }
02796 
02797 static INSTALLSTATE MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
02798                                          awstring* lpPathBuf, LPDWORD pcchBuf)
02799 {
02800     static const WCHAR wininstaller[] =
02801         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
02802     WCHAR squished_pc[GUID_SIZE];
02803     WCHAR squished_comp[GUID_SIZE];
02804     HKEY hkey;
02805     LPWSTR path = NULL;
02806     INSTALLSTATE state;
02807     DWORD version;
02808 
02809     if (!szProduct || !szComponent)
02810         return INSTALLSTATE_INVALIDARG;
02811 
02812     if (lpPathBuf->str.w && !pcchBuf)
02813         return INSTALLSTATE_INVALIDARG;
02814 
02815     if (!squash_guid(szProduct, squished_pc) ||
02816         !squash_guid(szComponent, squished_comp))
02817         return INSTALLSTATE_INVALIDARG;
02818 
02819     state = INSTALLSTATE_UNKNOWN;
02820 
02821     if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
02822         MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
02823     {
02824         path = msi_reg_get_val_str(hkey, squished_pc);
02825         RegCloseKey(hkey);
02826 
02827         state = INSTALLSTATE_ABSENT;
02828 
02829         if ((MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL,
02830                                      &hkey, FALSE) == ERROR_SUCCESS ||
02831             MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
02832                                           NULL, &hkey, FALSE) == ERROR_SUCCESS) &&
02833             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
02834             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
02835         {
02836             RegCloseKey(hkey);
02837             state = INSTALLSTATE_LOCAL;
02838         }
02839     }
02840 
02841     if (state != INSTALLSTATE_LOCAL &&
02842         (MSIREG_OpenProductKey(szProduct, NULL,
02843                                MSIINSTALLCONTEXT_USERUNMANAGED,
02844                                &hkey, FALSE) == ERROR_SUCCESS ||
02845          MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
02846                                &hkey, FALSE) == ERROR_SUCCESS))
02847     {
02848         RegCloseKey(hkey);
02849 
02850         if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
02851             MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
02852         {
02853             msi_free(path);
02854             path = msi_reg_get_val_str(hkey, squished_pc);
02855             RegCloseKey(hkey);
02856 
02857             state = INSTALLSTATE_ABSENT;
02858 
02859             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
02860                 state = INSTALLSTATE_LOCAL;
02861         }
02862     }
02863 
02864     if (!path)
02865         return INSTALLSTATE_UNKNOWN;
02866 
02867     if (state == INSTALLSTATE_LOCAL && !*path)
02868         state = INSTALLSTATE_NOTUSED;
02869 
02870     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
02871     msi_free(path);
02872     return state;
02873 }
02874 
02875 /******************************************************************
02876  * MsiGetComponentPathW      [MSI.@]
02877  */
02878 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
02879                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
02880 {
02881     awstring path;
02882 
02883     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szComponent), lpPathBuf, pcchBuf);
02884 
02885     path.unicode = TRUE;
02886     path.str.w = lpPathBuf;
02887 
02888     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
02889 }
02890 
02891 /******************************************************************
02892  * MsiGetComponentPathA      [MSI.@]
02893  */
02894 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
02895                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
02896 {
02897     LPWSTR szwProduct, szwComponent = NULL;
02898     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
02899     awstring path;
02900 
02901     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szComponent), lpPathBuf, pcchBuf);
02902 
02903     szwProduct = strdupAtoW( szProduct );
02904     if( szProduct && !szwProduct)
02905         goto end;
02906 
02907     szwComponent = strdupAtoW( szComponent );
02908     if( szComponent && !szwComponent )
02909         goto end;
02910 
02911     path.unicode = FALSE;
02912     path.str.a = lpPathBuf;
02913 
02914     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
02915 
02916 end:
02917     msi_free( szwProduct );
02918     msi_free( szwComponent );
02919 
02920     return r;
02921 }
02922 
02923 /******************************************************************
02924  * MsiQueryFeatureStateA      [MSI.@]
02925  */
02926 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
02927 {
02928     LPWSTR szwProduct = NULL, szwFeature= NULL;
02929     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
02930 
02931     szwProduct = strdupAtoW( szProduct );
02932     if ( szProduct && !szwProduct )
02933         goto end;
02934 
02935     szwFeature = strdupAtoW( szFeature );
02936     if ( szFeature && !szwFeature )
02937         goto end;
02938 
02939     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
02940 
02941 end:
02942     msi_free( szwProduct);
02943     msi_free( szwFeature);
02944 
02945     return rc;
02946 }
02947 
02948 /******************************************************************
02949  * MsiQueryFeatureStateW      [MSI.@]
02950  *
02951  * Checks the state of a feature
02952  *
02953  * PARAMS
02954  *   szProduct     [I]  Product's GUID string
02955  *   szFeature     [I]  Feature's GUID string
02956  *
02957  * RETURNS
02958  *   INSTALLSTATE_LOCAL        Feature is installed and usable
02959  *   INSTALLSTATE_ABSENT       Feature is absent
02960  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
02961  *   INSTALLSTATE_UNKNOWN      An error occurred
02962  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
02963  *
02964  */
02965 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
02966 {
02967     WCHAR squishProduct[33], comp[GUID_SIZE];
02968     GUID guid;
02969     LPWSTR components, p, parent_feature, path;
02970     UINT rc;
02971     HKEY hkey;
02972     INSTALLSTATE r;
02973     BOOL missing = FALSE;
02974     BOOL machine = FALSE;
02975     BOOL source = FALSE;
02976 
02977     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
02978 
02979     if (!szProduct || !szFeature)
02980         return INSTALLSTATE_INVALIDARG;
02981 
02982     if (!squash_guid( szProduct, squishProduct ))
02983         return INSTALLSTATE_INVALIDARG;
02984 
02985     SetLastError( ERROR_SUCCESS );
02986 
02987     if (MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
02988                                &hkey, FALSE) != ERROR_SUCCESS &&
02989         MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
02990                                &hkey, FALSE) != ERROR_SUCCESS)
02991     {
02992         rc = MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_MACHINE,
02993                                     &hkey, FALSE);
02994         if (rc != ERROR_SUCCESS)
02995             return INSTALLSTATE_UNKNOWN;
02996 
02997         machine = TRUE;
02998     }
02999 
03000     parent_feature = msi_reg_get_val_str( hkey, szFeature );
03001     RegCloseKey(hkey);
03002 
03003     if (!parent_feature)
03004         return INSTALLSTATE_UNKNOWN;
03005 
03006     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
03007     msi_free(parent_feature);
03008     if (r == INSTALLSTATE_ABSENT)
03009         return r;
03010 
03011     if (machine)
03012         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
03013                                             MSIINSTALLCONTEXT_MACHINE,
03014                                             &hkey, FALSE);
03015     else
03016         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
03017                                             MSIINSTALLCONTEXT_USERUNMANAGED,
03018                                             &hkey, FALSE);
03019 
03020     if (rc != ERROR_SUCCESS)
03021         return INSTALLSTATE_ADVERTISED;
03022 
03023     components = msi_reg_get_val_str( hkey, szFeature );
03024     RegCloseKey(hkey);
03025 
03026     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
03027 
03028     if (!components)
03029         return INSTALLSTATE_ADVERTISED;
03030 
03031     for( p = components; *p && *p != 2 ; p += 20)
03032     {
03033         if (!decode_base85_guid( p, &guid ))
03034         {
03035             if (p != components)
03036                 break;
03037 
03038             msi_free(components);
03039             return INSTALLSTATE_BADCONFIG;
03040         }
03041 
03042         StringFromGUID2(&guid, comp, GUID_SIZE);
03043 
03044         if (machine)
03045             rc = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
03046         else
03047             rc = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
03048 
03049         if (rc != ERROR_SUCCESS)
03050         {
03051             msi_free(components);
03052             return INSTALLSTATE_ADVERTISED;
03053         }
03054 
03055         path = msi_reg_get_val_str(hkey, squishProduct);
03056         if (!path)
03057             missing = TRUE;
03058         else if (lstrlenW(path) > 2 &&
03059                  path[0] >= '0' && path[0] <= '9' &&
03060                  path[1] >= '0' && path[1] <= '9')
03061         {
03062             source = TRUE;
03063         }
03064 
03065         msi_free(path);
03066     }
03067     msi_free(components);
03068 
03069     if (missing)
03070         r = INSTALLSTATE_ADVERTISED;
03071     else if (source)
03072         r = INSTALLSTATE_SOURCE;
03073     else
03074         r = INSTALLSTATE_LOCAL;
03075 
03076     TRACE("-> %d\n", r);
03077     return r;
03078 }
03079 
03080 /******************************************************************
03081  * MsiGetFileVersionA         [MSI.@]
03082  */
03083 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
03084                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
03085 {
03086     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
03087     UINT ret = ERROR_OUTOFMEMORY;
03088 
03089     if ((lpVersionBuf && !pcchVersionBuf) ||
03090         (lpLangBuf && !pcchLangBuf))
03091         return ERROR_INVALID_PARAMETER;
03092 
03093     if( szFilePath )
03094     {
03095         szwFilePath = strdupAtoW( szFilePath );
03096         if( !szwFilePath )
03097             goto end;
03098     }
03099 
03100     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
03101     {
03102         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
03103         if( !lpwVersionBuff )
03104             goto end;
03105     }
03106 
03107     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
03108     {
03109         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
03110         if( !lpwLangBuff )
03111             goto end;
03112     }
03113 
03114     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
03115                              lpwLangBuff, pcchLangBuf);
03116 
03117     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
03118         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
03119                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
03120     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
03121         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
03122                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
03123 
03124 end:
03125     msi_free(szwFilePath);
03126     msi_free(lpwVersionBuff);
03127     msi_free(lpwLangBuff);
03128 
03129     return ret;
03130 }
03131 
03132 static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen,
03133                               WCHAR *langbuf, DWORD *langlen )
03134 {
03135     static const WCHAR szVersionResource[] = {'\\',0};
03136     static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
03137     static const WCHAR szLangFormat[] = {'%','d',0};
03138     UINT ret = ERROR_SUCCESS;
03139     DWORD len, error;
03140     LPVOID version;
03141     VS_FIXEDFILEINFO *ffi;
03142     USHORT *lang;
03143     WCHAR tmp[32];
03144 
03145     if (!(len = GetFileVersionInfoSizeW( path, NULL )))
03146     {
03147         error = GetLastError();
03148         if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND;
03149         return error;
03150     }
03151     if (!(version = msi_alloc( len ))) return ERROR_OUTOFMEMORY;
03152     if (!GetFileVersionInfoW( path, 0, len, version ))
03153     {
03154         msi_free( version );
03155         return GetLastError();
03156     }
03157     if (verlen)
03158     {
03159         if (VerQueryValueW( version, szVersionResource, (LPVOID *)&ffi, &len ) && len > 0)
03160         {
03161             sprintfW( tmp, szVersionFormat,
03162                       HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
03163                       HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) );
03164             if (verbuf) lstrcpynW( verbuf, tmp, *verlen );
03165             len = strlenW( tmp );
03166             if (len >= *verlen) ret = ERROR_MORE_DATA;
03167             *verlen = len;
03168         }
03169         else
03170         {
03171             if (verbuf) *verbuf = 0;
03172             *verlen = 0;
03173         }
03174     }
03175     if (langlen)
03176     {
03177         if (VerQueryValueW( version, szLangResource, (LPVOID *)&lang, &len ) && len > 0)
03178         {
03179             sprintfW( tmp, szLangFormat, *lang );
03180             if (langbuf) lstrcpynW( langbuf, tmp, *langlen );
03181             len = strlenW( tmp );
03182             if (len >= *langlen) ret = ERROR_MORE_DATA;
03183             *langlen = len;
03184         }
03185         else
03186         {
03187             if (langbuf) *langbuf = 0;
03188             *langlen = 0;
03189         }
03190     }
03191     msi_free( version );
03192     return ret;
03193 }
03194 
03195 
03196 /******************************************************************
03197  * MsiGetFileVersionW         [MSI.@]
03198  */
03199 UINT WINAPI MsiGetFileVersionW( LPCWSTR path, LPWSTR verbuf, LPDWORD verlen,
03200                                 LPWSTR langbuf, LPDWORD langlen )
03201 {
03202     UINT ret;
03203 
03204     TRACE("%s %p %u %p %u\n", debugstr_w(path), verbuf, verlen ? *verlen : 0,
03205           langbuf, langlen ? *langlen : 0);
03206 
03207     if ((verbuf && !verlen) || (langbuf && !langlen))
03208         return ERROR_INVALID_PARAMETER;
03209 
03210     ret = get_file_version( path, verbuf, verlen, langbuf, langlen );
03211     if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen)
03212     {
03213         int len;
03214         WCHAR *version = msi_font_version_from_file( path );
03215         if (!version) return ERROR_FILE_INVALID;
03216         len = strlenW( version );
03217         if (len >= *verlen) ret = ERROR_MORE_DATA;
03218         else if (verbuf)
03219         {
03220             strcpyW( verbuf, version );
03221             ret = ERROR_SUCCESS;
03222         }
03223         *verlen = len;
03224         msi_free( version );
03225     }
03226     return ret;
03227 }
03228 
03229 /***********************************************************************
03230  * MsiGetFeatureUsageW           [MSI.@]
03231  */
03232 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
03233                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
03234 {
03235     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
03236           pdwUseCount, pwDateUsed);
03237     return ERROR_CALL_NOT_IMPLEMENTED;
03238 }
03239 
03240 /***********************************************************************
03241  * MsiGetFeatureUsageA           [MSI.@]
03242  */
03243 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
03244                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
03245 {
03246     LPWSTR prod = NULL, feat = NULL;
03247     UINT ret = ERROR_OUTOFMEMORY;
03248 
03249     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
03250           pdwUseCount, pwDateUsed);
03251 
03252     prod = strdupAtoW( szProduct );
03253     if (szProduct && !prod)
03254         goto end;
03255 
03256     feat = strdupAtoW( szFeature );
03257     if (szFeature && !feat)
03258         goto end;
03259 
03260     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
03261 
03262 end:
03263     msi_free( prod );
03264     msi_free( feat );
03265 
03266     return ret;
03267 }
03268 
03269 /***********************************************************************
03270  * MsiUseFeatureExW           [MSI.@]
03271  */
03272 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
03273                                       DWORD dwInstallMode, DWORD dwReserved )
03274 {
03275     INSTALLSTATE state;
03276 
03277     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
03278           dwInstallMode, dwReserved);
03279 
03280     state = MsiQueryFeatureStateW( szProduct, szFeature );
03281 
03282     if (dwReserved)
03283         return INSTALLSTATE_INVALIDARG;
03284 
03285     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
03286     {
03287         FIXME("mark product %s feature %s as used\n",
03288               debugstr_w(szProduct), debugstr_w(szFeature) );
03289     }
03290 
03291     return state;
03292 }
03293 
03294 /***********************************************************************
03295  * MsiUseFeatureExA           [MSI.@]
03296  */
03297 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
03298                                       DWORD dwInstallMode, DWORD dwReserved )
03299 {
03300     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
03301     LPWSTR prod = NULL, feat = NULL;
03302 
03303     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
03304           dwInstallMode, dwReserved);
03305 
03306     prod = strdupAtoW( szProduct );
03307     if (szProduct && !prod)
03308         goto end;
03309 
03310     feat = strdupAtoW( szFeature );
03311     if (szFeature && !feat)
03312         goto end;
03313 
03314     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
03315 
03316 end:
03317     msi_free( prod );
03318     msi_free( feat );
03319 
03320     return ret;
03321 }
03322 
03323 /***********************************************************************
03324  * MsiUseFeatureW             [MSI.@]
03325  */
03326 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
03327 {
03328     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
03329 }
03330 
03331 /***********************************************************************
03332  * MsiUseFeatureA             [MSI.@]
03333  */
03334 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
03335 {
03336     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
03337 }
03338 
03339 /***********************************************************************
03340  * MSI_ProvideQualifiedComponentEx [internal]
03341  */
03342 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
03343                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
03344                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
03345                 LPDWORD pcchPathBuf)
03346 {
03347     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
03348           feature[MAX_FEATURE_CHARS+1];
03349     LPWSTR info;
03350     HKEY hkey;
03351     DWORD sz;
03352     UINT rc;
03353 
03354     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
03355     if (rc != ERROR_SUCCESS)
03356         return ERROR_INDEX_ABSENT;
03357 
03358     info = msi_reg_get_val_str( hkey, szQualifier );
03359     RegCloseKey(hkey);
03360 
03361     if (!info)
03362         return ERROR_INDEX_ABSENT;
03363 
03364     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
03365 
03366     if (!szProduct)
03367         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
03368     else
03369         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
03370 
03371     msi_free( info );
03372 
03373     if (rc != INSTALLSTATE_LOCAL)
03374         return ERROR_FILE_NOT_FOUND;
03375 
03376     return ERROR_SUCCESS;
03377 }
03378 
03379 /***********************************************************************
03380  * MsiProvideQualifiedComponentExW [MSI.@]
03381  */
03382 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
03383                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
03384                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
03385                 LPDWORD pcchPathBuf)
03386 {
03387     awstring path;
03388 
03389     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_w(szComponent),
03390           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
03391           Unused1, Unused2, lpPathBuf, pcchPathBuf);
03392 
03393     path.unicode = TRUE;
03394     path.str.w = lpPathBuf;
03395 
03396     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
03397             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
03398 }
03399 
03400 /***********************************************************************
03401  * MsiProvideQualifiedComponentExA [MSI.@]
03402  */
03403 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
03404                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
03405                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
03406                 LPDWORD pcchPathBuf)
03407 {
03408     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
03409     UINT r = ERROR_OUTOFMEMORY;
03410     awstring path;
03411 
03412     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
03413           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
03414           Unused1, Unused2, lpPathBuf, pcchPathBuf);
03415 
03416     szwComponent = strdupAtoW( szComponent );
03417     if (szComponent && !szwComponent)
03418         goto end;
03419 
03420     szwQualifier = strdupAtoW( szQualifier );
03421     if (szQualifier && !szwQualifier)
03422         goto end;
03423 
03424     szwProduct = strdupAtoW( szProduct );
03425     if (szProduct && !szwProduct)
03426         goto end;
03427 
03428     path.unicode = FALSE;
03429     path.str.a = lpPathBuf;
03430 
03431     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
03432                               dwInstallMode, szwProduct, Unused1,
03433                               Unused2, &path, pcchPathBuf);
03434 end:
03435     msi_free(szwProduct);
03436     msi_free(szwComponent);
03437     msi_free(szwQualifier);
03438 
03439     return r;
03440 }
03441 
03442 /***********************************************************************
03443  * MsiProvideQualifiedComponentW [MSI.@]
03444  */
03445 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
03446                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
03447                 LPDWORD pcchPathBuf)
03448 {
03449     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
03450                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
03451 }
03452 
03453 /***********************************************************************
03454  * MsiProvideQualifiedComponentA [MSI.@]
03455  */
03456 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
03457                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
03458                 LPDWORD pcchPathBuf)
03459 {
03460     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
03461                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
03462 }
03463 
03464 /***********************************************************************
03465  * MSI_GetUserInfo [internal]
03466  */
03467 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
03468                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
03469                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
03470                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
03471 {
03472     WCHAR squished_pc[SQUISH_GUID_SIZE];
03473     LPWSTR user, org, serial;
03474     USERINFOSTATE state;
03475     HKEY hkey, props;
03476     LPCWSTR orgptr;
03477     UINT r;
03478 
03479     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
03480           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
03481           pcchSerialBuf);
03482 
03483     if (!szProduct || !squash_guid(szProduct, squished_pc))
03484         return USERINFOSTATE_INVALIDARG;
03485 
03486     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
03487                               &hkey, FALSE) != ERROR_SUCCESS &&
03488         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
03489                               &hkey, FALSE) != ERROR_SUCCESS &&
03490         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
03491                               &hkey, FALSE) != ERROR_SUCCESS)
03492     {
03493         return USERINFOSTATE_UNKNOWN;
03494     }
03495 
03496     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
03497                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
03498         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
03499                                 NULL, &props, FALSE) != ERROR_SUCCESS)
03500     {
03501         RegCloseKey(hkey);
03502         return USERINFOSTATE_ABSENT;
03503     }
03504 
03505     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
03506     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
03507     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
03508     state = USERINFOSTATE_ABSENT;
03509 
03510     RegCloseKey(hkey);
03511     RegCloseKey(props);
03512 
03513     if (user && serial)
03514         state = USERINFOSTATE_PRESENT;
03515 
03516     if (pcchUserNameBuf)
03517     {
03518         if (lpUserNameBuf && !user)
03519         {
03520             (*pcchUserNameBuf)--;
03521             goto done;
03522         }
03523 
03524         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
03525         if (r == ERROR_MORE_DATA)
03526         {
03527             state = USERINFOSTATE_MOREDATA;
03528             goto done;
03529         }
03530     }
03531 
03532     if (pcchOrgNameBuf)
03533     {
03534         orgptr = org;
03535         if (!orgptr) orgptr = szEmpty;
03536 
03537         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
03538         if (r == ERROR_MORE_DATA)
03539         {
03540             state = USERINFOSTATE_MOREDATA;
03541             goto done;
03542         }
03543     }
03544 
03545     if (pcchSerialBuf)
03546     {
03547         if (!serial)
03548         {
03549             (*pcchSerialBuf)--;
03550             goto done;
03551         }
03552 
03553         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
03554         if (r == ERROR_MORE_DATA)
03555             state = USERINFOSTATE_MOREDATA;
03556     }
03557 
03558 done:
03559     msi_free(user);
03560     msi_free(org);
03561     msi_free(serial);
03562 
03563     return state;
03564 }
03565 
03566 /***********************************************************************
03567  * MsiGetUserInfoW [MSI.@]
03568  */
03569 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
03570                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
03571                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
03572                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
03573 {
03574     awstring user, org, serial;
03575 
03576     if ((lpUserNameBuf && !pcchUserNameBuf) ||
03577         (lpOrgNameBuf && !pcchOrgNameBuf) ||
03578         (lpSerialBuf && !pcchSerialBuf))
03579         return USERINFOSTATE_INVALIDARG;
03580 
03581     user.unicode = TRUE;
03582     user.str.w = lpUserNameBuf;
03583     org.unicode = TRUE;
03584     org.str.w = lpOrgNameBuf;
03585     serial.unicode = TRUE;
03586     serial.str.w = lpSerialBuf;
03587 
03588     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
03589                             &org, pcchOrgNameBuf,
03590                             &serial, pcchSerialBuf );
03591 }
03592 
03593 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
03594                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
03595                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
03596                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
03597 {
03598     awstring user, org, serial;
03599     LPWSTR prod;
03600     UINT r;
03601 
03602     if ((lpUserNameBuf && !pcchUserNameBuf) ||
03603         (lpOrgNameBuf && !pcchOrgNameBuf) ||
03604         (lpSerialBuf && !pcchSerialBuf))
03605         return USERINFOSTATE_INVALIDARG;
03606 
03607     prod = strdupAtoW( szProduct );
03608     if (szProduct && !prod)
03609         return ERROR_OUTOFMEMORY;
03610 
03611     user.unicode = FALSE;
03612     user.str.a = lpUserNameBuf;
03613     org.unicode = FALSE;
03614     org.str.a = lpOrgNameBuf;
03615     serial.unicode = FALSE;
03616     serial.str.a = lpSerialBuf;
03617 
03618     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
03619                          &org, pcchOrgNameBuf,
03620                          &serial, pcchSerialBuf );
03621 
03622     msi_free( prod );
03623 
03624     return r;
03625 }
03626 
03627 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
03628 {
03629     MSIHANDLE handle;
03630     UINT rc;
03631     MSIPACKAGE *package;
03632     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
03633 
03634     TRACE("(%s)\n",debugstr_w(szProduct));
03635 
03636     rc = MsiOpenProductW(szProduct,&handle);
03637     if (rc != ERROR_SUCCESS)
03638         return ERROR_INVALID_PARAMETER;
03639 
03640     /* MsiCollectUserInfo cannot be called from a custom action. */
03641     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
03642     if (!package)
03643         return ERROR_CALL_NOT_IMPLEMENTED;
03644 
03645     rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
03646     msiobj_release( &package->hdr );
03647 
03648     MsiCloseHandle(handle);
03649 
03650     return rc;
03651 }
03652 
03653 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
03654 {
03655     MSIHANDLE handle;
03656     UINT rc;
03657     MSIPACKAGE *package;
03658     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
03659 
03660     TRACE("(%s)\n",debugstr_a(szProduct));
03661 
03662     rc = MsiOpenProductA(szProduct,&handle);
03663     if (rc != ERROR_SUCCESS)
03664         return ERROR_INVALID_PARAMETER;
03665 
03666     /* MsiCollectUserInfo cannot be called from a custom action. */
03667     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
03668     if (!package)
03669         return ERROR_CALL_NOT_IMPLEMENTED;
03670 
03671     rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
03672     msiobj_release( &package->hdr );
03673 
03674     MsiCloseHandle(handle);
03675 
03676     return rc;
03677 }
03678 
03679 /***********************************************************************
03680  * MsiConfigureFeatureA            [MSI.@]
03681  */
03682 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
03683 {
03684     LPWSTR prod, feat = NULL;
03685     UINT r = ERROR_OUTOFMEMORY;
03686 
03687     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
03688 
03689     prod = strdupAtoW( szProduct );
03690     if (szProduct && !prod)
03691         goto end;
03692 
03693     feat = strdupAtoW( szFeature );
03694     if (szFeature && !feat)
03695         goto end;
03696 
03697     r = MsiConfigureFeatureW(prod, feat, eInstallState);
03698 
03699 end:
03700     msi_free(feat);
03701     msi_free(prod);
03702 
03703     return r;
03704 }
03705 
03706 /***********************************************************************
03707  * MsiConfigureFeatureW            [MSI.@]
03708  */
03709 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
03710 {
03711     MSIPACKAGE *package = NULL;
03712     UINT r;
03713     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
03714     DWORD sz;
03715 
03716     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
03717 
03718     if (!szProduct || !szFeature)
03719         return ERROR_INVALID_PARAMETER;
03720 
03721     switch (eInstallState)
03722     {
03723     case INSTALLSTATE_DEFAULT:
03724         /* FIXME: how do we figure out the default location? */
03725         eInstallState = INSTALLSTATE_LOCAL;
03726         break;
03727     case INSTALLSTATE_LOCAL:
03728     case INSTALLSTATE_SOURCE:
03729     case INSTALLSTATE_ABSENT:
03730     case INSTALLSTATE_ADVERTISED:
03731         break;
03732     default:
03733         return ERROR_INVALID_PARAMETER;
03734     }
03735 
03736     r = MSI_OpenProductW( szProduct, &package );
03737     if (r != ERROR_SUCCESS)
03738         return r;
03739 
03740     sz = sizeof(sourcepath);
03741     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
03742                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
03743 
03744     sz = sizeof(filename);
03745     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
03746                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
03747 
03748     lstrcatW( sourcepath, filename );
03749 
03750     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
03751 
03752     r = ACTION_PerformUIAction( package, szCostInitialize, SCRIPT_NONE );
03753     if (r != ERROR_SUCCESS)
03754         goto end;
03755 
03756     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
03757     if (r != ERROR_SUCCESS)
03758         goto end;
03759 
03760     r = MSI_InstallPackage( package, sourcepath, NULL );
03761 
03762 end:
03763     msiobj_release( &package->hdr );
03764 
03765     return r;
03766 }
03767 
03768 /***********************************************************************
03769  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
03770  *
03771  * Notes: undocumented
03772  */
03773 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
03774 {
03775     WCHAR path[MAX_PATH];
03776 
03777     TRACE("%d\n", dwReserved);
03778 
03779     if (dwReserved)
03780     {
03781         FIXME("dwReserved=%d\n", dwReserved);
03782         return ERROR_INVALID_PARAMETER;
03783     }
03784 
03785     if (!GetWindowsDirectoryW(path, MAX_PATH))
03786         return ERROR_FUNCTION_FAILED;
03787 
03788     lstrcatW(path, installerW);
03789 
03790     if (!CreateDirectoryW(path, NULL))
03791         return ERROR_FUNCTION_FAILED;
03792 
03793     return ERROR_SUCCESS;
03794 }
03795 
03796 /***********************************************************************
03797  * MsiGetShortcutTargetA           [MSI.@]
03798  */
03799 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
03800                                    LPSTR szProductCode, LPSTR szFeatureId,
03801                                    LPSTR szComponentCode )
03802 {
03803     LPWSTR target;
03804     const int len = MAX_FEATURE_CHARS+1;
03805     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
03806     UINT r;
03807 
03808     target = strdupAtoW( szShortcutTarget );
03809     if (szShortcutTarget && !target )
03810         return ERROR_OUTOFMEMORY;
03811     product[0] = 0;
03812     feature[0] = 0;
03813     component[0] = 0;
03814     r = MsiGetShortcutTargetW( target, product, feature, component );
03815     msi_free( target );
03816     if (r == ERROR_SUCCESS)
03817     {
03818         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
03819         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
03820         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
03821     }
03822     return r;
03823 }
03824 
03825 /***********************************************************************
03826  * MsiGetShortcutTargetW           [MSI.@]
03827  */
03828 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
03829                                    LPWSTR szProductCode, LPWSTR szFeatureId,
03830                                    LPWSTR szComponentCode )
03831 {
03832     IShellLinkDataList *dl = NULL;
03833     IPersistFile *pf = NULL;
03834     LPEXP_DARWIN_LINK darwin = NULL;
03835     HRESULT r, init;
03836 
03837     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
03838           szProductCode, szFeatureId, szComponentCode );
03839 
03840     init = CoInitialize(NULL);
03841 
03842     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
03843                           &IID_IPersistFile, (LPVOID*) &pf );
03844     if( SUCCEEDED( r ) )
03845     {
03846         r = IPersistFile_Load( pf, szShortcutTarget,
03847                                STGM_READ | STGM_SHARE_DENY_WRITE );
03848         if( SUCCEEDED( r ) )
03849         {
03850             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
03851                                              (LPVOID*) &dl );
03852             if( SUCCEEDED( r ) )
03853             {
03854                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
03855                                                   (LPVOID) &darwin );
03856                 IShellLinkDataList_Release( dl );
03857             }
03858         }
03859         IPersistFile_Release( pf );
03860     }
03861 
03862     if (SUCCEEDED(init))
03863         CoUninitialize();
03864 
03865     TRACE("darwin = %p\n", darwin);
03866 
03867     if (darwin)
03868     {
03869         DWORD sz;
03870         UINT ret;
03871 
03872         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
03873                   szProductCode, szFeatureId, szComponentCode, &sz );
03874         LocalFree( darwin );
03875         return ret;
03876     }
03877 
03878     return ERROR_FUNCTION_FAILED;
03879 }
03880 
03881 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, DWORD dwReinstallMode )
03882 {
03883     static const WCHAR fmtW[] = {'%','s','=','%','s',' ','%','s','=','%','s',0};
03884     MSIPACKAGE *package;
03885     MSIINSTALLCONTEXT context;
03886     UINT r;
03887     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH], reinstallmode[11];
03888     WCHAR *ptr, *cmdline;
03889     DWORD sz;
03890 
03891     TRACE("%s, %s, 0x%08x\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode);
03892 
03893     r = msi_locate_product( szProduct, &context );
03894     if (r != ERROR_SUCCESS)
03895         return r;
03896 
03897     ptr = reinstallmode;
03898 
03899     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
03900         *ptr++ = 'p';
03901     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
03902         *ptr++ = 'o';
03903     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
03904         *ptr++ = 'w';
03905     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
03906         *ptr++ = 'd';
03907     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
03908         *ptr++ = 'c';
03909     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
03910         *ptr++ = 'a';
03911     if (dwReinstallMode & REINSTALLMODE_USERDATA)
03912         *ptr++ = 'u';
03913     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
03914         *ptr++ = 'm';
03915     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
03916         *ptr++ = 's';
03917     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
03918         *ptr++ = 'v';
03919     *ptr = 0;
03920     
03921     sz = sizeof(sourcepath);
03922     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
03923                            INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
03924     sz = sizeof(filename);
03925     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
03926                            INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
03927     strcatW( sourcepath, filename );
03928 
03929     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
03930         r = MSI_OpenPackageW( sourcepath, &package );
03931     else
03932         r = MSI_OpenProductW( szProduct, &package );
03933 
03934     if (r != ERROR_SUCCESS)
03935         return r;
03936 
03937     sz = (strlenW( fmtW ) + strlenW( szReinstallMode ) + strlenW( reinstallmode )) * sizeof(WCHAR);
03938     sz += (strlenW( szReinstall ) + strlenW( szFeature )) * sizeof(WCHAR);
03939     if (!(cmdline = msi_alloc( sz )))
03940     {
03941         msiobj_release( &package->hdr );
03942         return ERROR_OUTOFMEMORY;
03943     }
03944     sprintfW( cmdline, fmtW, szReinstallMode, reinstallmode, szReinstall, szFeature );
03945 
03946     r = MSI_InstallPackage( package, sourcepath, cmdline );
03947     msiobj_release( &package->hdr );
03948     msi_free( cmdline );
03949 
03950     return r;
03951 }
03952 
03953 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
03954                                   DWORD dwReinstallMode )
03955 {
03956     LPWSTR wszProduct;
03957     LPWSTR wszFeature;
03958     UINT rc;
03959 
03960     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
03961                            dwReinstallMode);
03962 
03963     wszProduct = strdupAtoW(szProduct);
03964     wszFeature = strdupAtoW(szFeature);
03965 
03966     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
03967 
03968     msi_free(wszProduct);
03969     msi_free(wszFeature);
03970     return rc;
03971 }
03972 
03973 typedef struct
03974 {
03975     unsigned int i[2];
03976     unsigned int buf[4];
03977     unsigned char in[64];
03978     unsigned char digest[16];
03979 } MD5_CTX;
03980 
03981 extern VOID WINAPI MD5Init( MD5_CTX *);
03982 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
03983 extern VOID WINAPI MD5Final( MD5_CTX *);
03984 
03985 /***********************************************************************
03986  * MsiGetFileHashW            [MSI.@]
03987  */
03988 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
03989                              PMSIFILEHASHINFO pHash )
03990 {
03991     HANDLE handle, mapping;
03992     void *p;
03993     DWORD length;
03994     UINT r = ERROR_FUNCTION_FAILED;
03995 
03996     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
03997 
03998     if (!szFilePath)
03999         return ERROR_INVALID_PARAMETER;
04000 
04001     if (!*szFilePath)
04002         return ERROR_PATH_NOT_FOUND;
04003 
04004     if (dwOptions)
04005         return ERROR_INVALID_PARAMETER;
04006     if (!pHash)
04007         return ERROR_INVALID_PARAMETER;
04008     if (pHash->dwFileHashInfoSize < sizeof *pHash)
04009         return ERROR_INVALID_PARAMETER;
04010 
04011     handle = CreateFileW( szFilePath, GENERIC_READ,
04012                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
04013     if (handle == INVALID_HANDLE_VALUE)
04014     {
04015         WARN("can't open file %u\n", GetLastError());
04016         return ERROR_FILE_NOT_FOUND;
04017     }
04018     length = GetFileSize( handle, NULL );
04019 
04020     if (length)
04021     {
04022         mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
04023         if (mapping)
04024         {
04025             p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
04026             if (p)
04027             {
04028                 MD5_CTX ctx;
04029 
04030                 MD5Init( &ctx );
04031                 MD5Update( &ctx, p, length );
04032                 MD5Final( &ctx );
04033                 UnmapViewOfFile( p );
04034 
04035                 memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
04036                 r = ERROR_SUCCESS;
04037             }
04038             CloseHandle( mapping );
04039         }
04040     }
04041     else
04042     {
04043         /* Empty file -> set hash to 0 */
04044         memset( pHash->dwData, 0, sizeof pHash->dwData );
04045         r = ERROR_SUCCESS;
04046     }
04047 
04048     CloseHandle( handle );
04049 
04050     return r;
04051 }
04052 
04053 /***********************************************************************
04054  * MsiGetFileHashA            [MSI.@]
04055  */
04056 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
04057                              PMSIFILEHASHINFO pHash )
04058 {
04059     LPWSTR file;
04060     UINT r;
04061 
04062     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
04063 
04064     file = strdupAtoW( szFilePath );
04065     if (szFilePath && !file)
04066         return ERROR_OUTOFMEMORY;
04067 
04068     r = MsiGetFileHashW( file, dwOptions, pHash );
04069     msi_free( file );
04070     return r;
04071 }
04072 
04073 /***********************************************************************
04074  * MsiAdvertiseScriptW        [MSI.@]
04075  */
04076 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
04077                                  PHKEY phRegData, BOOL fRemoveItems )
04078 {
04079     FIXME("%s %08x %p %d\n",
04080           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
04081     return ERROR_CALL_NOT_IMPLEMENTED;
04082 }
04083 
04084 /***********************************************************************
04085  * MsiAdvertiseScriptA        [MSI.@]
04086  */
04087 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
04088                                  PHKEY phRegData, BOOL fRemoveItems )
04089 {
04090     FIXME("%s %08x %p %d\n",
04091           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
04092     return ERROR_CALL_NOT_IMPLEMENTED;
04093 }
04094 
04095 /***********************************************************************
04096  * MsiIsProductElevatedW        [MSI.@]
04097  */
04098 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
04099 {
04100     FIXME("%s %p - stub\n",
04101           debugstr_w( szProduct ), pfElevated );
04102     *pfElevated = TRUE;
04103     return ERROR_SUCCESS;
04104 }
04105 
04106 /***********************************************************************
04107  * MsiIsProductElevatedA        [MSI.@]
04108  */
04109 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
04110 {
04111     FIXME("%s %p - stub\n",
04112           debugstr_a( szProduct ), pfElevated );
04113     *pfElevated = TRUE;
04114     return ERROR_SUCCESS;
04115 }
04116 
04117 /***********************************************************************
04118  * MsiSetExternalUIRecord     [MSI.@]
04119  */
04120 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler,
04121                                     DWORD filter, LPVOID context,
04122                                     PINSTALLUI_HANDLER_RECORD prev )
04123 {
04124     TRACE("%p %08x %p %p\n", handler, filter, context, prev);
04125 
04126     if (prev)
04127         *prev = gUIHandlerRecord;
04128 
04129     gUIHandlerRecord = handler;
04130     gUIFilter        = filter;
04131     gUIContext       = context;
04132 
04133     return ERROR_SUCCESS;
04134 }
04135 
04136 /***********************************************************************
04137  * MsiInstallMissingComponentA     [MSI.@]
04138  */
04139 UINT WINAPI MsiInstallMissingComponentA( LPCSTR product, LPCSTR component, INSTALLSTATE state )
04140 {
04141     UINT r;
04142     WCHAR *productW = NULL, *componentW = NULL;
04143 
04144     TRACE("%s, %s, %d\n", debugstr_a(product), debugstr_a(component), state);
04145 
04146     if (product && !(productW = strdupAtoW( product )))
04147         return ERROR_OUTOFMEMORY;
04148 
04149     if (component && !(componentW = strdupAtoW( component )))
04150     {
04151         msi_free( productW );
04152         return ERROR_OUTOFMEMORY;
04153     }
04154 
04155     r = MsiInstallMissingComponentW( productW, componentW, state );
04156     msi_free( productW );
04157     msi_free( componentW );
04158     return r;
04159 }
04160 
04161 /***********************************************************************
04162  * MsiInstallMissingComponentW     [MSI.@]
04163  */
04164 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
04165 {
04166     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
04167     return ERROR_SUCCESS;
04168 }
04169 
04170 /***********************************************************************
04171  * MsiBeginTransactionA     [MSI.@]
04172  */
04173 UINT WINAPI MsiBeginTransactionA( LPCSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
04174 {
04175     WCHAR *nameW;
04176     UINT r;
04177 
04178     FIXME("%s %u %p %p\n", debugstr_a(name), attrs, id, event);
04179 
04180     nameW = strdupAtoW( name );
04181     if (name && !nameW)
04182         return ERROR_OUTOFMEMORY;
04183 
04184     r = MsiBeginTransactionW( nameW, attrs, id, event );
04185     msi_free( nameW );
04186     return r;
04187 }
04188 
04189 /***********************************************************************
04190  * MsiBeginTransactionW     [MSI.@]
04191  */
04192 UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
04193 {
04194     FIXME("%s %u %p %p\n", debugstr_w(name), attrs, id, event);
04195 
04196     *id = (MSIHANDLE)0xdeadbeef;
04197     *event = (HANDLE)0xdeadbeef;
04198 
04199     return ERROR_SUCCESS;
04200 }
04201 
04202 /***********************************************************************
04203  * MsiEndTransaction     [MSI.@]
04204  */
04205 UINT WINAPI MsiEndTransaction( DWORD state )
04206 {
04207     FIXME("%u\n", state);
04208     return ERROR_SUCCESS;
04209 }

Generated on Thu May 24 2012 04:22:57 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.