1 /*
2  * Copyright 2013 Ludger Sprenker
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdarg.h>
20 //#include <math.h>
21 
22 #define WIN32_NO_STATUS
23 #define _INC_WINDOWS
24 #define COM_NO_WINDOWS_H
25 
26 #define COBJMACROS
27 #define CONST_VTABLE
28 
29 #include <windef.h>
30 #include <winbase.h>
31 #include <ole2.h>
32 //#include "wincodec.h"
33 #include <wincodecsdk.h>
34 #include <wine/test.h>
35 
36 static const WCHAR wszTestProperty1[] = {'P','r','o','p','e','r','t','y','1',0};
37 static const WCHAR wszTestProperty2[] = {'P','r','o','p','e','r','t','y','2',0};
38 static const WCHAR wszTestInvalidProperty[] = {'I','n','v','a','l','i','d',0};
39 
40 static void test_propertybag_getpropertyinfo(IPropertyBag2 *property, ULONG expected_count)
41 {
42     HRESULT hr;
43     PROPBAG2 pb[2];
44     ULONG out_count;
45 
46     /* iProperty: Out of bounce */
47     hr = IPropertyBag2_GetPropertyInfo(property, expected_count, 1, pb, &out_count);
48     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
49        "GetPropertyInfo handled iProperty out of bounce wrong, hr=%x\n", hr);
50 
51     /* cProperty: Out of bounce */
52     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count+1, pb, &out_count);
53     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
54        "GetPropertyInfo handled cProperty out of bounce wrong, hr=%x\n", hr);
55 
56     /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
57     if (expected_count == 0)
58         return;
59 
60     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count, pb, &out_count);
61     ok(hr == S_OK, "GetPropertyInfo failed, hr=%x\n", hr);
62     if (FAILED(hr))
63         return;
64 
65     ok(expected_count == out_count,
66        "GetPropertyInfo returned unexpected property count, %i != %i)\n",
67        expected_count, out_count);
68 
69     if(expected_count != 2)
70         return;
71 
72     ok(pb[0].vt == VT_UI1, "Invalid variant type, pb[0].vt=%x\n", pb[0].vt);
73     ok(pb[0].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[0].dwType=%x\n", pb[0].dwType);
74     ok(lstrcmpW(pb[0].pstrName, wszTestProperty1) == 0, "Invalid property name, pb[0].pstrName=%s\n", wine_dbgstr_w(pb[0].pstrName));
75     CoTaskMemFree(pb[0].pstrName);
76 
77     ok(pb[1].vt == VT_R4, "Invalid variant type, pb[1].vt=%x\n", pb[1].vt);
78     ok(pb[1].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[1].dwType=%x\n", pb[1].dwType);
79     ok(lstrcmpW(pb[1].pstrName, wszTestProperty2) == 0, "Invalid property name, pb[1].pstrName=%s\n", wine_dbgstr_w(pb[1].pstrName));
80     CoTaskMemFree(pb[1].pstrName);
81 }
82 
83 static void test_propertybag_countproperties(IPropertyBag2 *property, ULONG expected_count)
84 {
85     ULONG count = (ULONG)-1;
86     HRESULT hr;
87 
88     hr = IPropertyBag2_CountProperties(property, NULL);
89     ok(hr == E_INVALIDARG, "CountProperties returned unexpected result, hr=%x\n", hr);
90 
91     hr = IPropertyBag2_CountProperties(property, &count);
92     ok(hr == S_OK, "CountProperties failed, hr=%x\n", hr);
93 
94     if (FAILED(hr))
95         return;
96 
97     ok(count == expected_count, "CountProperties returned invalid value, count=%i\n", count);
98 }
99 
100 static void test_propertybag_read(IPropertyBag2 *property)
101 {
102     HRESULT hr;
103     PROPBAG2 options[3] = {{0}};
104     VARIANT values[3];
105     HRESULT itm_hr[3] = {S_OK, S_OK, S_OK};
106 
107     /* 1. One unknown property */
108     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
109     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
110     ok(hr == E_FAIL,
111        "Read for an unknown property did not fail with expected code, hr=%x\n", hr);
112 
113     /* 2. One known property */
114     options[0].pstrName = (LPOLESTR)wszTestProperty1;
115     itm_hr[0] = E_FAIL;
116     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
117     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
118     if (SUCCEEDED(hr))
119     {
120         ok(itm_hr[0] == S_OK,
121            "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
122         ok(V_VT(&values[0]) == VT_UI1,
123            "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
124         ok(V_UNION(&values[0], bVal) == 12,
125            "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
126 
127         VariantClear(&values[0]);
128     }
129 
130     /* 3. Two known properties */
131     options[0].pstrName = (LPOLESTR)wszTestProperty1;
132     options[1].pstrName = (LPOLESTR)wszTestProperty2;
133     itm_hr[0] = E_FAIL;
134     itm_hr[1] = E_FAIL;
135     hr = IPropertyBag2_Read(property, 2, options, NULL, values, itm_hr);
136     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
137     if (SUCCEEDED(hr))
138     {
139         ok(itm_hr[0] == S_OK, "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
140         ok(V_VT(&values[0]) == VT_UI1, "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
141         ok(V_UNION(&values[0], bVal) == 12, "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
142 
143         ok(itm_hr[1] == S_OK, "Read failed, itm_hr[1]=%x\n", itm_hr[1]);
144         ok(V_VT(&values[1]) == VT_R4, "Read failed, V_VT(&values[1])=%x\n", V_VT(&values[1]));
145         ok(V_UNION(&values[1], fltVal) == (float)3.14, "Read failed, &values[1]=%f\n", V_UNION(&values[1], fltVal));
146 
147         VariantClear(&values[0]);
148         VariantClear(&values[1]);
149     }
150 
151 
152     /* 4. One unknown property between two valid */
153 
154     /* Exotic initializations so we can detect what is unchanged */
155     itm_hr[0] = -1; itm_hr[1] = -1; itm_hr[2] = -1;
156     V_VT(&values[0]) = VT_NULL;
157     V_VT(&values[1]) = VT_NULL;
158     V_VT(&values[2]) = VT_NULL;
159     V_UNION(&values[0], bVal) = 254;
160     V_UNION(&values[1], bVal) = 254;
161     V_UNION(&values[2], bVal) = 254;
162 
163     options[0].pstrName = (LPOLESTR)wszTestProperty1;
164     options[1].pstrName = (LPOLESTR)wszTestInvalidProperty;
165     options[2].pstrName = (LPOLESTR)wszTestProperty2;
166 
167     hr = IPropertyBag2_Read(property, 3, options, NULL, values, itm_hr);
168     ok(hr == E_FAIL, "Read failed, hr=%x\n", hr);
169     if (hr == E_FAIL)
170     {
171         ok(itm_hr[0] == S_OK, "Read error code has unexpected value, itm_hr[0]=%x\n", itm_hr[0]);
172         ok(itm_hr[1] == -1,   "Read error code has unexpected value, itm_hr[1]=%x\n", itm_hr[1]);
173         ok(itm_hr[2] == -1,   "Read error code has unexpected value, itm_hr[2]=%x\n", itm_hr[2]);
174 
175         ok(V_VT(&values[0]) == VT_UI1,  "Read variant has unexpected type, V_VT(&values[0])=%x\n", V_VT(&values[0]));
176         ok(V_VT(&values[1]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[1])=%x\n", V_VT(&values[1]));
177         ok(V_VT(&values[2]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[2])=%x\n", V_VT(&values[2]));
178 
179         ok(V_UNION(&values[0], bVal) == 12,  "Read variant has unexpected value, V_UNION(&values[0])=%i\n", V_UNION(&values[0], bVal));
180         ok(V_UNION(&values[1], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[1])=%i\n", V_UNION(&values[1], bVal));
181         ok(V_UNION(&values[2], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[2])=%i\n", V_UNION(&values[2], bVal));
182     }
183 }
184 
185 static void test_propertybag_write(IPropertyBag2 *property)
186 {
187     HRESULT hr;
188     PROPBAG2 options[2] = {{0}};
189     VARIANT values[2];
190 
191     VariantInit(&values[0]);
192     VariantInit(&values[1]);
193 
194     /* 1. One unknown property */
195     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
196     hr = IPropertyBag2_Write(property, 1, options, values);
197     ok(hr == E_FAIL, "Write for an unknown property did not fail with expected code, hr=%x\n", hr);
198 
199     /* 2. One property without correct type */
200     options[0].pstrName = (LPOLESTR)wszTestProperty1;
201     V_VT(&values[0]) = VT_UI1;
202     V_UNION(&values[0], bVal) = 1;
203     hr = IPropertyBag2_Write(property, 1, options, values);
204     ok(hr == S_OK, "Write for one property failed, hr=%x\n", hr);
205 
206     /* 3. One property with mismatching type */
207     options[0].pstrName = (LPOLESTR)wszTestProperty1;
208     V_VT(&values[0]) = VT_I1;
209     V_UNION(&values[0], bVal) = 2;
210     hr = IPropertyBag2_Write(property, 1, options, values);
211     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
212        "Write with mismatching type did not fail with expected code hr=%x\n", hr);
213 
214     /* 4. Reset one property to empty */
215     options[0].pstrName = (LPOLESTR)wszTestProperty1;
216     VariantClear(&values[0]);
217     hr = IPropertyBag2_Write(property, 1, options, values);
218     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
219        "Write to reset to empty value does not fail with expected code, hr=%x\n", hr);
220 
221     /* 5. Set two properties */
222     options[0].pstrName = (LPOLESTR)wszTestProperty1;
223     V_VT(&values[0]) = VT_UI1;
224     V_UNION(&values[0], bVal) = 12;
225     options[1].pstrName = (LPOLESTR)wszTestProperty2;
226     V_VT(&values[1]) = VT_R4;
227     V_UNION(&values[1], fltVal) = (float)3.14;
228     hr = IPropertyBag2_Write(property, 2, options, values);
229     ok(hr == S_OK, "Write for two properties failed, hr=%x\n", hr);
230 }
231 
232 static void test_empty_propertybag(void)
233 {
234     HRESULT hr;
235     IWICComponentFactory *factory;
236     IPropertyBag2 *property;
237 
238     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
239                           &IID_IWICComponentFactory, (void**)&factory);
240     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
241 
242     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, NULL, 0, &property);
243 
244     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
245     if (FAILED(hr)) return;
246 
247     test_propertybag_countproperties(property, 0);
248 
249     test_propertybag_getpropertyinfo(property, 0);
250 
251     IPropertyBag2_Release(property);
252 
253     IWICComponentFactory_Release(factory);
254 }
255 
256 static void test_filled_propertybag(void)
257 {
258     HRESULT hr;
259     IWICComponentFactory *factory;
260     IPropertyBag2 *property;
261     PROPBAG2 opts[2]= {
262         {PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszTestProperty1, {0}},
263         {PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszTestProperty2, {0}}
264     };
265 
266     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
267                           &IID_IWICComponentFactory, (void**)&factory);
268     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
269 
270     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, opts, 2, &property);
271 
272     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
273     if (FAILED(hr)) return;
274 
275     test_propertybag_countproperties(property, 2);
276 
277     test_propertybag_getpropertyinfo(property, 2);
278 
279     test_propertybag_write(property);
280 
281     test_propertybag_read(property);
282 
283     IPropertyBag2_Release(property);
284 
285     IWICComponentFactory_Release(factory);
286 }
287 
288 START_TEST(propertybag)
289 {
290     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
291 
292     test_empty_propertybag();
293 
294     test_filled_propertybag();
295 
296     CoUninitialize();
297 }
298