[FUSION]
[reactos.git] / reactos / dll / win32 / fusion / asmname.c
1 /*
2 * IAssemblyName implementation
3 *
4 * Copyright 2008 James Hawkins
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "fusionpriv.h"
22
23 #include <assert.h>
24 #include <winuser.h>
25
26 typedef struct {
27 IAssemblyName IAssemblyName_iface;
28
29 LPWSTR path;
30
31 LPWSTR displayname;
32 LPWSTR name;
33 LPWSTR culture;
34 LPWSTR procarch;
35
36 WORD version[4];
37 DWORD versize;
38
39 BYTE pubkey[8];
40 BOOL haspubkey;
41
42 LONG ref;
43 } IAssemblyNameImpl;
44
45 static const WCHAR separator[] = {',',' ',0};
46 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
47 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
48 static const WCHAR pubkey[] =
49 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
50 static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r',
51 'A','r','c','h','i','t','e','c','t','u','r','e',0};
52
53 #define CHARS_PER_PUBKEY 16
54
55 static inline IAssemblyNameImpl *impl_from_IAssemblyName(IAssemblyName *iface)
56 {
57 return CONTAINING_RECORD(iface, IAssemblyNameImpl, IAssemblyName_iface);
58 }
59
60 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
61 REFIID riid, LPVOID *ppobj)
62 {
63 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
64
65 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
66
67 *ppobj = NULL;
68
69 if (IsEqualIID(riid, &IID_IUnknown) ||
70 IsEqualIID(riid, &IID_IAssemblyName))
71 {
72 IAssemblyName_AddRef(iface);
73 *ppobj = This;
74 return S_OK;
75 }
76
77 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
78 return E_NOINTERFACE;
79 }
80
81 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
82 {
83 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
84 ULONG refCount = InterlockedIncrement(&This->ref);
85
86 TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
87
88 return refCount;
89 }
90
91 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
92 {
93 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
94 ULONG refCount = InterlockedDecrement(&This->ref);
95
96 TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
97
98 if (!refCount)
99 {
100 HeapFree(GetProcessHeap(), 0, This->path);
101 HeapFree(GetProcessHeap(), 0, This->displayname);
102 HeapFree(GetProcessHeap(), 0, This->name);
103 HeapFree(GetProcessHeap(), 0, This->culture);
104 HeapFree(GetProcessHeap(), 0, This->procarch);
105 HeapFree(GetProcessHeap(), 0, This);
106 }
107
108 return refCount;
109 }
110
111 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
112 DWORD PropertyId,
113 LPVOID pvProperty,
114 DWORD cbProperty)
115 {
116 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
117 return E_NOTIMPL;
118 }
119
120 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
121 DWORD PropertyId,
122 LPVOID pvProperty,
123 LPDWORD pcbProperty)
124 {
125 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
126
127 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
128
129 *((LPWSTR)pvProperty) = '\0';
130
131 switch (PropertyId)
132 {
133 case ASM_NAME_NULL_PUBLIC_KEY:
134 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
135 if (name->haspubkey)
136 return S_OK;
137 return S_FALSE;
138
139 case ASM_NAME_NULL_CUSTOM:
140 return S_OK;
141
142 case ASM_NAME_NAME:
143 *pcbProperty = 0;
144 if (name->name)
145 {
146 lstrcpyW(pvProperty, name->name);
147 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
148 }
149 break;
150
151 case ASM_NAME_MAJOR_VERSION:
152 *pcbProperty = 0;
153 *((WORD *)pvProperty) = name->version[0];
154 if (name->versize >= 1)
155 *pcbProperty = sizeof(WORD);
156 break;
157
158 case ASM_NAME_MINOR_VERSION:
159 *pcbProperty = 0;
160 *((WORD *)pvProperty) = name->version[1];
161 if (name->versize >= 2)
162 *pcbProperty = sizeof(WORD);
163 break;
164
165 case ASM_NAME_BUILD_NUMBER:
166 *pcbProperty = 0;
167 *((WORD *)pvProperty) = name->version[2];
168 if (name->versize >= 3)
169 *pcbProperty = sizeof(WORD);
170 break;
171
172 case ASM_NAME_REVISION_NUMBER:
173 *pcbProperty = 0;
174 *((WORD *)pvProperty) = name->version[3];
175 if (name->versize >= 4)
176 *pcbProperty = sizeof(WORD);
177 break;
178
179 case ASM_NAME_CULTURE:
180 *pcbProperty = 0;
181 if (name->culture)
182 {
183 lstrcpyW(pvProperty, name->culture);
184 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
185 }
186 break;
187
188 case ASM_NAME_PUBLIC_KEY_TOKEN:
189 *pcbProperty = 0;
190 if (name->haspubkey)
191 {
192 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
193 *pcbProperty = sizeof(DWORD) * 2;
194 }
195 break;
196
197 default:
198 *pcbProperty = 0;
199 break;
200 }
201
202 return S_OK;
203 }
204
205 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
206 {
207 FIXME("(%p) stub!\n", iface);
208 return E_NOTIMPL;
209 }
210
211 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
212 LPOLESTR szDisplayName,
213 LPDWORD pccDisplayName,
214 DWORD dwDisplayFlags)
215 {
216 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
217 WCHAR verstr[30];
218 DWORD size;
219 LPWSTR cultureval = 0;
220
221 static const WCHAR equals[] = {'=',0};
222
223 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
224 pccDisplayName, dwDisplayFlags);
225
226 if (dwDisplayFlags == 0)
227 {
228 if (!name->displayname || !*name->displayname)
229 return FUSION_E_INVALID_NAME;
230
231 size = min(*pccDisplayName, lstrlenW(name->displayname) + 1);
232
233 lstrcpynW(szDisplayName, name->displayname, size);
234 *pccDisplayName = size;
235
236 return S_OK;
237 }
238
239 if (!name->name || !*name->name)
240 return FUSION_E_INVALID_NAME;
241
242 /* Verify buffer size is sufficient */
243 size = lstrlenW(name->name) + 1;
244
245 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
246 {
247 static const WCHAR spec[] = {'%','d',0};
248 static const WCHAR period[] = {'.',0};
249 DWORD i;
250
251 wsprintfW(verstr, spec, name->version[0]);
252
253 for (i = 1; i < name->versize; i++)
254 {
255 WCHAR value[6];
256 wsprintfW(value, spec, name->version[i]);
257
258 lstrcatW(verstr, period);
259 lstrcatW(verstr, value);
260 }
261
262 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
263 }
264
265 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
266 {
267 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
268
269 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
270 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
271 }
272
273 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
274 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
275
276 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
277 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
278
279 if (size > *pccDisplayName)
280 return S_FALSE;
281
282 /* Construct the string */
283 lstrcpyW(szDisplayName, name->name);
284
285 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
286 {
287 lstrcatW(szDisplayName, separator);
288
289 lstrcatW(szDisplayName, version);
290 lstrcatW(szDisplayName, equals);
291 lstrcatW(szDisplayName, verstr);
292 }
293
294 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
295 {
296 lstrcatW(szDisplayName, separator);
297
298 lstrcatW(szDisplayName, culture);
299 lstrcatW(szDisplayName, equals);
300 lstrcatW(szDisplayName, cultureval);
301 }
302
303 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
304 {
305 WCHAR pkt[CHARS_PER_PUBKEY + 1];
306 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
307 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
308
309 lstrcatW(szDisplayName, separator);
310
311 lstrcatW(szDisplayName, pubkey);
312 lstrcatW(szDisplayName, equals);
313
314 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
315 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
316 name->pubkey[7]);
317
318 lstrcatW(szDisplayName, pkt);
319 }
320
321 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
322 {
323 lstrcatW(szDisplayName, separator);
324
325 lstrcatW(szDisplayName, procarch);
326 lstrcatW(szDisplayName, equals);
327 lstrcatW(szDisplayName, name->procarch);
328 }
329
330 *pccDisplayName = size;
331 return S_OK;
332 }
333
334 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
335 REFIID refIID,
336 IUnknown *pUnkReserved1,
337 IUnknown *pUnkReserved2,
338 LPCOLESTR szReserved,
339 LONGLONG llReserved,
340 LPVOID pvReserved,
341 DWORD cbReserved,
342 LPVOID *ppReserved)
343 {
344 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
345 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
346 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
347 pvReserved, cbReserved, ppReserved);
348
349 return E_NOTIMPL;
350 }
351
352 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
353 LPDWORD lpcwBuffer,
354 WCHAR *pwzName)
355 {
356 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
357
358 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
359
360 if (!name->name)
361 {
362 *pwzName = '\0';
363 *lpcwBuffer = 0;
364 return S_OK;
365 }
366
367 lstrcpyW(pwzName, name->name);
368 *lpcwBuffer = lstrlenW(pwzName) + 1;
369
370 return S_OK;
371 }
372
373 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
374 LPDWORD pdwVersionHi,
375 LPDWORD pdwVersionLow)
376 {
377 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
378
379 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
380
381 *pdwVersionHi = 0;
382 *pdwVersionLow = 0;
383
384 if (name->versize != 4)
385 return FUSION_E_INVALID_NAME;
386
387 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
388 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
389
390 return S_OK;
391 }
392
393 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
394 IAssemblyName *pName,
395 DWORD flags)
396 {
397 IAssemblyNameImpl *name1 = impl_from_IAssemblyName(iface);
398 IAssemblyNameImpl *name2 = impl_from_IAssemblyName(pName);
399
400 TRACE("(%p, %p, 0x%08x)\n", iface, pName, flags);
401
402 if (!pName) return S_FALSE;
403 if (flags & ~ASM_CMPF_IL_ALL) FIXME("unsupported flags\n");
404
405 if ((flags & ASM_CMPF_NAME) && strcmpW(name1->name, name2->name)) return S_FALSE;
406 if (name1->versize && name2->versize)
407 {
408 if ((flags & ASM_CMPF_MAJOR_VERSION) &&
409 name1->version[0] != name2->version[0]) return S_FALSE;
410 if ((flags & ASM_CMPF_MINOR_VERSION) &&
411 name1->version[1] != name2->version[1]) return S_FALSE;
412 if ((flags & ASM_CMPF_BUILD_NUMBER) &&
413 name1->version[2] != name2->version[2]) return S_FALSE;
414 if ((flags & ASM_CMPF_REVISION_NUMBER) &&
415 name1->version[3] != name2->version[3]) return S_FALSE;
416 }
417 if ((flags & ASM_CMPF_PUBLIC_KEY_TOKEN) &&
418 name1->haspubkey && name2->haspubkey &&
419 memcmp(name1->pubkey, name2->pubkey, sizeof(name1->pubkey))) return S_FALSE;
420
421 if ((flags & ASM_CMPF_CULTURE) &&
422 name1->culture && name2->culture &&
423 strcmpW(name1->culture, name2->culture)) return S_FALSE;
424
425 return S_OK;
426 }
427
428 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
429 IAssemblyName **pName)
430 {
431 FIXME("(%p, %p) stub!\n", iface, pName);
432 return E_NOTIMPL;
433 }
434
435 static const IAssemblyNameVtbl AssemblyNameVtbl = {
436 IAssemblyNameImpl_QueryInterface,
437 IAssemblyNameImpl_AddRef,
438 IAssemblyNameImpl_Release,
439 IAssemblyNameImpl_SetProperty,
440 IAssemblyNameImpl_GetProperty,
441 IAssemblyNameImpl_Finalize,
442 IAssemblyNameImpl_GetDisplayName,
443 IAssemblyNameImpl_Reserved,
444 IAssemblyNameImpl_GetName,
445 IAssemblyNameImpl_GetVersion,
446 IAssemblyNameImpl_IsEqual,
447 IAssemblyNameImpl_Clone
448 };
449
450 /* Internal methods */
451 static inline IAssemblyNameImpl *unsafe_impl_from_IAssemblyName(IAssemblyName *iface)
452 {
453 assert(iface->lpVtbl == &AssemblyNameVtbl);
454
455 return impl_from_IAssemblyName(iface);
456 }
457
458 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
459 {
460 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
461
462 name->path = strdupW(path);
463 if (!name->path)
464 return E_OUTOFMEMORY;
465
466 return S_OK;
467 }
468
469 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
470 {
471 ULONG buffer_size = *len;
472 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
473
474 if (!name->path)
475 return S_OK;
476
477 if (!buf)
478 buffer_size = 0;
479
480 *len = lstrlenW(name->path) + 1;
481
482 if (*len <= buffer_size)
483 lstrcpyW(buf, name->path);
484 else
485 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
486
487 return S_OK;
488 }
489
490 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
491 {
492 LPWSTR beg, end;
493 int i;
494
495 for (i = 0, beg = version; i < 4; i++)
496 {
497 if (!*beg)
498 return S_OK;
499
500 end = strchrW(beg, '.');
501
502 if (end) *end = '\0';
503 name->version[i] = atolW(beg);
504 name->versize++;
505
506 if (!end && i < 3)
507 return S_OK;
508
509 beg = end + 1;
510 }
511
512 return S_OK;
513 }
514
515 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
516 {
517 static const WCHAR empty[] = {0};
518
519 if (lstrlenW(culture) == 2)
520 name->culture = strdupW(culture);
521 else
522 name->culture = strdupW(empty);
523
524 return S_OK;
525 }
526
527 static BOOL is_hex(WCHAR c)
528 {
529 return ((c >= 'a' && c <= 'f') ||
530 (c >= 'A' && c <= 'F') ||
531 (c >= '0' && c <= '9'));
532 }
533
534 static BYTE hextobyte(WCHAR c)
535 {
536 if(c >= '0' && c <= '9')
537 return c - '0';
538 if(c >= 'A' && c <= 'F')
539 return c - 'A' + 10;
540 if(c >= 'a' && c <= 'f')
541 return c - 'a' + 10;
542 return 0;
543 }
544
545 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
546 {
547 int i;
548 BYTE val;
549 static const WCHAR nullstr[] = {'n','u','l','l',0};
550
551 if(lstrcmpiW(pubkey, nullstr) == 0)
552 return FUSION_E_PRIVATE_ASM_DISALLOWED;
553
554 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
555 return FUSION_E_INVALID_NAME;
556
557 for (i = 0; i < CHARS_PER_PUBKEY; i++)
558 if (!is_hex(pubkey[i]))
559 return FUSION_E_INVALID_NAME;
560
561 name->haspubkey = TRUE;
562
563 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
564 {
565 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
566 name->pubkey[i / 2] = val;
567 }
568
569 return S_OK;
570 }
571
572 static WCHAR *parse_value( const WCHAR *str, unsigned int len )
573 {
574 WCHAR *ret;
575 const WCHAR *p = str;
576 BOOL quoted = FALSE;
577 unsigned int i = 0;
578
579 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
580 if (*p == '\"')
581 {
582 quoted = TRUE;
583 p++;
584 }
585 while (*p && *p != '\"') ret[i++] = *p++;
586 if ((quoted && *p != '\"') || (!quoted && *p == '\"'))
587 {
588 HeapFree( GetProcessHeap(), 0, ret );
589 return NULL;
590 }
591 ret[i] = 0;
592 return ret;
593 }
594
595 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
596 {
597 LPWSTR str, save, ptr, ptr2, value;
598 HRESULT hr = S_OK;
599 BOOL done = FALSE;
600
601 if (!szAssemblyName)
602 return S_OK;
603
604 name->displayname = strdupW(szAssemblyName);
605 if (!name->displayname)
606 return E_OUTOFMEMORY;
607
608 str = strdupW(szAssemblyName);
609 save = str;
610 if (!str)
611 {
612 hr = E_OUTOFMEMORY;
613 goto done;
614 }
615
616 ptr = strchrW(str, ',');
617 if (ptr) *ptr = '\0';
618
619 /* no ',' but ' ' only */
620 if( !ptr && strchrW(str, ' ') )
621 {
622 hr = FUSION_E_INVALID_NAME;
623 goto done;
624 }
625
626 name->name = strdupW(str);
627 if (!name->name)
628 {
629 hr = E_OUTOFMEMORY;
630 goto done;
631 }
632
633 if (!ptr)
634 goto done;
635
636 str = ptr + 1;
637 while (!done)
638 {
639 ptr = strchrW(str, '=');
640 if (!ptr)
641 {
642 hr = FUSION_E_INVALID_NAME;
643 goto done;
644 }
645
646 *(ptr++) = '\0';
647 if (!*ptr)
648 {
649 hr = FUSION_E_INVALID_NAME;
650 goto done;
651 }
652
653 if (!(ptr2 = strchrW(ptr, ',')))
654 {
655 if (!(ptr2 = strchrW(ptr, '\0')))
656 {
657 hr = FUSION_E_INVALID_NAME;
658 goto done;
659 }
660
661 done = TRUE;
662 }
663
664 *ptr2 = '\0';
665 if (!(value = parse_value( ptr, ptr2 - ptr )))
666 {
667 hr = FUSION_E_INVALID_NAME;
668 goto done;
669 }
670 while (*str == ' ') str++;
671
672 if (!lstrcmpiW(str, version))
673 hr = parse_version( name, value );
674 else if (!lstrcmpiW(str, culture))
675 hr = parse_culture( name, value );
676 else if (!lstrcmpiW(str, pubkey))
677 hr = parse_pubkey( name, value );
678 else if (!lstrcmpiW(str, procarch))
679 {
680 name->procarch = value;
681 value = NULL;
682 }
683 HeapFree( GetProcessHeap(), 0, value );
684
685 if (FAILED(hr))
686 goto done;
687
688 str = ptr2 + 1;
689 }
690
691 done:
692 HeapFree(GetProcessHeap(), 0, save);
693 if (FAILED(hr))
694 {
695 HeapFree(GetProcessHeap(), 0, name->displayname);
696 HeapFree(GetProcessHeap(), 0, name->name);
697 HeapFree(GetProcessHeap(), 0, name->culture);
698 HeapFree(GetProcessHeap(), 0, name->procarch);
699 }
700 return hr;
701 }
702
703 /******************************************************************
704 * CreateAssemblyNameObject (FUSION.@)
705 */
706 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
707 LPCWSTR szAssemblyName, DWORD dwFlags,
708 LPVOID pvReserved)
709 {
710 IAssemblyNameImpl *name;
711 HRESULT hr;
712
713 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj,
714 debugstr_w(szAssemblyName), dwFlags, pvReserved);
715
716 if (!ppAssemblyNameObj)
717 return E_INVALIDARG;
718
719 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
720 (!szAssemblyName || !*szAssemblyName))
721 return E_INVALIDARG;
722
723 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
724 if (!name)
725 return E_OUTOFMEMORY;
726
727 name->IAssemblyName_iface.lpVtbl = &AssemblyNameVtbl;
728 name->ref = 1;
729
730 hr = parse_display_name(name, szAssemblyName);
731 if (FAILED(hr))
732 {
733 HeapFree(GetProcessHeap(), 0, name);
734 return hr;
735 }
736
737 *ppAssemblyNameObj = &name->IAssemblyName_iface;
738
739 return S_OK;
740 }