msi: automation: Implement Installer::Products and Installer::ProductState.
This commit is contained in:
parent
4ba4936dee
commit
05de3b03de
|
@ -82,6 +82,11 @@ interface AutomationObject {
|
||||||
* Structures for additional data required by specific automation objects
|
* Structures for additional data required by specific automation objects
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int iCount;
|
||||||
|
LPWSTR *pszStrings;
|
||||||
|
} StringListData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* The parent Installer object */
|
/* The parent Installer object */
|
||||||
IDispatch *pInstaller;
|
IDispatch *pInstaller;
|
||||||
|
@ -559,6 +564,60 @@ static HRESULT WINAPI RecordImpl_Invoke(
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI StringListImpl_Invoke(
|
||||||
|
AutomationObject* This,
|
||||||
|
DISPID dispIdMember,
|
||||||
|
REFIID riid,
|
||||||
|
LCID lcid,
|
||||||
|
WORD wFlags,
|
||||||
|
DISPPARAMS* pDispParams,
|
||||||
|
VARIANT* pVarResult,
|
||||||
|
EXCEPINFO* pExcepInfo,
|
||||||
|
UINT* puArgErr)
|
||||||
|
{
|
||||||
|
StringListData *data = (StringListData *)private_data(This);
|
||||||
|
HRESULT hr;
|
||||||
|
VARIANTARG varg0;
|
||||||
|
|
||||||
|
VariantInit(&varg0);
|
||||||
|
|
||||||
|
switch (dispIdMember)
|
||||||
|
{
|
||||||
|
case DISPID_STRINGLIST_ITEM:
|
||||||
|
if (wFlags & DISPATCH_PROPERTYGET) {
|
||||||
|
hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount)
|
||||||
|
return DISP_E_BADINDEX;
|
||||||
|
V_VT(pVarResult) = VT_BSTR;
|
||||||
|
V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISPID_STRINGLIST_COUNT:
|
||||||
|
if (wFlags & DISPATCH_PROPERTYGET) {
|
||||||
|
V_VT(pVarResult) = VT_I4;
|
||||||
|
V_I4(pVarResult) = data->iCount;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DISP_E_MEMBERNOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WINAPI StringListImpl_Free(AutomationObject *This)
|
||||||
|
{
|
||||||
|
StringListData *data = private_data(This);
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
for (idx=0; idx<data->iCount; idx++)
|
||||||
|
SysFreeString(data->pszStrings[idx]);
|
||||||
|
HeapFree(GetProcessHeap(), 0, data->pszStrings);
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI ViewImpl_Invoke(
|
static HRESULT WINAPI ViewImpl_Invoke(
|
||||||
AutomationObject* This,
|
AutomationObject* This,
|
||||||
DISPID dispIdMember,
|
DISPID dispIdMember,
|
||||||
|
@ -940,6 +999,53 @@ static HRESULT WINAPI InstallerImpl_Invoke(
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISPID_INSTALLER_PRODUCTS:
|
||||||
|
if (wFlags & DISPATCH_PROPERTYGET)
|
||||||
|
{
|
||||||
|
StringListData *sldata = NULL;
|
||||||
|
int idx = 0;
|
||||||
|
WCHAR szProductBuf[GUID_SIZE];
|
||||||
|
|
||||||
|
/* Find number of products */
|
||||||
|
do {
|
||||||
|
ret = MsiEnumProductsW(idx, szProductBuf);
|
||||||
|
if (ret == ERROR_SUCCESS) idx++;
|
||||||
|
} while (ret == ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS);
|
||||||
|
|
||||||
|
if (ret != ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS)
|
||||||
|
{
|
||||||
|
ERR("MsiEnumProducts returned %d\n", ret);
|
||||||
|
return DISP_E_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
V_VT(pVarResult) = VT_DISPATCH;
|
||||||
|
if (SUCCEEDED(create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
|
||||||
|
{
|
||||||
|
IDispatch_AddRef(pDispatch);
|
||||||
|
V_DISPATCH(pVarResult) = pDispatch;
|
||||||
|
|
||||||
|
/* Save product strings */
|
||||||
|
sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
|
||||||
|
sldata->iCount = idx;
|
||||||
|
sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount);
|
||||||
|
for (idx = 0; idx < sldata->iCount; idx++)
|
||||||
|
{
|
||||||
|
ret = MsiEnumProductsW(idx, szProductBuf);
|
||||||
|
sldata->pszStrings[idx] = SysAllocString(szProductBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DISP_E_MEMBERNOTFOUND;
|
return DISP_E_MEMBERNOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,22 @@ library WindowsInstaller
|
||||||
dispinterface Product;
|
dispinterface Product;
|
||||||
dispinterface Patch;
|
dispinterface Patch;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
msiInstallStateNotUsed = -7,
|
||||||
|
msiInstallStateBadConfig = -6,
|
||||||
|
msiInstallStateIncomplete = -5,
|
||||||
|
msiInstallStateSourceAbsent = -4,
|
||||||
|
msiInstallStateInvalidArg = -2,
|
||||||
|
msiInstallStateUnknown = -1,
|
||||||
|
msiInstallStateBroken = 0,
|
||||||
|
msiInstallStateAdvertised = 1,
|
||||||
|
msiInstallStateRemoved = 1,
|
||||||
|
msiInstallStateAbsent = 2,
|
||||||
|
msiInstallStateLocal = 3,
|
||||||
|
msiInstallStateSource = 4,
|
||||||
|
msiInstallStateDefault = 5
|
||||||
|
} MsiInstallState;
|
||||||
|
|
||||||
[ uuid(000C1090-0000-0000-C000-000000000046) ]
|
[ uuid(000C1090-0000-0000-C000-000000000046) ]
|
||||||
dispinterface Installer
|
dispinterface Installer
|
||||||
{
|
{
|
||||||
|
@ -47,6 +63,11 @@ library WindowsInstaller
|
||||||
Session* OpenPackage(
|
Session* OpenPackage(
|
||||||
[in] VARIANT PackagePath,
|
[in] VARIANT PackagePath,
|
||||||
[in, optional, defaultvalue(0)] long Options);
|
[in, optional, defaultvalue(0)] long Options);
|
||||||
|
[id(DISPID_INSTALLER_PRODUCTSTATE), propget]
|
||||||
|
MsiInstallState ProductState(
|
||||||
|
[in] BSTR Product);
|
||||||
|
[id(DISPID_INSTALLER_PRODUCTS), propget]
|
||||||
|
StringList *Products();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ uuid(000C1093-0000-0000-C000-000000000046) ]
|
[ uuid(000C1093-0000-0000-C000-000000000046) ]
|
||||||
|
@ -67,6 +88,10 @@ library WindowsInstaller
|
||||||
{
|
{
|
||||||
properties:
|
properties:
|
||||||
methods:
|
methods:
|
||||||
|
[id(DISPID_STRINGLIST_ITEM), propget]
|
||||||
|
BSTR Item(long Index);
|
||||||
|
[id(DISPID_STRINGLIST_COUNT), propget]
|
||||||
|
long Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ uuid(000C1096-0000-0000-C000-000000000046) ]
|
[ uuid(000C1096-0000-0000-C000-000000000046) ]
|
||||||
|
@ -142,22 +167,6 @@ library WindowsInstaller
|
||||||
msiRunModeCommit = 18
|
msiRunModeCommit = 18
|
||||||
} MsiRunMode;
|
} MsiRunMode;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
msiInstallStateNotUsed = -7,
|
|
||||||
msiInstallStateBadConfig = -6,
|
|
||||||
msiInstallStateIncomplete = -5,
|
|
||||||
msiInstallStateSourceAbsent = -4,
|
|
||||||
msiInstallStateInvalidArg = -2,
|
|
||||||
msiInstallStateUnknown = -1,
|
|
||||||
msiInstallStateBroken = 0,
|
|
||||||
msiInstallStateAdvertised = 1,
|
|
||||||
msiInstallStateRemoved = 1,
|
|
||||||
msiInstallStateAbsent = 2,
|
|
||||||
msiInstallStateLocal = 3,
|
|
||||||
msiInstallStateSource = 4,
|
|
||||||
msiInstallStateDefault = 5
|
|
||||||
} MsiInstallState;
|
|
||||||
|
|
||||||
[ uuid(000C109E-0000-0000-C000-000000000046) ]
|
[ uuid(000C109E-0000-0000-C000-000000000046) ]
|
||||||
dispinterface Session
|
dispinterface Session
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,9 +17,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DISPID_INSTALLER_OPENPACKAGE 2
|
#define DISPID_INSTALLER_OPENPACKAGE 2
|
||||||
|
#define DISPID_INSTALLER_PRODUCTSTATE 17
|
||||||
|
#define DISPID_INSTALLER_PRODUCTS 35
|
||||||
|
|
||||||
#define DISPID_RECORD_STRINGDATA 1
|
#define DISPID_RECORD_STRINGDATA 1
|
||||||
|
|
||||||
|
#define DISPID_STRINGLIST_ITEM 0
|
||||||
|
#define DISPID_STRINGLIST_COUNT 1
|
||||||
|
|
||||||
#define DISPID_VIEW_EXECUTE 1
|
#define DISPID_VIEW_EXECUTE 1
|
||||||
#define DISPID_VIEW_FETCH 2
|
#define DISPID_VIEW_FETCH 2
|
||||||
#define DISPID_VIEW_CLOSE 4
|
#define DISPID_VIEW_CLOSE 4
|
||||||
|
|
|
@ -325,10 +325,11 @@ static DISPID get_dispid( IDispatch *disp, const char *name )
|
||||||
|
|
||||||
static void test_dispid(void)
|
static void test_dispid(void)
|
||||||
{
|
{
|
||||||
ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
|
|
||||||
|
|
||||||
todo_wine {
|
todo_wine {
|
||||||
ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
|
||||||
|
}
|
||||||
|
ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
|
||||||
|
todo_wine {
|
||||||
ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
|
||||||
|
@ -343,7 +344,9 @@ static void test_dispid(void)
|
||||||
|
|
||||||
ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
|
||||||
|
}
|
||||||
ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
|
||||||
|
todo_wine {
|
||||||
ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
|
||||||
|
@ -361,7 +364,9 @@ static void test_dispid(void)
|
||||||
ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
|
||||||
|
}
|
||||||
ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
|
||||||
|
todo_wine {
|
||||||
ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
|
||||||
ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
|
ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
|
||||||
|
@ -1100,50 +1105,46 @@ static void test_Installer(void)
|
||||||
DeleteFileA(msifile);
|
DeleteFileA(msifile);
|
||||||
|
|
||||||
/* Installer::Products */
|
/* Installer::Products */
|
||||||
todo_wine {
|
hr = Installer_Products(&pStringList);
|
||||||
hr = Installer_Products(&pStringList);
|
ok(SUCCEEDED(hr), "Installer_Products failed, hresult 0x%08x\n", hr);
|
||||||
ok(SUCCEEDED(hr), "Installer_Products failed, hresult 0x%08x\n", hr);
|
if (SUCCEEDED(hr))
|
||||||
if (SUCCEEDED(hr))
|
{
|
||||||
|
int iCount = 0, idx;
|
||||||
|
|
||||||
|
/* StringList::Count */
|
||||||
|
hr = StringList_Count(pStringList, &iCount);
|
||||||
|
ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr);
|
||||||
|
|
||||||
|
for (idx=0; idx<iCount; idx++)
|
||||||
{
|
{
|
||||||
int iCount = 0, idx;
|
/* StringList::Item */
|
||||||
|
|
||||||
/* StringList::Count */
|
|
||||||
hr = StringList_Count(pStringList, &iCount);
|
|
||||||
ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr);
|
|
||||||
|
|
||||||
for (idx=0; idx<iCount; idx++)
|
|
||||||
{
|
|
||||||
/* StringList::Item */
|
|
||||||
memset(szPath, 0, sizeof(szPath));
|
|
||||||
hr = StringList_Item(pStringList, idx, szPath);
|
|
||||||
ok(SUCCEEDED(hr), "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
/* Installer::ProductState */
|
|
||||||
hr = Installer_ProductState(szPath, &iState);
|
|
||||||
ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
ok(iState == INSTALLSTATE_DEFAULT || iState == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d", iState, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* StringList::Item using an invalid index */
|
|
||||||
memset(szPath, 0, sizeof(szPath));
|
memset(szPath, 0, sizeof(szPath));
|
||||||
hr = StringList_Item(pStringList, iCount, szPath);
|
hr = StringList_Item(pStringList, idx, szPath);
|
||||||
ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
|
ok(SUCCEEDED(hr), "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
|
||||||
|
|
||||||
IDispatch_Release(pStringList);
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
/* Installer::ProductState */
|
||||||
|
hr = Installer_ProductState(szPath, &iState);
|
||||||
|
ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
ok(iState == INSTALLSTATE_DEFAULT || iState == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d", iState, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* StringList::Item using an invalid index */
|
||||||
|
memset(szPath, 0, sizeof(szPath));
|
||||||
|
hr = StringList_Item(pStringList, iCount, szPath);
|
||||||
|
ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
|
||||||
|
|
||||||
|
IDispatch_Release(pStringList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Installer::ProductState for our product code, which should not be installed */
|
/* Installer::ProductState for our product code, which should not be installed */
|
||||||
todo_wine {
|
hr = Installer_ProductState(szProductCode, &iState);
|
||||||
hr = Installer_ProductState(szProductCode, &iState);
|
ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
|
||||||
ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
|
if (SUCCEEDED(hr))
|
||||||
if (SUCCEEDED(hr))
|
ok(iState == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d", iState, INSTALLSTATE_UNKNOWN);
|
||||||
ok(iState == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d", iState, INSTALLSTATE_UNKNOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Installer::Version */
|
/* Installer::Version */
|
||||||
todo_wine {
|
todo_wine {
|
||||||
|
|
Loading…
Reference in New Issue