cc9995b1908082f86da58057d424914670bc4af7
[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->IAssemblyName_iface;
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 static const WCHAR equals[] = {'=',0};
217 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
218 WCHAR verstr[30], *cultureval = NULL;
219 DWORD size;
220
221 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
222 pccDisplayName, dwDisplayFlags);
223
224 if (dwDisplayFlags == 0)
225 {
226 if (!name->displayname || !*name->displayname)
227 return FUSION_E_INVALID_NAME;
228
229 size = strlenW(name->displayname) + 1;
230
231 if (*pccDisplayName < size)
232 {
233 *pccDisplayName = size;
234 return E_NOT_SUFFICIENT_BUFFER;
235 }
236
237 if (szDisplayName) strcpyW(szDisplayName, name->displayname);
238 *pccDisplayName = size;
239
240 return S_OK;
241 }
242
243 if (!name->name || !*name->name)
244 return FUSION_E_INVALID_NAME;
245
246 /* Verify buffer size is sufficient */
247 size = lstrlenW(name->name) + 1;
248
249 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
250 {
251 static const WCHAR spec[] = {'%','d',0};
252 static const WCHAR period[] = {'.',0};
253 DWORD i;
254
255 wsprintfW(verstr, spec, name->version[0]);
256
257 for (i = 1; i < name->versize; i++)
258 {
259 WCHAR value[6];
260 wsprintfW(value, spec, name->version[i]);
261
262 lstrcatW(verstr, period);
263 lstrcatW(verstr, value);
264 }
265
266 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
267 }
268
269 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
270 {
271 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
272
273 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
274 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
275 }
276
277 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
278 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
279
280 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
281 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
282
283 if (size > *pccDisplayName)
284 return S_FALSE;
285
286 /* Construct the string */
287 lstrcpyW(szDisplayName, name->name);
288
289 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
290 {
291 lstrcatW(szDisplayName, separator);
292
293 lstrcatW(szDisplayName, version);
294 lstrcatW(szDisplayName, equals);
295 lstrcatW(szDisplayName, verstr);
296 }
297
298 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
299 {
300 lstrcatW(szDisplayName, separator);
301
302 lstrcatW(szDisplayName, culture);
303 lstrcatW(szDisplayName, equals);
304 lstrcatW(szDisplayName, cultureval);
305 }
306
307 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
308 {
309 WCHAR pkt[CHARS_PER_PUBKEY + 1];
310 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
311 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
312
313 lstrcatW(szDisplayName, separator);
314
315 lstrcatW(szDisplayName, pubkey);
316 lstrcatW(szDisplayName, equals);
317
318 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
319 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
320 name->pubkey[7]);
321
322 lstrcatW(szDisplayName, pkt);
323 }
324
325 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
326 {
327 lstrcatW(szDisplayName, separator);
328
329 lstrcatW(szDisplayName, procarch);
330 lstrcatW(szDisplayName, equals);
331 lstrcatW(szDisplayName, name->procarch);
332 }
333
334 *pccDisplayName = size;
335 return S_OK;
336 }
337
338 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
339 REFIID refIID,
340 IUnknown *pUnkReserved1,
341 IUnknown *pUnkReserved2,
342 LPCOLESTR szReserved,
343 LONGLONG llReserved,
344 LPVOID pvReserved,
345 DWORD cbReserved,
346 LPVOID *ppReserved)
347 {
348 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
349 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
350 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
351 pvReserved, cbReserved, ppReserved);
352
353 return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
357 LPDWORD lpcwBuffer,
358 WCHAR *pwzName)
359 {
360 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
361 DWORD len;
362
363 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
364
365 if (name->name)
366 len = strlenW(name->name) + 1;
367 else
368 len = 0;
369
370 if (*lpcwBuffer < len)
371 {
372 *lpcwBuffer = len;
373 return E_NOT_SUFFICIENT_BUFFER;
374 }
375 if (!name->name) lpcwBuffer[0] = 0;
376 else strcpyW(pwzName, name->name);
377
378 *lpcwBuffer = len;
379 return S_OK;
380 }
381
382 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
383 LPDWORD pdwVersionHi,
384 LPDWORD pdwVersionLow)
385 {
386 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
387
388 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
389
390 *pdwVersionHi = 0;
391 *pdwVersionLow = 0;
392
393 if (name->versize != 4)
394 return FUSION_E_INVALID_NAME;
395
396 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
397 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
398
399 return S_OK;
400 }
401
402 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
403 IAssemblyName *pName,
404 DWORD flags)
405 {
406 IAssemblyNameImpl *name1 = impl_from_IAssemblyName(iface);
407 IAssemblyNameImpl *name2 = impl_from_IAssemblyName(pName);
408
409 TRACE("(%p, %p, 0x%08x)\n", iface, pName, flags);
410
411 if (!pName) return S_FALSE;
412 if (flags & ~ASM_CMPF_IL_ALL) FIXME("unsupported flags\n");
413
414 if ((flags & ASM_CMPF_NAME) && strcmpW(name1->name, name2->name)) return S_FALSE;
415 if (name1->versize && name2->versize)
416 {
417 if ((flags & ASM_CMPF_MAJOR_VERSION) &&
418 name1->version[0] != name2->version[0]) return S_FALSE;
419 if ((flags & ASM_CMPF_MINOR_VERSION) &&
420 name1->version[1] != name2->version[1]) return S_FALSE;
421 if ((flags & ASM_CMPF_BUILD_NUMBER) &&
422 name1->version[2] != name2->version[2]) return S_FALSE;
423 if ((flags & ASM_CMPF_REVISION_NUMBER) &&
424 name1->version[3] != name2->version[3]) return S_FALSE;
425 }
426 if ((flags & ASM_CMPF_PUBLIC_KEY_TOKEN) &&
427 name1->haspubkey && name2->haspubkey &&
428 memcmp(name1->pubkey, name2->pubkey, sizeof(name1->pubkey))) return S_FALSE;
429
430 if ((flags & ASM_CMPF_CULTURE) &&
431 name1->culture && name2->culture &&
432 strcmpW(name1->culture, name2->culture)) return S_FALSE;
433
434 return S_OK;
435 }
436
437 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
438 IAssemblyName **pName)
439 {
440 FIXME("(%p, %p) stub!\n", iface, pName);
441 return E_NOTIMPL;
442 }
443
444 static const IAssemblyNameVtbl AssemblyNameVtbl = {
445 IAssemblyNameImpl_QueryInterface,
446 IAssemblyNameImpl_AddRef,
447 IAssemblyNameImpl_Release,
448 IAssemblyNameImpl_SetProperty,
449 IAssemblyNameImpl_GetProperty,
450 IAssemblyNameImpl_Finalize,
451 IAssemblyNameImpl_GetDisplayName,
452 IAssemblyNameImpl_Reserved,
453 IAssemblyNameImpl_GetName,
454 IAssemblyNameImpl_GetVersion,
455 IAssemblyNameImpl_IsEqual,
456 IAssemblyNameImpl_Clone
457 };
458
459 /* Internal methods */
460 static inline IAssemblyNameImpl *unsafe_impl_from_IAssemblyName(IAssemblyName *iface)
461 {
462 assert(iface->lpVtbl == &AssemblyNameVtbl);
463
464 return impl_from_IAssemblyName(iface);
465 }
466
467 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
468 {
469 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
470
471 name->path = strdupW(path);
472 if (!name->path)
473 return E_OUTOFMEMORY;
474
475 return S_OK;
476 }
477
478 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
479 {
480 ULONG buffer_size = *len;
481 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
482
483 if (!name->path)
484 return S_OK;
485
486 if (!buf)
487 buffer_size = 0;
488
489 *len = lstrlenW(name->path) + 1;
490
491 if (*len <= buffer_size)
492 lstrcpyW(buf, name->path);
493 else
494 return E_NOT_SUFFICIENT_BUFFER;
495
496 return S_OK;
497 }
498
499 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
500 {
501 LPWSTR beg, end;
502 int i;
503
504 for (i = 0, beg = version; i < 4; i++)
505 {
506 if (!*beg)
507 return S_OK;
508
509 end = strchrW(beg, '.');
510
511 if (end) *end = '\0';
512 name->version[i] = atolW(beg);
513 name->versize++;
514
515 if (!end && i < 3)
516 return S_OK;
517
518 beg = end + 1;
519 }
520
521 return S_OK;
522 }
523
524 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
525 {
526 static const WCHAR empty[] = {0};
527
528 if (lstrlenW(culture) == 2)
529 name->culture = strdupW(culture);
530 else
531 name->culture = strdupW(empty);
532
533 return S_OK;
534 }
535
536 static BOOL is_hex(WCHAR c)
537 {
538 return ((c >= 'a' && c <= 'f') ||
539 (c >= 'A' && c <= 'F') ||
540 (c >= '0' && c <= '9'));
541 }
542
543 static BYTE hextobyte(WCHAR c)
544 {
545 if(c >= '0' && c <= '9')
546 return c - '0';
547 if(c >= 'A' && c <= 'F')
548 return c - 'A' + 10;
549 if(c >= 'a' && c <= 'f')
550 return c - 'a' + 10;
551 return 0;
552 }
553
554 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
555 {
556 int i;
557 BYTE val;
558 static const WCHAR nullstr[] = {'n','u','l','l',0};
559
560 if(lstrcmpiW(pubkey, nullstr) == 0)
561 return FUSION_E_PRIVATE_ASM_DISALLOWED;
562
563 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
564 return FUSION_E_INVALID_NAME;
565
566 for (i = 0; i < CHARS_PER_PUBKEY; i++)
567 if (!is_hex(pubkey[i]))
568 return FUSION_E_INVALID_NAME;
569
570 name->haspubkey = TRUE;
571
572 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
573 {
574 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
575 name->pubkey[i / 2] = val;
576 }
577
578 return S_OK;
579 }
580
581 static WCHAR *parse_value( const WCHAR *str, unsigned int len )
582 {
583 WCHAR *ret;
584 const WCHAR *p = str;
585 BOOL quoted = FALSE;
586 unsigned int i = 0;
587
588 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
589 if (*p == '\"')
590 {
591 quoted = TRUE;
592 p++;
593 }
594 while (*p && *p != '\"') ret[i++] = *p++;
595 if ((quoted && *p != '\"') || (!quoted && *p == '\"'))
596 {
597 HeapFree( GetProcessHeap(), 0, ret );
598 return NULL;
599 }
600 ret[i] = 0;
601 return ret;
602 }
603
604 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
605 {
606 LPWSTR str, save, ptr, ptr2, value;
607 HRESULT hr = S_OK;
608 BOOL done = FALSE;
609
610 if (!szAssemblyName)
611 return S_OK;
612
613 name->displayname = strdupW(szAssemblyName);
614 if (!name->displayname)
615 return E_OUTOFMEMORY;
616
617 str = strdupW(szAssemblyName);
618 save = str;
619 if (!str)
620 {
621 hr = E_OUTOFMEMORY;
622 goto done;
623 }
624
625 ptr = strchrW(str, ',');
626 if (ptr) *ptr = '\0';
627
628 /* no ',' but ' ' only */
629 if( !ptr && strchrW(str, ' ') )
630 {
631 hr = FUSION_E_INVALID_NAME;
632 goto done;
633 }
634
635 name->name = strdupW(str);
636 if (!name->name)
637 {
638 hr = E_OUTOFMEMORY;
639 goto done;
640 }
641
642 if (!ptr)
643 goto done;
644
645 str = ptr + 1;
646 while (!done)
647 {
648 ptr = strchrW(str, '=');
649 if (!ptr)
650 {
651 hr = FUSION_E_INVALID_NAME;
652 goto done;
653 }
654
655 *(ptr++) = '\0';
656 if (!*ptr)
657 {
658 hr = FUSION_E_INVALID_NAME;
659 goto done;
660 }
661
662 if (!(ptr2 = strchrW(ptr, ',')))
663 {
664 if (!(ptr2 = strchrW(ptr, '\0')))
665 {
666 hr = FUSION_E_INVALID_NAME;
667 goto done;
668 }
669
670 done = TRUE;
671 }
672
673 *ptr2 = '\0';
674 if (!(value = parse_value( ptr, ptr2 - ptr )))
675 {
676 hr = FUSION_E_INVALID_NAME;
677 goto done;
678 }
679 while (*str == ' ') str++;
680
681 if (!lstrcmpiW(str, version))
682 hr = parse_version( name, value );
683 else if (!lstrcmpiW(str, culture))
684 hr = parse_culture( name, value );
685 else if (!lstrcmpiW(str, pubkey))
686 hr = parse_pubkey( name, value );
687 else if (!lstrcmpiW(str, procarch))
688 {
689 name->procarch = value;
690 value = NULL;
691 }
692 HeapFree( GetProcessHeap(), 0, value );
693
694 if (FAILED(hr))
695 goto done;
696
697 str = ptr2 + 1;
698 }
699
700 done:
701 HeapFree(GetProcessHeap(), 0, save);
702 if (FAILED(hr))
703 {
704 HeapFree(GetProcessHeap(), 0, name->displayname);
705 HeapFree(GetProcessHeap(), 0, name->name);
706 HeapFree(GetProcessHeap(), 0, name->culture);
707 HeapFree(GetProcessHeap(), 0, name->procarch);
708 }
709 return hr;
710 }
711
712 /******************************************************************
713 * CreateAssemblyNameObject (FUSION.@)
714 */
715 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
716 LPCWSTR szAssemblyName, DWORD dwFlags,
717 LPVOID pvReserved)
718 {
719 IAssemblyNameImpl *name;
720 HRESULT hr;
721
722 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj,
723 debugstr_w(szAssemblyName), dwFlags, pvReserved);
724
725 if (!ppAssemblyNameObj)
726 return E_INVALIDARG;
727
728 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
729 (!szAssemblyName || !*szAssemblyName))
730 return E_INVALIDARG;
731
732 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
733 if (!name)
734 return E_OUTOFMEMORY;
735
736 name->IAssemblyName_iface.lpVtbl = &AssemblyNameVtbl;
737 name->ref = 1;
738
739 hr = parse_display_name(name, szAssemblyName);
740 if (FAILED(hr))
741 {
742 HeapFree(GetProcessHeap(), 0, name);
743 return hr;
744 }
745
746 *ppAssemblyNameObj = &name->IAssemblyName_iface;
747
748 return S_OK;
749 }