FIXME("Not removing environment variable on uninstall!\n");
size = 0;
+ type = REG_SZ;
res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
(res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
goto done;
- if (res != ERROR_FILE_NOT_FOUND)
+ if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
+ {
+ /* Nothing to do. */
+ if (!value)
+ {
+ res = ERROR_SUCCESS;
+ goto done;
+ }
+
+ size = (lstrlenW(value) + 1) * sizeof(WCHAR);
+ newval = strdupW(value);
+ if (!newval)
+ {
+ res = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+ }
+ else
{
if (flags & ENV_ACT_SETABSENT)
{
goto done;
}
- size += (lstrlenW(value) + 1) * sizeof(WCHAR);
- newval = msi_alloc(size);
+ size = (lstrlenW(data) + 1) * sizeof(WCHAR);
+ if (flags & ENV_MOD_MASK)
+ {
+ DWORD mod_size;
+ int multiplier = 0;
+ if (flags & ENV_MOD_APPEND) multiplier++;
+ if (flags & ENV_MOD_PREFIX) multiplier++;
+ mod_size = (lstrlenW(value) + 1) * multiplier;
+ size += mod_size * sizeof(WCHAR);
+ }
+
+ newval = msi_alloc(size);
ptr = newval;
if (!newval)
{
goto done;
}
- if (!(flags & ENV_MOD_MASK))
- lstrcpyW(newval, value);
- else
+ if (flags & ENV_MOD_PREFIX)
{
- if (flags & ENV_MOD_PREFIX)
- {
- lstrcpyW(newval, value);
- lstrcatW(newval, szSemiColon);
- ptr = newval + lstrlenW(value) + 1;
- }
+ lstrcpyW(newval, value);
+ lstrcatW(newval, szSemiColon);
+ ptr = newval + lstrlenW(value) + 1;
+ }
- lstrcpyW(ptr, data);
+ lstrcpyW(ptr, data);
- if (flags & ENV_MOD_APPEND)
- {
- lstrcatW(newval, szSemiColon);
- lstrcatW(newval, value);
- }
- }
- }
- else if (value)
- {
- size = (lstrlenW(value) + 1) * sizeof(WCHAR);
- newval = msi_alloc(size);
- if (!newval)
+ if (flags & ENV_MOD_APPEND)
{
- res = ERROR_OUTOFMEMORY;
- goto done;
+ lstrcatW(newval, szSemiColon);
+ lstrcatW(newval, value);
}
-
- lstrcpyW(newval, value);
}
if (newval)
goto done;
}
+ /* file->dest may be shorter after the reallocation, so add a NULL
+ * terminator. This is needed for the call to strrchrW, as there will no
+ * longer be a NULL terminator within the bounds of the allocation in this case.
+ */
+ file->dest[size - 1] = '\0';
lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
while (!list_empty(&files.entry))
return r;
if (check_column_exists(av->db, av->colinfo->table, av->colinfo->column))
+ {
+ columns->ops->delete(columns);
return ERROR_BAD_QUERY_SYNTAX;
+ }
r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column);
if (r == ERROR_SUCCESS)
size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File);
WCHAR subpath[MAX_PATH];
WCHAR *buf;
+ DWORD len;
static const WCHAR starDotStarW[] = { '*','.','*',0 };
* here. Add two because we might need to add a backslash if the dir name
* isn't backslash-terminated.
*/
- buf = msi_alloc( (dirLen + max(fileLen, strlenW(starDotStarW)) + 2) * sizeof(WCHAR));
+ len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2;
+ buf = msi_alloc(len * sizeof(WCHAR));
if (!buf)
return ERROR_OUTOFMEMORY;
}
}
- if (!*appValue)
+ if (*appValue != buf)
msi_free(buf);
return rc;
}
}
+static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+ MSIHANDLE hrec;
+ IDispatch* dispatch;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ hrec = MsiCreateRecord(V_I4(&varg0));
+ if (!hrec)
+ return DISP_E_EXCEPTION;
+
+ hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
+ &DIID_Record, RecordImpl_Invoke, NULL, 0);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+ return hr;
+}
+
+static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ MSIHANDLE hpkg;
+ IDispatch* dispatch;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ if (pDispParams->cArgs == 0)
+ return DISP_E_TYPEMISMATCH;
+
+ if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
+ return DISP_E_TYPEMISMATCH;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ if (pDispParams->cArgs == 2)
+ {
+ hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+ }
+ else
+ {
+ V_VT(&varg1) = VT_I4;
+ V_I4(&varg1) = 0;
+ }
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ hr = create_session(hpkg, (IDispatch *)This, &dispatch);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
+
+ VariantInit(pVarResult);
+
+ VariantClear(&varg0);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ MSIHANDLE hdb;
+ IDispatch* dispatch;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
+ &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_UILevel(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+ INSTALLUILEVEL ui;
+
+ if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ ui = MsiSetInternalUI(V_I4(&varg0), NULL);
+ if (ui == INSTALLUILEVEL_NOCHANGE)
+ return DISP_E_EXCEPTION;
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
+ if (ui == INSTALLUILEVEL_NOCHANGE)
+ return DISP_E_EXCEPTION;
+
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = ui;
+ }
+
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_EnableLog(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_Version(WORD wFlags,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ DLLVERSIONINFO verinfo;
+ WCHAR version[MAX_PATH];
+
+ static const WCHAR format[] = {
+ '%','d','.','%','d','.','%','d','.','%','d',0};
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ verinfo.cbSize = sizeof(DLLVERSIONINFO);
+ hr = DllGetVersion(&verinfo);
+ if (FAILED(hr))
+ return hr;
+
+ sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
+ verinfo.dwBuildNumber, verinfo.dwPlatformID);
+
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(version);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HKEY hkey = NULL;
+ HRESULT hr;
+ UINT posValue;
+ DWORD type, size;
+ LPWSTR szString = NULL;
+ VARIANTARG varg0, varg1, varg2;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ /* Save valuePos so we can save puArgErr if we are unable to do our type
+ * conversions.
+ */
+ posValue = 2;
+ VariantInit(&varg2);
+ hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
+ if (FAILED(hr))
+ goto done;
+
+ if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
+ V_I4(&varg0) <= REG_INDEX_DYN_DATA)
+ {
+ V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
+ }
+
+ ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
+
+ /* Only VT_EMPTY case can do anything if the key doesn't exist. */
+ if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
+ {
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
+ switch (V_VT(&varg2))
+ {
+ /* Return VT_BOOL clarifying whether registry key exists or not. */
+ case VT_EMPTY:
+ V_VT(pVarResult) = VT_BOOL;
+ V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
+ break;
+
+ /* Return the value of specified key if it exists. */
+ case VT_BSTR:
+ ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
+ NULL, NULL, NULL, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ szString = msi_alloc(size);
+ if (!szString)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
+ &type, (LPBYTE)szString, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ msi_free(szString);
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ variant_from_registry_value(pVarResult, type,
+ (LPBYTE)szString, size);
+ msi_free(szString);
+ break;
+
+ /* Try to make it into VT_I4, can use VariantChangeType for this. */
+ default:
+ hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
+ if (FAILED(hr))
+ {
+ if (hr == DISP_E_TYPEMISMATCH)
+ *puArgErr = posValue;
+
+ goto done;
+ }
+
+ /* Retrieve class name or maximum value name or subkey name size. */
+ if (!V_I4(&varg2))
+ ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else if (V_I4(&varg2) > 0)
+ ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &size, NULL, NULL, NULL);
+ else /* V_I4(&varg2) < 0 */
+ ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ if (ret != ERROR_SUCCESS)
+ goto done;
+
+ szString = msi_alloc(++size * sizeof(WCHAR));
+ if (!szString)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ if (!V_I4(&varg2))
+ ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else if (V_I4(&varg2) > 0)
+ ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
+ &size, 0, 0, NULL, NULL);
+ else /* V_I4(&varg2) < 0 */
+ ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(szString);
+ }
+
+ msi_free(szString);
+ }
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ VariantClear(&varg2);
+ RegCloseKey(hkey);
+ return hr;
+}
+
+static HRESULT InstallerImpl_Environment(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileSize(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileVersion(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductState(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
+
+ VariantClear(&varg0);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ DWORD size;
+ LPWSTR str = NULL;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = NULL;
+
+ ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ str = msi_alloc(++size * sizeof(WCHAR));
+ if (!str)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ V_BSTR(pVarResult) = SysAllocString(str);
+ hr = S_OK;
+
+done:
+ msi_free(str);
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static void cleanup_products(IDispatch* dispatch, ULONG count)
+{
+ UINT i;
+ ListData* ldata = private_data((AutomationObject *)dispatch);
+
+ for (i = 0; i < count - 1; i++)
+ VariantClear(&ldata->pVars[i]);
+
+ ldata->ulCount = 0;
+ msi_free(ldata->pVars);
+
+ IDispatch_Release(dispatch);
+}
+
+static HRESULT InstallerImpl_Products(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ ULONG idx = 0;
+ ListData *ldata;
+ IDispatch *dispatch;
+ WCHAR product[GUID_SIZE];
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ /* Find number of products. */
+ while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
+ idx++;
+
+ if (ret != ERROR_NO_MORE_ITEMS)
+ return DISP_E_EXCEPTION;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+ hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
+ &DIID_StringList, ListImpl_Invoke,
+ ListImpl_Free, sizeof(ListData));
+ if (FAILED(hr))
+ return hr;
+
+ V_DISPATCH(pVarResult) = dispatch;
+
+ /* Save product strings. */
+ ldata = private_data((AutomationObject *)dispatch);
+ ldata->ulCount = 0;
+ ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
+ if (!ldata->pVars)
+ {
+ IDispatch_Release(dispatch);
+ return E_OUTOFMEMORY;
+ }
+
+ ldata->ulCount = idx;
+ for (idx = 0; idx < ldata->ulCount; idx++)
+ {
+ ret = MsiEnumProductsW(idx, product);
+ if (ret != ERROR_SUCCESS)
+ {
+ cleanup_products(dispatch, idx - 1);
+ return DISP_E_EXCEPTION;
+ }
+
+ VariantInit(&ldata->pVars[idx]);
+ V_VT(&ldata->pVars[idx]) = VT_BSTR;
+ V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
+ }
+
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ ULONG idx;
+ HRESULT hr;
+ ListData *ldata;
+ VARIANTARG varg0;
+ IDispatch* dispatch;
+ WCHAR product[GUID_SIZE];
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ /* Find number of related products. */
+ idx = 0;
+ do
+ {
+ ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
+ if (ret == ERROR_SUCCESS)
+ idx++;
+ } while (ret == ERROR_SUCCESS);
+
+ if (ret != ERROR_NO_MORE_ITEMS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
+ &DIID_StringList, ListImpl_Invoke,
+ ListImpl_Free, sizeof(ListData));
+ if (FAILED(hr))
+ goto done;
+
+ V_DISPATCH(pVarResult) = dispatch;
+
+ /* Save product strings. */
+ ldata = private_data((AutomationObject *)dispatch);
+ ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
+ if (!ldata->pVars)
+ {
+ IDispatch_Release(dispatch);
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ ldata->ulCount = idx;
+ for (idx = 0; idx < ldata->ulCount; idx++)
+ {
+ ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
+ if (ret != ERROR_SUCCESS)
+ {
+ cleanup_products(dispatch, idx - 1);
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ VariantInit(&ldata->pVars[idx]);
+ V_VT(&ldata->pVars[idx]) = VT_BSTR;
+ V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
+ }
+
+ hr = S_OK;
+
+done:
+ VariantClear(&varg0);
+ return hr;
+}
+
static HRESULT WINAPI InstallerImpl_Invoke(
AutomationObject* This,
DISPID dispIdMember,
EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{
- MSIHANDLE msiHandle;
- IDispatch *pDispatch = NULL;
- UINT ret;
- VARIANTARG varg0, varg1, varg2;
- HRESULT hr;
- LPWSTR szString = NULL;
- DWORD dwSize = 0;
- INSTALLUILEVEL ui;
-
- VariantInit(&varg0);
- VariantInit(&varg1);
- VariantInit(&varg2);
-
switch (dispIdMember)
{
case DISPID_INSTALLER_CREATERECORD:
- if (wFlags & DISPATCH_METHOD)
- {
- hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- V_VT(pVarResult) = VT_DISPATCH;
- if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
- {
- if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
- V_DISPATCH(pVarResult) = pDispatch;
- else
- ERR("Failed to create Record object, hresult 0x%08x\n", hr);
- }
- else
- {
- ERR("MsiCreateRecord failed\n");
- return DISP_E_EXCEPTION;
- }
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_CreateRecord(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_OPENPACKAGE:
- if (wFlags & DISPATCH_METHOD)
- {
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
- if (FAILED(hr))
- {
- VariantClear(&varg0);
- return hr;
- }
- V_VT(pVarResult) = VT_DISPATCH;
- if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
- {
- if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
- V_DISPATCH(pVarResult) = pDispatch;
- else
- ERR("Failed to create Session object, hresult 0x%08x\n", hr);
- }
- else
- {
- VariantClear(&varg0);
- ERR("MsiOpenPackageEx returned %d\n", ret);
- return DISP_E_EXCEPTION;
- }
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- case DISPID_INSTALLER_OPENDATABASE:
- if (wFlags & DISPATCH_METHOD)
- {
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
+ case DISPID_INSTALLER_OPENPRODUCT:
+ return InstallerImpl_OpenProduct(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
- if (FAILED(hr))
- {
- VariantClear(&varg0);
- return hr;
- }
+ case DISPID_INSTALLER_OPENDATABASE:
+ return InstallerImpl_OpenDatabase(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- V_VT(pVarResult) = VT_DISPATCH;
- if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
- {
- hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
- &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
- if (SUCCEEDED(hr))
- V_DISPATCH(pVarResult) = pDispatch;
- else
- ERR("Failed to create Database object: 0x%08x\n", hr);
- }
- else
- {
- VariantClear(&varg0);
- VariantClear(&varg1);
- ERR("MsiOpenDatabase returned %d\n", ret);
- return DISP_E_EXCEPTION;
- }
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ case DISPID_INSTALLER_SUMMARYINFORMATION:
+ return InstallerImpl_SummaryInformation(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
case DISPID_INSTALLER_UILEVEL:
- if (wFlags & DISPATCH_PROPERTYPUT)
- {
- hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- if ((ui = MsiSetInternalUI(V_I4(&varg0), NULL) == INSTALLUILEVEL_NOCHANGE))
- {
- ERR("MsiSetInternalUI failed\n");
- return DISP_E_EXCEPTION;
- }
- }
- else if (wFlags & DISPATCH_PROPERTYGET)
- {
- if ((ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL) == INSTALLUILEVEL_NOCHANGE))
- {
- ERR("MsiSetInternalUI failed\n");
- return DISP_E_EXCEPTION;
- }
+ return InstallerImpl_UILevel(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- V_VT(pVarResult) = VT_I4;
- V_I4(pVarResult) = ui;
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ case DISPID_INSTALLER_ENABLELOG:
+ return InstallerImpl_EnableLog(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_INSTALLPRODUCT:
- if (wFlags & DISPATCH_METHOD)
- {
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
- if (FAILED(hr))
- {
- VariantClear(&varg0);
- return hr;
- }
- if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
- {
- VariantClear(&varg1);
- VariantClear(&varg0);
- ERR("MsiInstallProduct returned %d\n", ret);
- return DISP_E_EXCEPTION;
- }
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_InstallProduct(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
case DISPID_INSTALLER_VERSION:
- if (wFlags & DISPATCH_PROPERTYGET) {
- DLLVERSIONINFO verinfo;
- WCHAR version[MAX_PATH];
+ return InstallerImpl_Version(wFlags, pVarResult,
+ pExcepInfo, puArgErr);
- static const WCHAR format[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
-
- verinfo.cbSize = sizeof(DLLVERSIONINFO);
- hr = DllGetVersion(&verinfo);
- if (FAILED(hr)) return hr;
-
- sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
- verinfo.dwBuildNumber, verinfo.dwPlatformID);
-
- V_VT(pVarResult) = VT_BSTR;
- V_BSTR(pVarResult) = SysAllocString(version);
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ case DISPID_INSTALLER_LASTERRORRECORD:
+ return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
case DISPID_INSTALLER_REGISTRYVALUE:
- if (wFlags & DISPATCH_METHOD) {
- HKEY hkey;
- DWORD dwType;
- UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
-
- hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
- if (FAILED(hr)) return hr;
- hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
- if (FAILED(hr))
- {
- VariantClear(&varg1);
- return hr;
- }
-
- if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
- V_I4(&varg0) <= REG_INDEX_DYN_DATA)
- V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
-
- ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
-
- /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
- switch (V_VT(&varg2))
- {
- case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
- V_VT(pVarResult) = VT_BOOL;
- V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
- break;
-
- case VT_BSTR: /* Return value of specified key if it exists */
- if (ret == ERROR_SUCCESS &&
- (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
- {
- if (!(szString = msi_alloc(dwSize)))
- ERR("Out of memory\n");
- else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
- variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
- }
-
- if (ret != ERROR_SUCCESS)
- {
- msi_free(szString);
- VariantClear(&varg2);
- VariantClear(&varg1);
- return DISP_E_BADINDEX;
- }
- break;
+ return InstallerImpl_RegistryValue(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
- default: /* Try to make it into VT_I4, can use VariantChangeType for this */
- hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
- if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
- if (FAILED(hr))
- {
- if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
- VariantClear(&varg2); /* Unknown type, so let's clear it */
- VariantClear(&varg1);
- return hr;
- }
+ case DISPID_INSTALLER_ENVIRONMENT:
+ return InstallerImpl_Environment(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- /* Retrieve class name or maximum value name or subkey name size */
- if (!V_I4(&varg2))
- ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- else if (V_I4(&varg2) > 0)
- ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
- else /* V_I4(&varg2) < 0 */
- ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
+ case DISPID_INSTALLER_FILEATTRIBUTES:
+ return InstallerImpl_FileAttributes(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
- if (ret == ERROR_SUCCESS)
- {
- if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
- ERR("Out of memory\n");
- else if (!V_I4(&varg2))
- ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- else if (V_I4(&varg2) > 0)
- ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
- else /* V_I4(&varg2) < 0 */
- ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
-
- if (szString && ret == ERROR_SUCCESS)
- {
- V_VT(pVarResult) = VT_BSTR;
- V_BSTR(pVarResult) = SysAllocString(szString);
- }
- }
- }
+ case DISPID_INSTALLER_FILESIZE:
+ return InstallerImpl_FileSize(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
- msi_free(szString);
- RegCloseKey(hkey);
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ case DISPID_INSTALLER_FILEVERSION:
+ return InstallerImpl_FileVersion(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_PRODUCTSTATE:
- if (wFlags & DISPATCH_PROPERTYGET) {
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- V_VT(pVarResult) = VT_I4;
- V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_ProductState(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_PRODUCTINFO:
- if (wFlags & DISPATCH_PROPERTYGET) {
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
- hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
- if (FAILED(hr))
- {
- VariantClear(&varg0);
- return hr;
- }
- V_VT(pVarResult) = VT_BSTR;
- V_BSTR(pVarResult) = NULL;
- if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
- {
- if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
- ERR("Out of memory\n");
- else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
- V_BSTR(pVarResult) = SysAllocString(szString);
- msi_free(szString);
- }
- if (ret != ERROR_SUCCESS)
- {
- ERR("MsiGetProductInfo returned %d\n", ret);
- VariantClear(&varg1);
- VariantClear(&varg0);
- return DISP_E_EXCEPTION;
- }
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_ProductInfo(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_PRODUCTS:
- if (wFlags & DISPATCH_PROPERTYGET)
- {
- ListData *ldata = NULL;
- ULONG idx = 0;
- WCHAR szProductBuf[GUID_SIZE];
-
- /* Find number of products */
- while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
- if (ret != ERROR_NO_MORE_ITEMS)
- {
- ERR("MsiEnumProducts returned %d\n", ret);
- return DISP_E_EXCEPTION;
- }
-
- V_VT(pVarResult) = VT_DISPATCH;
- if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
- {
- V_DISPATCH(pVarResult) = pDispatch;
-
- /* Save product strings */
- ldata = private_data((AutomationObject *)pDispatch);
- if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
- ERR("Out of memory\n");
- else
- {
- ldata->ulCount = idx;
- for (idx = 0; idx < ldata->ulCount; idx++)
- {
- ret = MsiEnumProductsW(idx, szProductBuf);
- VariantInit(&ldata->pVars[idx]);
- V_VT(&ldata->pVars[idx]) = VT_BSTR;
- V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
- }
- }
- }
- else
- ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_Products(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
case DISPID_INSTALLER_RELATEDPRODUCTS:
- if (wFlags & DISPATCH_PROPERTYGET)
- {
- ListData *ldata = NULL;
- ULONG idx = 0;
- WCHAR szProductBuf[GUID_SIZE];
-
- hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
- if (FAILED(hr)) return hr;
-
- /* Find number of related products */
- while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
- if (ret != ERROR_NO_MORE_ITEMS)
- {
- VariantClear(&varg0);
- ERR("MsiEnumRelatedProducts returned %d\n", ret);
- return DISP_E_EXCEPTION;
- }
-
- V_VT(pVarResult) = VT_DISPATCH;
- if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
- {
- V_DISPATCH(pVarResult) = pDispatch;
-
- /* Save product strings */
- ldata = private_data((AutomationObject *)pDispatch);
- if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
- ERR("Out of memory\n");
- else
- {
- ldata->ulCount = idx;
- for (idx = 0; idx < ldata->ulCount; idx++)
- {
- ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
- VariantInit(&ldata->pVars[idx]);
- V_VT(&ldata->pVars[idx]) = VT_BSTR;
- V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
- }
- }
- }
- else
- ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
- }
- else return DISP_E_MEMBERNOTFOUND;
- break;
+ return InstallerImpl_RelatedProducts(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
- default:
+ default:
return DISP_E_MEMBERNOTFOUND;
}
-
- VariantClear(&varg2);
- VariantClear(&varg1);
- VariantClear(&varg0);
-
- return S_OK;
}
/* Wrapper around create_automation_object to create an installer object. */
* Any binary data in a table is a reference to a stream.
*/
+typedef struct tagMSITRANSFORM {
+ struct list entry;
+ IStorage *stg;
+} MSITRANSFORM;
+
+typedef struct tagMSISTREAM {
+ struct list entry;
+ IStream *stm;
+} MSISTREAM;
+
+static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
+{
+ MSISTREAM *stream;
+
+ LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
+ {
+ HRESULT r;
+ STATSTG stat;
+
+ r = IStream_Stat( stream->stm, &stat, 0 );
+ if( FAILED( r ) )
+ {
+ WARN("failed to stat stream r = %08x!\n", r);
+ continue;
+ }
+
+ if( !lstrcmpW( name, stat.pwcsName ) )
+ {
+ TRACE("found %s\n", debugstr_w(name));
+ *stm = stream->stm;
+ CoTaskMemFree( stat.pwcsName );
+ return ERROR_SUCCESS;
+ }
+
+ CoTaskMemFree( stat.pwcsName );
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
+{
+ IStream *stream;
+
+ if (find_open_stream( db, name, &stream ) == ERROR_SUCCESS)
+ {
+ HRESULT r;
+ LARGE_INTEGER pos;
+
+ r = IStream_Clone( stream, stm );
+ if( FAILED( r ) )
+ {
+ WARN("failed to clone stream r = %08x!\n", r);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ pos.QuadPart = 0;
+ r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
+ if( FAILED( r ) )
+ {
+ IStream_Release( *stm );
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ return ERROR_SUCCESS;
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
+{
+ LPWSTR encname;
+ HRESULT r;
+
+ encname = encode_streamname(FALSE, stname);
+
+ TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
+
+ if (clone_open_stream( db, encname, stm ) == ERROR_SUCCESS)
+ {
+ msi_free( encname );
+ return ERROR_SUCCESS;
+ }
+
+ r = IStorage_OpenStream( db->storage, encname, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
+ if( FAILED( r ) )
+ {
+ MSITRANSFORM *transform;
+
+ LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
+ {
+ TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
+ r = IStorage_OpenStream( transform->stg, encname, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
+ if (SUCCEEDED(r))
+ break;
+ }
+ }
+
+ msi_free( encname );
+
+ if( SUCCEEDED(r) )
+ {
+ MSISTREAM *stream;
+
+ stream = msi_alloc( sizeof(MSISTREAM) );
+ if( !stream )
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ stream->stm = *stm;
+ IStream_AddRef( *stm );
+ list_add_tail( &db->streams, &stream->entry );
+ }
+
+ return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
+}
+
+UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
+ USHORT **pdata, UINT *psz )
+{
+ HRESULT r;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ VOID *data;
+ ULONG sz, count;
+ IStream *stm = NULL;
+ STATSTG stat;
+
+ r = db_get_raw_stream( db, stname, &stm );
+ if( r != ERROR_SUCCESS)
+ return ret;
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
+ if( FAILED( r ) )
+ {
+ WARN("open stream failed r = %08x!\n", r);
+ goto end;
+ }
+
+ if( stat.cbSize.QuadPart >> 32 )
+ {
+ WARN("Too big!\n");
+ goto end;
+ }
+
+ sz = stat.cbSize.QuadPart;
+ data = msi_alloc( sz );
+ if( !data )
+ {
+ WARN("couldn't allocate memory r=%08x!\n", r);
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+
+ r = IStream_Read(stm, data, sz, &count );
+ if( FAILED( r ) || ( count != sz ) )
+ {
+ msi_free( data );
+ WARN("read stream failed r = %08x!\n", r);
+ goto end;
+ }
+
+ *pdata = data;
+ *psz = sz;
+ ret = ERROR_SUCCESS;
+
+end:
+ IStream_Release( stm );
+
+ return ret;
+}
+
+void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
+{
+ MSITRANSFORM *t;
+
+ t = msi_alloc( sizeof *t );
+ t->stg = stg;
+ IStorage_AddRef( stg );
+ list_add_tail( &db->transforms, &t->entry );
+}
+
+static void free_transforms( MSIDATABASE *db )
+{
+ while( !list_empty( &db->transforms ) )
+ {
+ MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
+ MSITRANSFORM, entry );
+ list_remove( &t->entry );
+ IStorage_Release( t->stg );
+ msi_free( t );
+ }
+}
+
+static void free_streams( MSIDATABASE *db )
+{
+ while( !list_empty( &db->streams ) )
+ {
+ MSISTREAM *s = LIST_ENTRY( list_head( &db->streams ),
+ MSISTREAM, entry );
+ list_remove( &s->entry );
+ IStream_Release( s->stm );
+ msi_free( s );
+ }
+}
+
static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
{
MSIDATABASE *db = (MSIDATABASE *) arg;
msi_free(db->path);
free_cached_tables( db );
- msi_free_transforms( db );
+ free_streams( db );
+ free_transforms( db );
msi_destroy_stringtable( db->strings );
IStorage_Release( db->storage );
if (db->deletefile)
db->deletefile = strdupW( szDBPath );
list_init( &db->tables );
list_init( &db->transforms );
+ list_init( &db->streams );
db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
if( !db->strings )
static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
{
- UINT r;
+ UINT r = ERROR_OUTOFMEMORY;
DWORD size;
MSIQUERY *view;
- LPWSTR create_sql;
+ LPWSTR create_sql = NULL;
LPWSTR prelude, columns_sql, postlude;
prelude = msi_build_createsql_prelude(labels[0]);
postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */
if (!prelude || !columns_sql || !postlude)
- return ERROR_OUTOFMEMORY;
+ goto done;
size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1;
create_sql = msi_alloc(size * sizeof(WCHAR));
if (!create_sql)
- return ERROR_OUTOFMEMORY;
+ goto done;
lstrcpyW(create_sql, prelude);
lstrcatW(create_sql, columns_sql);
lstrcatW(create_sql, postlude);
- msi_free(prelude);
- msi_free(columns_sql);
- msi_free(postlude);
-
r = MSI_DatabaseOpenViewW( db, create_sql, &view );
- msi_free(create_sql);
-
if (r != ERROR_SUCCESS)
- return r;
+ goto done;
r = MSI_ViewExecute(view, NULL);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
+done:
+ msi_free(prelude);
+ msi_free(columns_sql);
+ msi_free(postlude);
+ msi_free(create_sql);
return r;
}
while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
{
r = MSI_ViewModify(view, MSIMODIFY_DELETE, rec);
+ msiobj_release(&rec->hdr);
if (r != ERROR_SUCCESS)
goto done;
}
goto end;
}
+ *numtypes = count;
for (i=1; i<=count; i++ )
{
(*types)[i-1] = strdupW(MSI_RecordGetString(prec, i));
static void free_merge_table(MERGETABLE *table)
{
- UINT i;
+ UINT i;
- if (table->labels != NULL)
- {
- for (i = 0; i < table->numlabels; i++)
- msi_free(table->labels[i]);
- msi_free(table->labels);
- }
+ if (table->labels != NULL)
+ {
+ for (i = 0; i < table->numlabels; i++)
+ msi_free(table->labels[i]);
- if (table->columns != NULL)
- {
- for (i = 0; i < table->numcolumns; i++)
- msi_free(table->columns[i]);
- msi_free(table->columns);
- }
+ msi_free(table->labels);
+ }
- if (table->types != NULL)
- {
- for (i = 0; i < table->numtypes; i++)
- msi_free(table->types[i]);
- msi_free(table->types);
- }
- msi_free(table->name);
- merge_free_rows(table);
+ if (table->columns != NULL)
+ {
+ for (i = 0; i < table->numcolumns; i++)
+ msi_free(table->columns[i]);
- msi_free(table);
+ msi_free(table->columns);
+ }
+
+ if (table->types != NULL)
+ {
+ for (i = 0; i < table->numtypes; i++)
+ msi_free(table->types[i]);
+
+ msi_free(table->types);
+ }
+
+ msi_free(table->name);
+ merge_free_rows(table);
+
+ msi_free(table);
}
static UINT msi_get_merge_table (MSIDATABASE *db, LPCWSTR name, MERGETABLE **ptable)
LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
{
MERGETABLE *table = LIST_ENTRY(item, MERGETABLE, entry);
-
list_remove(&table->entry);
free_merge_table(table);
}
return ERROR_FUNCTION_FAILED;
}
+static UINT DROP_delete( struct tagMSIVIEW *view )
+{
+ MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
+
+ TRACE("%p\n", dv );
+
+ if( dv->table )
+ dv->table->ops->delete( dv->table );
+
+ msi_free( dv );
+
+ return ERROR_SUCCESS;
+}
+
static const MSIVIEWOPS drop_ops =
{
NULL,
DROP_get_dimensions,
NULL,
NULL,
- NULL,
+ DROP_delete,
NULL,
NULL,
NULL,
gle = copy_file(file, source);
TRACE("Overwriting existing file: %d\n", gle);
}
- if ((gle == ERROR_SHARING_VIOLATION) || (gle == ERROR_USER_MAPPED_FILE))
+ if (gle == ERROR_SHARING_VIOLATION || gle == ERROR_USER_MAPPED_FILE)
{
WCHAR tmpfileW[MAX_PATH], *pathW, *p;
DWORD len;
static UINT JOIN_delete( struct tagMSIVIEW *view )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
- JOINTABLE *table;
+ struct list *item, *cursor;
TRACE("%p\n", jv );
- LIST_FOR_EACH_ENTRY(table, &jv->tables, JOINTABLE, entry)
+ LIST_FOR_EACH_SAFE(item, cursor, &jv->tables)
{
+ JOINTABLE* table = LIST_ENTRY(item, JOINTABLE, entry);
+
+ list_remove(&table->entry);
table->view->ops->delete(table->view);
table->view = NULL;
+ msi_free(table);
}
msi_free(jv);
if( r != ERROR_SUCCESS )
{
WARN("can't create table: %s\n", debugstr_w(tables));
+ msi_free(table);
r = ERROR_BAD_QUERY_SYNTAX;
goto end;
}
- r = table->view->ops->get_dimensions( table->view, NULL, &table->columns );
+ r = table->view->ops->get_dimensions( table->view, NULL,
+ &table->columns );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
data->curfile = strdupAtoW(pfdin->psz1);
if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
&attrs, data->user))
+ {
+ /* We're not extracting this file, so free the filename. */
+ msi_free(data->curfile);
+ data->curfile = NULL;
goto done;
+ }
TRACE("extracting %s\n", debugstr_w(path));
if (handle != INVALID_HANDLE_VALUE) goto done;
err = GetLastError();
}
- if ((err == ERROR_SHARING_VIOLATION) || (err == ERROR_USER_MAPPED_FILE))
+ if (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE)
{
WCHAR tmpfileW[MAX_PATH], *tmppathW, *p;
DWORD len;
WCHAR packagecode[GUID_SIZE];
BOOL badconfig = FALSE;
LONG res;
- DWORD save, type = REG_NONE;
+ DWORD type = REG_NONE;
static WCHAR empty[] = {0};
static const WCHAR sourcelist[] = {
if (pcchValueBuf)
{
- save = *pcchValueBuf;
-
- if (strlenW(val) < *pcchValueBuf)
- r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
- else if (szValue->str.a || szValue->str.w)
- r = ERROR_MORE_DATA;
+ /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
+ * out. Also, *pcchValueBuf may be uninitialized in this case, so we
+ * can't rely on its value.
+ */
+ if (szValue->str.a || szValue->str.w)
+ {
+ DWORD size = *pcchValueBuf;
+ if (strlenW(val) < size)
+ r = msi_strcpy_to_awstring(val, szValue, &size);
+ else
+ {
+ r = ERROR_MORE_DATA;
+ }
+ }
if (!badconfig)
*pcchValueBuf = lstrlenW(val);
- else if (r == ERROR_SUCCESS)
- {
- *pcchValueBuf = save;
- r = ERROR_BAD_CONFIGURATION;
- }
}
- else if (badconfig)
+
+ if (badconfig)
r = ERROR_BAD_CONFIGURATION;
if (val != empty)
LPCWSTR mode;
struct list tables;
struct list transforms;
+ struct list streams;
} MSIDATABASE;
typedef struct tagMSIVIEW MSIVIEW;
extern void msi_free_handle_table(void);
extern void free_cached_tables( MSIDATABASE *db );
-extern void msi_free_transforms( MSIDATABASE *db );
extern UINT MSI_CommitTables( MSIDATABASE *db );
BOOL preserve_case );
/* record internals */
+extern void MSI_CloseRecord( MSIOBJECTHDR * );
extern UINT MSI_RecordSetIStream( MSIRECORD *, UINT, IStream *);
extern UINT MSI_RecordGetIStream( MSIRECORD *, UINT, IStream **);
extern const WCHAR *MSI_RecordGetString( const MSIRECORD *, UINT );
extern BOOL MSI_RecordsAreEqual( MSIRECORD *, MSIRECORD * );
/* stream internals */
-extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
extern void enum_stream_names( IStorage *stg );
+extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in);
extern BOOL decode_streamname(LPCWSTR in, LPWSTR out);
/* database internals */
+extern UINT db_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** );
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE );
-extern LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename );
+extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename );
extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR);
extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR);
extern UINT msi_clone_properties(MSIPACKAGE *);
Session* OpenPackage(
[in] VARIANT PackagePath,
[in, optional, defaultvalue(0)] long Options);
+ [id(DISPID_INSTALLER_OPENPRODUCT)]
+ Session* OpenProduct(
+ [in] BSTR ProductCode);
+ [id(DISPID_INSTALLER_SUMMARYINFORMATION)]
+ SummaryInfo* SummaryInformation(
+ [in] BSTR PackagePath,
+ [in, optional, defaultvalue(0)] long UpdateCount);
[id(DISPID_INSTALLER_OPENDATABASE)]
Database *OpenDatabase(
[in] BSTR DatabasePath,
[in] VARIANT OpenMode);
+ [id(DISPID_INSTALLER_ENABLELOG)]
+ void EnableLog(
+ [in] BSTR LogMode,
+ [in] BSTR LogFile);
[id(DISPID_INSTALLER_INSTALLPRODUCT)]
void InstallProduct(
[in] BSTR PackagePath,
[in, optional, defaultvalue("0")] BSTR PropertyValues);
[id(DISPID_INSTALLER_VERSION)]
BSTR Version();
+ [id(DISPID_INSTALLER_LASTERRORRECORD)]
+ Record* LastErrorRecord();
[id(DISPID_INSTALLER_REGISTRYVALUE), propget]
BSTR RegistryValue(
[in] VARIANT Root,
[in] BSTR Key,
[in, optional] VARIANT Value);
+ [id(DISPID_INSTALLER_ENVIRONMENT), propget]
+ BSTR Environment([in] BSTR Variable);
+ [id(DISPID_INSTALLER_ENVIRONMENT), propput]
+ void Environment(
+ [in] BSTR Variable,
+ [in] BSTR rhs);
+ [id(DISPID_INSTALLER_FILEATTRIBUTES)]
+ long FileAttributes([in] BSTR FilePath);
+ [id(DISPID_INSTALLER_FILESIZE)]
+ long FileSize([in] BSTR FilePath);
+ [id(DISPID_INSTALLER_FILEVERSION)]
+ BSTR FileVersion(
+ [in] BSTR FilePath,
+ [in, optional] VARIANT Language);
[id(DISPID_INSTALLER_PRODUCTSTATE), propget]
MsiInstallState ProductState(
[in] BSTR Product);
#define DISPID_INSTALLER_CREATERECORD 1
#define DISPID_INSTALLER_OPENPACKAGE 2
+#define DISPID_INSTALLER_OPENPRODUCT 3
#define DISPID_INSTALLER_OPENDATABASE 4
+#define DISPID_INSTALLER_SUMMARYINFORMATION 5
#define DISPID_INSTALLER_UILEVEL 6
+#define DISPID_INSTALLER_ENABLELOG 7
#define DISPID_INSTALLER_INSTALLPRODUCT 8
#define DISPID_INSTALLER_VERSION 9
+#define DISPID_INSTALLER_LASTERRORRECORD 10
#define DISPID_INSTALLER_REGISTRYVALUE 11
+#define DISPID_INSTALLER_ENVIRONMENT 12
+#define DISPID_INSTALLER_FILEATTRIBUTES 13
+#define DISPID_INSTALLER_FILESIZE 15
+#define DISPID_INSTALLER_FILEVERSION 16
#define DISPID_INSTALLER_PRODUCTSTATE 17
#define DISPID_INSTALLER_PRODUCTINFO 18
#define DISPID_INSTALLER_PRODUCTS 35
return r;
}
+static void adjust_allusers_property( MSIPACKAGE *package )
+{
+ /* FIXME: this should depend on the user's privileges */
+ if (msi_get_property_int( package, szAllUsers, 0 ) == 2)
+ {
+ TRACE("resetting ALLUSERS property from 2 to 1\n");
+ MSI_SetPropertyW( package, szAllUsers, szOne );
+ }
+}
+
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
{
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
msi_load_admin_properties( package );
+
+ adjust_allusers_property( package );
}
return package;
* we should read all the tables to memory, then open the
* database to read binary streams on demand.
*/
-static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
+static UINT copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
{
WCHAR path[MAX_PATH];
if( !CopyFileW( szPackage, filename, FALSE ) )
{
+ UINT error = GetLastError();
+ ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error);
DeleteFileW( filename );
- ERR("failed to copy package %s\n", debugstr_w(szPackage) );
- return szPackage;
+ return error;
}
- TRACE("Opening relocated package %s\n", debugstr_w( filename ));
- return filename;
+ return ERROR_SUCCESS;
}
-LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
+UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
{
LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
DWORD size = 0;
cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
{
+ UINT error = GetLastError();
HeapFree( GetProcessHeap(), 0, cache_entry );
- return szUrl;
+ return error;
}
lstrcpyW( filename, cache_entry->lpszLocalFileName );
HeapFree( GetProcessHeap(), 0, cache_entry );
- return filename;
+ return ERROR_SUCCESS;
}
hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
if ( FAILED(hr) )
- return szUrl;
+ {
+ WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
+ return ERROR_FUNCTION_FAILED;
+ }
- return filename;
+ return ERROR_SUCCESS;
}
static UINT msi_get_local_package_name( LPWSTR path )
MSIHANDLE handle;
LPWSTR ptr, base_url = NULL;
UINT r;
- WCHAR temppath[MAX_PATH], localfile[MAX_PATH];
+ WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH];
LPCWSTR file = szPackage;
TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
{
if ( UrlIsW( szPackage, URLIS_URL ) )
{
- file = msi_download_file( szPackage, temppath );
- if ( file != szPackage )
- file = copy_package_to_temp( file, temppath );
+ r = msi_download_file( szPackage, cachefile );
+ if ( r != ERROR_SUCCESS )
+ return r;
+
+ r = copy_package_to_temp( cachefile, temppath );
+ if ( r != ERROR_SUCCESS )
+ return r;
+
+ file = temppath;
base_url = strdupW( szPackage );
if ( !base_url )
if (ptr) *(ptr + 1) = '\0';
}
else
- file = copy_package_to_temp( szPackage, temppath );
+ {
+ r = copy_package_to_temp( szPackage, temppath );
+ if ( r != ERROR_SUCCESS )
+ return r;
+
+ file = temppath;
+ }
r = msi_get_local_package_name( localfile );
if (r != ERROR_SUCCESS)
return GetLastError();
}
+ TRACE("Opening relocated package %s\n", debugstr_w( file ));
+
/* transforms that add binary streams require that we open the database
* read/write, which is safe because we always create a copy that is thrown
* away when we're done.
}
}
-static void MSI_CloseRecord( MSIOBJECTHDR *arg )
+void MSI_CloseRecord( MSIOBJECTHDR *arg )
{
MSIRECORD *rec = (MSIRECORD *) arg;
UINT i;
LPCWSTR command;
DWORD n, len;
UINT r;
- MSIVIEW **view; /* view structure for the resulting query */
+ MSIVIEW **view; /* View structure for the resulting query. This value
+ * tracks the view currently being created so we can free
+ * this view on syntax error.
+ */
struct list *mem;
} SQL_input;
static struct expr * EXPR_sval( void *info, const struct sql_str *str );
static struct expr * EXPR_wildcard( void *info );
+#define PARSER_BUBBLE_UP_VIEW( sql, result, current_view ) \
+ *sql->view = current_view; \
+ result = current_view
+
/* Line 189 of yacc.c */
-#line 154 "sql.tab.c"
+#line 161 "sql.tab.c"
/* Enabling traces. */
#ifndef YYDEBUG
{
/* Line 214 of yacc.c */
-#line 76 "sql.y"
+#line 83 "sql.y"
struct sql_str str;
LPWSTR string;
/* Line 214 of yacc.c */
-#line 265 "sql.tab.c"
+#line 272 "sql.tab.c"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
/* Line 264 of yacc.c */
-#line 277 "sql.tab.c"
+#line 284 "sql.tab.c"
#ifdef short
# undef short
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 126, 126, 134, 135, 136, 137, 138, 139, 140,
- 144, 154, 167, 183, 198, 208, 221, 234, 244, 254,
- 267, 271, 278, 291, 301, 311, 318, 327, 331, 335,
- 342, 346, 353, 357, 361, 365, 369, 373, 377, 384,
- 393, 406, 410, 414, 430, 451, 452, 456, 463, 464,
- 480, 490, 502, 507, 516, 522, 528, 534, 540, 546,
- 552, 558, 564, 570, 576, 585, 586, 590, 597, 608,
- 609, 617, 625, 631, 637, 643, 652, 661, 667, 676,
- 683, 691
+ 0, 133, 133, 141, 142, 143, 144, 145, 146, 147,
+ 151, 162, 176, 193, 209, 220, 234, 248, 259, 270,
+ 284, 288, 295, 310, 320, 330, 337, 346, 350, 354,
+ 361, 365, 372, 376, 380, 384, 388, 392, 396, 403,
+ 412, 425, 429, 433, 448, 468, 469, 473, 480, 481,
+ 496, 508, 523, 528, 537, 543, 549, 555, 561, 567,
+ 573, 579, 585, 591, 597, 606, 607, 611, 618, 629,
+ 630, 638, 646, 652, 658, 664, 673, 682, 688, 697,
+ 704, 712
};
#endif
case 2:
/* Line 1455 of yacc.c */
-#line 127 "sql.y"
+#line 134 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
*sql->view = (yyvsp[(1) - (1)].query);
case 10:
/* Line 1455 of yacc.c */
-#line 145 "sql.y"
+#line 152 "sql.y"
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
INSERT_CreateView( sql->db, &insert, (yyvsp[(3) - (10)].string), (yyvsp[(5) - (10)].column_list), (yyvsp[(9) - (10)].column_list), FALSE );
if( !insert )
YYABORT;
- (yyval.query) = insert;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), insert );
;}
break;
case 11:
/* Line 1455 of yacc.c */
-#line 155 "sql.y"
+#line 163 "sql.y"
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
INSERT_CreateView( sql->db, &insert, (yyvsp[(3) - (11)].string), (yyvsp[(5) - (11)].column_list), (yyvsp[(9) - (11)].column_list), TRUE );
if( !insert )
YYABORT;
- (yyval.query) = insert;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), insert );
;}
break;
case 12:
/* Line 1455 of yacc.c */
-#line 168 "sql.y"
+#line 177 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
sql->r = r;
YYABORT;
}
- (yyval.query) = create;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), create );
;}
break;
case 13:
/* Line 1455 of yacc.c */
-#line 184 "sql.y"
+#line 194 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
CREATE_CreateView( sql->db, &create, (yyvsp[(3) - (7)].string), (yyvsp[(5) - (7)].column_list), TRUE );
if( !create )
YYABORT;
- (yyval.query) = create;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), create );
;}
break;
case 14:
/* Line 1455 of yacc.c */
-#line 199 "sql.y"
+#line 210 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *update = NULL;
UPDATE_CreateView( sql->db, &update, (yyvsp[(2) - (6)].string), (yyvsp[(4) - (6)].column_list), (yyvsp[(6) - (6)].expr) );
if( !update )
YYABORT;
- (yyval.query) = update;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), update );
;}
break;
case 15:
/* Line 1455 of yacc.c */
-#line 209 "sql.y"
+#line 221 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *update = NULL;
UPDATE_CreateView( sql->db, &update, (yyvsp[(2) - (4)].string), (yyvsp[(4) - (4)].column_list), NULL );
if( !update )
YYABORT;
- (yyval.query) = update;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), update );
;}
break;
case 16:
/* Line 1455 of yacc.c */
-#line 222 "sql.y"
+#line 235 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *delete = NULL;
DELETE_CreateView( sql->db, &delete, (yyvsp[(2) - (2)].query) );
if( !delete )
YYABORT;
- (yyval.query) = delete;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), delete );
;}
break;
case 17:
/* Line 1455 of yacc.c */
-#line 235 "sql.y"
+#line 249 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *alter = NULL;
ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (4)].string), NULL, (yyvsp[(4) - (4)].integer) );
if( !alter )
YYABORT;
- (yyval.query) = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
;}
break;
case 18:
/* Line 1455 of yacc.c */
-#line 245 "sql.y"
+#line 260 "sql.y"
{
SQL_input *sql = (SQL_input *)info;
MSIVIEW *alter = NULL;
ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (5)].string), (yyvsp[(5) - (5)].column_list), 0 );
if (!alter)
YYABORT;
- (yyval.query) = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
;}
break;
case 19:
/* Line 1455 of yacc.c */
-#line 255 "sql.y"
+#line 271 "sql.y"
{
SQL_input *sql = (SQL_input *)info;
MSIVIEW *alter = NULL;
ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (6)].string), (yyvsp[(5) - (6)].column_list), 1 );
if (!alter)
YYABORT;
- (yyval.query) = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
;}
break;
case 20:
/* Line 1455 of yacc.c */
-#line 268 "sql.y"
+#line 285 "sql.y"
{
(yyval.integer) = 1;
;}
case 21:
/* Line 1455 of yacc.c */
-#line 272 "sql.y"
+#line 289 "sql.y"
{
(yyval.integer) = -1;
;}
case 22:
/* Line 1455 of yacc.c */
-#line 279 "sql.y"
+#line 296 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* drop = NULL;
UINT r;
- (yyval.query) = NULL;
- r = DROP_CreateView( sql->db, &(yyval.query), (yyvsp[(3) - (3)].string) );
+ r = DROP_CreateView( sql->db, &drop, (yyvsp[(3) - (3)].string) );
if( r != ERROR_SUCCESS || !(yyval.query) )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), drop );
;}
break;
case 23:
/* Line 1455 of yacc.c */
-#line 292 "sql.y"
+#line 311 "sql.y"
{
if( SQL_MarkPrimaryKeys( &(yyvsp[(1) - (4)].column_list), (yyvsp[(4) - (4)].column_list) ) )
(yyval.column_list) = (yyvsp[(1) - (4)].column_list);
case 24:
/* Line 1455 of yacc.c */
-#line 302 "sql.y"
+#line 321 "sql.y"
{
column_info *ci;
case 25:
/* Line 1455 of yacc.c */
-#line 312 "sql.y"
+#line 331 "sql.y"
{
(yyval.column_list) = (yyvsp[(1) - (1)].column_list);
;}
case 26:
/* Line 1455 of yacc.c */
-#line 319 "sql.y"
+#line 338 "sql.y"
{
(yyval.column_list) = (yyvsp[(1) - (2)].column_list);
(yyval.column_list)->type = ((yyvsp[(2) - (2)].column_type) | MSITYPE_VALID);
case 27:
/* Line 1455 of yacc.c */
-#line 328 "sql.y"
+#line 347 "sql.y"
{
(yyval.column_type) = (yyvsp[(1) - (1)].column_type);
;}
case 28:
/* Line 1455 of yacc.c */
-#line 332 "sql.y"
+#line 351 "sql.y"
{
(yyval.column_type) = (yyvsp[(1) - (2)].column_type) | MSITYPE_LOCALIZABLE;
;}
case 29:
/* Line 1455 of yacc.c */
-#line 336 "sql.y"
+#line 355 "sql.y"
{
(yyval.column_type) = (yyvsp[(1) - (2)].column_type) | MSITYPE_TEMPORARY;
;}
case 30:
/* Line 1455 of yacc.c */
-#line 343 "sql.y"
+#line 362 "sql.y"
{
(yyval.column_type) |= MSITYPE_NULLABLE;
;}
case 31:
/* Line 1455 of yacc.c */
-#line 347 "sql.y"
+#line 366 "sql.y"
{
(yyval.column_type) = (yyvsp[(1) - (3)].column_type);
;}
case 32:
/* Line 1455 of yacc.c */
-#line 354 "sql.y"
+#line 373 "sql.y"
{
(yyval.column_type) = MSITYPE_STRING | 1;
;}
case 33:
/* Line 1455 of yacc.c */
-#line 358 "sql.y"
+#line 377 "sql.y"
{
(yyval.column_type) = MSITYPE_STRING | 0x400 | (yyvsp[(3) - (4)].column_type);
;}
case 34:
/* Line 1455 of yacc.c */
-#line 362 "sql.y"
+#line 381 "sql.y"
{
(yyval.column_type) = MSITYPE_STRING | 0x400;
;}
case 35:
/* Line 1455 of yacc.c */
-#line 366 "sql.y"
+#line 385 "sql.y"
{
(yyval.column_type) = 2 | 0x400;
;}
case 36:
/* Line 1455 of yacc.c */
-#line 370 "sql.y"
+#line 389 "sql.y"
{
(yyval.column_type) = 2 | 0x400;
;}
case 37:
/* Line 1455 of yacc.c */
-#line 374 "sql.y"
+#line 393 "sql.y"
{
(yyval.column_type) = 4;
;}
case 38:
/* Line 1455 of yacc.c */
-#line 378 "sql.y"
+#line 397 "sql.y"
{
(yyval.column_type) = MSITYPE_STRING | MSITYPE_VALID;
;}
case 39:
/* Line 1455 of yacc.c */
-#line 385 "sql.y"
+#line 404 "sql.y"
{
if( ( (yyvsp[(1) - (1)].integer) > 255 ) || ( (yyvsp[(1) - (1)].integer) < 0 ) )
YYABORT;
case 40:
/* Line 1455 of yacc.c */
-#line 394 "sql.y"
+#line 413 "sql.y"
{
UINT r;
case 42:
/* Line 1455 of yacc.c */
-#line 411 "sql.y"
+#line 430 "sql.y"
{
(yyval.query) = (yyvsp[(2) - (2)].query);
;}
case 43:
/* Line 1455 of yacc.c */
-#line 415 "sql.y"
+#line 434 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* distinct = NULL;
UINT r;
- (yyval.query) = NULL;
- r = DISTINCT_CreateView( sql->db, &(yyval.query), (yyvsp[(3) - (3)].query) );
+ r = DISTINCT_CreateView( sql->db, &distinct, (yyvsp[(3) - (3)].query) );
if (r != ERROR_SUCCESS)
- {
- (yyvsp[(3) - (3)].query)->ops->delete((yyvsp[(3) - (3)].query));
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), distinct );
;}
break;
case 44:
/* Line 1455 of yacc.c */
-#line 431 "sql.y"
+#line 449 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* select = NULL;
UINT r;
- (yyval.query) = NULL;
if( (yyvsp[(1) - (2)].column_list) )
{
- r = SELECT_CreateView( sql->db, &(yyval.query), (yyvsp[(2) - (2)].query), (yyvsp[(1) - (2)].column_list) );
+ r = SELECT_CreateView( sql->db, &select, (yyvsp[(2) - (2)].query), (yyvsp[(1) - (2)].column_list) );
if (r != ERROR_SUCCESS)
- {
- (yyvsp[(2) - (2)].query)->ops->delete((yyvsp[(2) - (2)].query));
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), select );
}
else
(yyval.query) = (yyvsp[(2) - (2)].query);
case 46:
/* Line 1455 of yacc.c */
-#line 453 "sql.y"
+#line 470 "sql.y"
{
(yyvsp[(1) - (3)].column_list)->next = (yyvsp[(3) - (3)].column_list);
;}
case 47:
/* Line 1455 of yacc.c */
-#line 457 "sql.y"
+#line 474 "sql.y"
{
(yyval.column_list) = NULL;
;}
case 49:
/* Line 1455 of yacc.c */
-#line 465 "sql.y"
+#line 482 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* where = NULL;
UINT r;
- (yyval.query) = NULL;
- r = WHERE_CreateView( sql->db, &(yyval.query), (yyvsp[(1) - (3)].query), (yyvsp[(3) - (3)].expr) );
+ r = WHERE_CreateView( sql->db, &where, (yyvsp[(1) - (3)].query), (yyvsp[(3) - (3)].expr) );
if( r != ERROR_SUCCESS )
- {
- (yyvsp[(1) - (3)].query)->ops->delete( (yyvsp[(1) - (3)].query) );
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), where );
;}
break;
case 50:
/* Line 1455 of yacc.c */
-#line 481 "sql.y"
+#line 497 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* table = NULL;
UINT r;
- (yyval.query) = NULL;
- r = TABLE_CreateView( sql->db, (yyvsp[(2) - (2)].string), &(yyval.query) );
+ r = TABLE_CreateView( sql->db, (yyvsp[(2) - (2)].string), &table );
if( r != ERROR_SUCCESS || !(yyval.query) )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), table );
;}
break;
case 51:
/* Line 1455 of yacc.c */
-#line 491 "sql.y"
+#line 509 "sql.y"
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* join = NULL;
UINT r;
- r = JOIN_CreateView( sql->db, &(yyval.query), (yyvsp[(2) - (2)].string) );
+ r = JOIN_CreateView( sql->db, &join, (yyvsp[(2) - (2)].string) );
if( r != ERROR_SUCCESS )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), join );
;}
break;
case 52:
/* Line 1455 of yacc.c */
-#line 503 "sql.y"
+#line 524 "sql.y"
{
(yyval.string) = (yyvsp[(1) - (1)].string);
;}
case 53:
/* Line 1455 of yacc.c */
-#line 508 "sql.y"
+#line 529 "sql.y"
{
(yyval.string) = parser_add_table( info, (yyvsp[(3) - (3)].string), (yyvsp[(1) - (3)].string) );
if (!(yyval.string))
case 54:
/* Line 1455 of yacc.c */
-#line 517 "sql.y"
+#line 538 "sql.y"
{
(yyval.expr) = (yyvsp[(2) - (3)].expr);
if( !(yyval.expr) )
case 55:
/* Line 1455 of yacc.c */
-#line 523 "sql.y"
+#line 544 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_AND, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 56:
/* Line 1455 of yacc.c */
-#line 529 "sql.y"
+#line 550 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_OR, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 57:
/* Line 1455 of yacc.c */
-#line 535 "sql.y"
+#line 556 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_EQ, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 58:
/* Line 1455 of yacc.c */
-#line 541 "sql.y"
+#line 562 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_GT, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 59:
/* Line 1455 of yacc.c */
-#line 547 "sql.y"
+#line 568 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_LT, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 60:
/* Line 1455 of yacc.c */
-#line 553 "sql.y"
+#line 574 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_LE, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 61:
/* Line 1455 of yacc.c */
-#line 559 "sql.y"
+#line 580 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_GE, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 62:
/* Line 1455 of yacc.c */
-#line 565 "sql.y"
+#line 586 "sql.y"
{
(yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_NE, (yyvsp[(3) - (3)].expr) );
if( !(yyval.expr) )
case 63:
/* Line 1455 of yacc.c */
-#line 571 "sql.y"
+#line 592 "sql.y"
{
(yyval.expr) = EXPR_unary( info, (yyvsp[(1) - (3)].expr), OP_ISNULL );
if( !(yyval.expr) )
case 64:
/* Line 1455 of yacc.c */
-#line 577 "sql.y"
+#line 598 "sql.y"
{
(yyval.expr) = EXPR_unary( info, (yyvsp[(1) - (4)].expr), OP_NOTNULL );
if( !(yyval.expr) )
case 67:
/* Line 1455 of yacc.c */
-#line 591 "sql.y"
+#line 612 "sql.y"
{
(yyval.column_list) = parser_alloc_column( info, NULL, NULL );
if( !(yyval.column_list) )
case 68:
/* Line 1455 of yacc.c */
-#line 598 "sql.y"
+#line 619 "sql.y"
{
(yyval.column_list) = parser_alloc_column( info, NULL, NULL );
if( !(yyval.column_list) )
case 70:
/* Line 1455 of yacc.c */
-#line 610 "sql.y"
+#line 631 "sql.y"
{
(yyval.column_list) = (yyvsp[(1) - (3)].column_list);
(yyval.column_list)->next = (yyvsp[(3) - (3)].column_list);
case 71:
/* Line 1455 of yacc.c */
-#line 618 "sql.y"
+#line 639 "sql.y"
{
(yyval.column_list) = (yyvsp[(1) - (3)].column_list);
(yyval.column_list)->val = (yyvsp[(3) - (3)].expr);
case 72:
/* Line 1455 of yacc.c */
-#line 626 "sql.y"
+#line 647 "sql.y"
{
(yyval.expr) = EXPR_ival( info, (yyvsp[(1) - (1)].integer) );
if( !(yyval.expr) )
case 73:
/* Line 1455 of yacc.c */
-#line 632 "sql.y"
+#line 653 "sql.y"
{
(yyval.expr) = EXPR_ival( info, -(yyvsp[(2) - (2)].integer) );
if( !(yyval.expr) )
case 74:
/* Line 1455 of yacc.c */
-#line 638 "sql.y"
+#line 659 "sql.y"
{
(yyval.expr) = EXPR_sval( info, &(yyvsp[(1) - (1)].str) );
if( !(yyval.expr) )
case 75:
/* Line 1455 of yacc.c */
-#line 644 "sql.y"
+#line 665 "sql.y"
{
(yyval.expr) = EXPR_wildcard( info );
if( !(yyval.expr) )
case 76:
/* Line 1455 of yacc.c */
-#line 653 "sql.y"
+#line 674 "sql.y"
{
(yyval.expr) = EXPR_column( info, (yyvsp[(1) - (1)].column_list) );
if( !(yyval.expr) )
case 77:
/* Line 1455 of yacc.c */
-#line 662 "sql.y"
+#line 683 "sql.y"
{
(yyval.column_list) = parser_alloc_column( info, (yyvsp[(1) - (3)].string), (yyvsp[(3) - (3)].string) );
if( !(yyval.column_list) )
case 78:
/* Line 1455 of yacc.c */
-#line 668 "sql.y"
+#line 689 "sql.y"
{
(yyval.column_list) = parser_alloc_column( info, NULL, (yyvsp[(1) - (1)].string) );
if( !(yyval.column_list) )
case 79:
/* Line 1455 of yacc.c */
-#line 677 "sql.y"
+#line 698 "sql.y"
{
(yyval.string) = (yyvsp[(1) - (1)].string);
;}
case 80:
/* Line 1455 of yacc.c */
-#line 684 "sql.y"
+#line 705 "sql.y"
{
if ( SQL_getstring( info, &(yyvsp[(1) - (1)].str), &(yyval.string) ) != ERROR_SUCCESS || !(yyval.string) )
YYABORT;
case 81:
/* Line 1455 of yacc.c */
-#line 692 "sql.y"
+#line 713 "sql.y"
{
(yyval.integer) = SQL_getint( info );
;}
/* Line 1455 of yacc.c */
-#line 2407 "sql.tab.c"
+#line 2428 "sql.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
/* Line 1675 of yacc.c */
-#line 697 "sql.y"
+#line 718 "sql.y"
static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table )
{
/* Line 1676 of yacc.c */
-#line 76 "sql.y"
+#line 83 "sql.y"
struct sql_str str;
LPWSTR string;
LPCWSTR command;
DWORD n, len;
UINT r;
- MSIVIEW **view; /* view structure for the resulting query */
+ MSIVIEW **view; /* View structure for the resulting query. This value
+ * tracks the view currently being created so we can free
+ * this view on syntax error.
+ */
struct list *mem;
} SQL_input;
static struct expr * EXPR_sval( void *info, const struct sql_str *str );
static struct expr * EXPR_wildcard( void *info );
+#define PARSER_BUBBLE_UP_VIEW( sql, result, current_view ) \
+ *sql->view = current_view; \
+ result = current_view
+
%}
%pure-parser
INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
if( !insert )
YYABORT;
- $$ = insert;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, insert );
}
| TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
{
INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
if( !insert )
YYABORT;
- $$ = insert;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, insert );
}
;
sql->r = r;
YYABORT;
}
- $$ = create;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, create );
}
| TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
{
CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
if( !create )
YYABORT;
- $$ = create;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, create );
}
;
UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
if( !update )
YYABORT;
- $$ = update;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, update );
}
| TK_UPDATE table TK_SET update_assign_list
{
UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
if( !update )
YYABORT;
- $$ = update;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, update );
}
;
DELETE_CreateView( sql->db, &delete, $2 );
if( !delete )
YYABORT;
- $$ = delete;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, delete );
}
;
ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
if( !alter )
YYABORT;
- $$ = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
}
| TK_ALTER TK_TABLE table TK_ADD column_and_type
{
ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
if (!alter)
YYABORT;
- $$ = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
}
| TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
{
ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
if (!alter)
YYABORT;
- $$ = alter;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
}
;
TK_DROP TK_TABLE table
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* drop = NULL;
UINT r;
- $$ = NULL;
- r = DROP_CreateView( sql->db, &$$, $3 );
+ r = DROP_CreateView( sql->db, &drop, $3 );
if( r != ERROR_SUCCESS || !$$ )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, drop );
}
;
| TK_SELECT TK_DISTINCT selectfrom
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* distinct = NULL;
UINT r;
- $$ = NULL;
- r = DISTINCT_CreateView( sql->db, &$$, $3 );
+ r = DISTINCT_CreateView( sql->db, &distinct, $3 );
if (r != ERROR_SUCCESS)
- {
- $3->ops->delete($3);
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, distinct );
}
;
selcollist from
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* select = NULL;
UINT r;
- $$ = NULL;
if( $1 )
{
- r = SELECT_CreateView( sql->db, &$$, $2, $1 );
+ r = SELECT_CreateView( sql->db, &select, $2, $1 );
if (r != ERROR_SUCCESS)
- {
- $2->ops->delete($2);
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, select );
}
else
$$ = $2;
| fromtable TK_WHERE expr
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* where = NULL;
UINT r;
- $$ = NULL;
- r = WHERE_CreateView( sql->db, &$$, $1, $3 );
+ r = WHERE_CreateView( sql->db, &where, $1, $3 );
if( r != ERROR_SUCCESS )
- {
- $1->ops->delete( $1 );
YYABORT;
- }
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, where );
}
;
TK_FROM table
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* table = NULL;
UINT r;
- $$ = NULL;
- r = TABLE_CreateView( sql->db, $2, &$$ );
+ r = TABLE_CreateView( sql->db, $2, &table );
if( r != ERROR_SUCCESS || !$$ )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, table );
}
| TK_FROM tablelist
{
SQL_input* sql = (SQL_input*) info;
+ MSIVIEW* join = NULL;
UINT r;
- r = JOIN_CreateView( sql->db, &$$, $2 );
+ r = JOIN_CreateView( sql->db, &join, $2 );
if( r != ERROR_SUCCESS )
YYABORT;
+
+ PARSER_BUBBLE_UP_VIEW( sql, $$, join );
}
;
if (sv->storages[i]->storage)
IStorage_Release(sv->storages[i]->storage);
+ msi_free(sv->storages[i]->name);
msi_free(sv->storages[i]);
}
msi_free(sv->storages);
sv->storages = NULL;
+ msi_free(sv);
return ERROR_SUCCESS;
}
for (i = 0; i < sv->num_rows; i++)
{
- if (sv->streams[i] && sv->streams[i]->stream)
- IStream_Release(sv->streams[i]->stream);
- msi_free(sv->streams[i]);
+ if (sv->streams[i])
+ {
+ if (sv->streams[i]->stream)
+ IStream_Release(sv->streams[i]->stream);
+
+ msi_free(sv->streams[i]->name);
+ msi_free(sv->streams[i]);
+ }
}
msi_free(sv->streams);
+ msi_free(sv);
return ERROR_SUCCESS;
}
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
-#define HASH_SIZE 0x101
#define LONG_STR_BYTES 3
typedef struct _msistring
{
- int hash_next;
UINT persistent_refcount;
UINT nonpersistent_refcount;
LPWSTR str;
UINT maxcount; /* the number of strings */
UINT freeslot;
UINT codepage;
- int hash[HASH_SIZE];
- msistring *strings; /* an array of strings (in the tree) */
+ UINT sortcount;
+ msistring *strings; /* an array of strings */
+ UINT *sorted; /* index */
};
-static UINT msistring_makehash( const WCHAR *str )
-{
- UINT hash = 0;
-
- if (str==NULL)
- return hash;
-
- while( *str )
- {
- hash ^= *str++;
- hash *= 53;
- hash = (hash<<5) | (hash>>27);
- }
- return hash % HASH_SIZE;
-}
-
static string_table *init_stringtable( int entries, UINT codepage )
{
string_table *st;
- int i;
if (codepage != CP_ACP && !IsValidCodePage(codepage))
{
return NULL;
if( entries < 1 )
entries = 1;
+
st->strings = msi_alloc_zero( sizeof (msistring) * entries );
if( !st->strings )
{
msi_free( st );
return NULL;
}
+
+ st->sorted = msi_alloc( sizeof (UINT) * entries );
+ if( !st->sorted )
+ {
+ msi_free( st->strings );
+ msi_free( st );
+ return NULL;
+ }
+
st->maxcount = entries;
st->freeslot = 1;
st->codepage = codepage;
-
- for( i=0; i<HASH_SIZE; i++ )
- st->hash[i] = -1;
+ st->sortcount = 0;
return st;
}
msi_free( st->strings[i].str );
}
msi_free( st->strings );
+ msi_free( st->sorted );
msi_free( st );
}
static int st_find_free_entry( string_table *st )
{
- UINT i, sz;
+ UINT i, sz, *s;
msistring *p;
TRACE("%p\n", st);
p = msi_realloc_zero( st->strings, sz*sizeof(msistring) );
if( !p )
return -1;
+
+ s = msi_realloc( st->sorted, sz*sizeof(UINT) );
+ if( !s )
+ {
+ msi_free( p );
+ return -1;
+ }
+
st->strings = p;
+ st->sorted = s;
+
st->freeslot = st->maxcount;
st->maxcount = sz;
if( st->strings[st->freeslot].persistent_refcount ||
return st->freeslot;
}
-static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, enum StringPersistence persistence )
+static int find_insert_index( const string_table *st, UINT string_id )
{
- UINT hash = msistring_makehash( str );
+ int i, c, low = 0, high = st->sortcount - 1;
+
+ while (low <= high)
+ {
+ i = (low + high) / 2;
+ c = lstrcmpW( st->strings[string_id].str, st->strings[st->sorted[i]].str );
+ if (c < 0)
+ high = i - 1;
+ else if (c > 0)
+ low = i + 1;
+ else
+ return -1; /* already exists */
+ }
+ return high + 1;
+}
+
+static void insert_string_sorted( string_table *st, UINT string_id )
+{
+ int i;
+
+ i = find_insert_index( st, string_id );
+ if (i == -1)
+ return;
+
+ memmove( &st->sorted[i] + 1, &st->sorted[i], (st->sortcount - i) * sizeof(UINT) );
+ st->sorted[i] = string_id;
+ st->sortcount++;
+}
+
+static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, enum StringPersistence persistence )
+{
if (persistence == StringPersistent)
{
st->strings[n].persistent_refcount = refcount;
st->strings[n].str = str;
- st->strings[n].hash_next = st->hash[hash];
- st->hash[hash] = n;
+ insert_string_sorted( st, n );
if( n < st->maxcount )
st->freeslot = n + 1;
*/
UINT msi_string2idW( const string_table *st, LPCWSTR str, UINT *id )
{
- UINT n, hash = msistring_makehash( str );
- msistring *se = st->strings;
+ int i, c, low = 0, high = st->sortcount - 1;
- for (n = st->hash[hash]; n != -1; n = st->strings[n].hash_next )
+ while (low <= high)
{
- if ((str == se[n].str) || !lstrcmpW(str, se[n].str))
+ i = (low + high) / 2;
+ c = lstrcmpW( str, st->strings[st->sorted[i]].str );
+
+ if (c < 0)
+ high = i - 1;
+ else if (c > 0)
+ low = i + 1;
+ else
{
- *id = n;
+ *id = st->sorted[i];
return ERROR_SUCCESS;
}
}
WCHAR name[1];
};
-typedef struct tagMSITRANSFORM {
- struct list entry;
- IStorage *stg;
-} MSITRANSFORM;
-
static const WCHAR szStringData[] = {
'_','S','t','r','i','n','g','D','a','t','a',0 };
static const WCHAR szStringPool[] = {
return -1;
}
-static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
+LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
{
DWORD count = MAX_STREAM_NAME;
DWORD ch, next;
return ret;
}
-static UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
-{
- LPWSTR encname;
- HRESULT r;
-
- encname = encode_streamname(FALSE, stname);
-
- TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
-
- r = IStorage_OpenStream(db->storage, encname, NULL,
- STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
- if( FAILED( r ) )
- {
- MSITRANSFORM *transform;
-
- LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
- {
- TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
- r = IStorage_OpenStream( transform->stg, encname, NULL,
- STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
- if (SUCCEEDED(r))
- break;
- }
- }
-
- msi_free( encname );
-
- return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
-}
-
-UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
- USHORT **pdata, UINT *psz )
-{
- HRESULT r;
- UINT ret = ERROR_FUNCTION_FAILED;
- VOID *data;
- ULONG sz, count;
- IStream *stm = NULL;
- STATSTG stat;
-
- r = db_get_raw_stream( db, stname, &stm );
- if( r != ERROR_SUCCESS)
- return ret;
- r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
- if( FAILED( r ) )
- {
- WARN("open stream failed r = %08x!\n", r);
- goto end;
- }
-
- if( stat.cbSize.QuadPart >> 32 )
- {
- WARN("Too big!\n");
- goto end;
- }
-
- sz = stat.cbSize.QuadPart;
- data = msi_alloc( sz );
- if( !data )
- {
- WARN("couldn't allocate memory r=%08x!\n", r);
- ret = ERROR_NOT_ENOUGH_MEMORY;
- goto end;
- }
-
- r = IStream_Read(stm, data, sz, &count );
- if( FAILED( r ) || ( count != sz ) )
- {
- msi_free( data );
- WARN("read stream failed r = %08x!\n", r);
- goto end;
- }
-
- *pdata = data;
- *psz = sz;
- ret = ERROR_SUCCESS;
-
-end:
- IStream_Release( stm );
-
- return ret;
-}
-
UINT write_stream_data( IStorage *stg, LPCWSTR stname,
LPCVOID data, UINT sz, BOOL bTable )
{
static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
{
MSITABLE *table;
+ LPWSTR tablename;
UINT size, offset, old_count;
UINT n;
- table = find_cached_table( db, name );
+ /* We may free name in msi_free_colinfo. */
+ tablename = strdupW( name );
+
+ table = find_cached_table( db, tablename );
old_count = table->col_count;
+ msi_free_colinfo( table->colinfo, table->col_count );
msi_free( table->colinfo );
table->colinfo = NULL;
- table_get_column_info( db, name, &table->colinfo, &table->col_count );
+ table_get_column_info( db, tablename, &table->colinfo, &table->col_count );
if (!table->col_count)
- return;
+ goto done;
size = msi_table_get_row_size( db, table->colinfo, table->col_count );
offset = table->colinfo[table->col_count - 1].offset;
if (old_count < table->col_count)
memset( &table->data[n][offset], 0, size - offset );
}
+
+done:
+ msi_free(tablename);
}
/* try to find the table name in the _Tables table */
tv->columns[i].hash_table = NULL;
}
- if ( row == num_rows - 1 )
- return ERROR_SUCCESS;
-
for (i = row + 1; i < num_rows; i++)
{
memcpy(tv->table->data[i - 1], tv->table->data[i], tv->row_size);
tv->table->data_persistent[i - 1] = tv->table->data_persistent[i];
}
+ msi_free(tv->table->data[num_rows - 1]);
+
return ERROR_SUCCESS;
}
if (r != ERROR_SUCCESS)
return r;
+ /* Close the original record */
+ MSI_CloseRecord(&rec->hdr);
+
count = MSI_RecordGetFieldCount(rec);
for (i = 0; i < count; i++)
MSI_RecordCopyField(curr, i + 1, rec, i + 1);
list_remove(&tv->table->entry);
free_table(tv->table);
- TABLE_delete(view);
done:
msiobj_release(&rec->hdr);
return ret;
}
-
-void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
-{
- MSITRANSFORM *t;
-
- t = msi_alloc( sizeof *t );
- t->stg = stg;
- IStorage_AddRef( stg );
- list_add_tail( &db->transforms, &t->entry );
-}
-
-void msi_free_transforms( MSIDATABASE *db )
-{
- while( !list_empty( &db->transforms ) )
- {
- MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
- MSITRANSFORM, entry );
- list_remove( &t->entry );
- IStorage_Release( t->stg );
- msi_free( t );
- }
-}
sr = lstrcmpW( l_str, r_str );
*val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
- ( cond->u.expr.op == OP_NE && ( sr != 0 ) ) ||
- ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
- ( cond->u.expr.op == OP_GT && ( sr > 0 ) );
+ ( cond->u.expr.op == OP_NE && ( sr != 0 ) );
return ERROR_SUCCESS;
}
switch( cond->u.expr.op )
{
case OP_EQ:
- case OP_GT:
- case OP_LT:
case OP_NE:
break;
default: