msvcrt: Use WINAPIV calling convention for variadic functions.
[wine.git] / dlls / fusion / asmname.c
blob1bfe9c13a362ba92833d42e8b02bb1a48e8ff754
1 /*
2 * IAssemblyName implementation
4 * Copyright 2008 James Hawkins
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.
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.
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
21 #include <stdarg.h>
22 #include <assert.h>
24 #define COBJMACROS
25 #define INITGUID
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "guiddef.h"
32 #include "fusion.h"
33 #include "corerror.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "fusionpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
41 typedef struct {
42 IAssemblyName IAssemblyName_iface;
44 LPWSTR path;
46 LPWSTR displayname;
47 LPWSTR name;
48 LPWSTR culture;
49 LPWSTR procarch;
51 WORD version[4];
52 DWORD versize;
54 BYTE pubkey[8];
55 BOOL haspubkey;
57 LONG ref;
58 } IAssemblyNameImpl;
60 static const WCHAR separator[] = {',',' ',0};
61 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
62 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
63 static const WCHAR pubkey[] =
64 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
65 static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r',
66 'A','r','c','h','i','t','e','c','t','u','r','e',0};
68 #define CHARS_PER_PUBKEY 16
70 static inline IAssemblyNameImpl *impl_from_IAssemblyName(IAssemblyName *iface)
72 return CONTAINING_RECORD(iface, IAssemblyNameImpl, IAssemblyName_iface);
75 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
76 REFIID riid, LPVOID *ppobj)
78 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
80 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
82 *ppobj = NULL;
84 if (IsEqualIID(riid, &IID_IUnknown) ||
85 IsEqualIID(riid, &IID_IAssemblyName))
87 IAssemblyName_AddRef(iface);
88 *ppobj = &This->IAssemblyName_iface;
89 return S_OK;
92 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
93 return E_NOINTERFACE;
96 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
98 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
99 ULONG refCount = InterlockedIncrement(&This->ref);
101 TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
103 return refCount;
106 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
108 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
109 ULONG refCount = InterlockedDecrement(&This->ref);
111 TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
113 if (!refCount)
115 HeapFree(GetProcessHeap(), 0, This->path);
116 HeapFree(GetProcessHeap(), 0, This->displayname);
117 HeapFree(GetProcessHeap(), 0, This->name);
118 HeapFree(GetProcessHeap(), 0, This->culture);
119 HeapFree(GetProcessHeap(), 0, This->procarch);
120 HeapFree(GetProcessHeap(), 0, This);
123 return refCount;
126 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
127 DWORD PropertyId,
128 LPVOID pvProperty,
129 DWORD cbProperty)
131 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
132 return E_NOTIMPL;
135 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
136 DWORD PropertyId,
137 LPVOID pvProperty,
138 LPDWORD pcbProperty)
140 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
142 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
144 *((LPWSTR)pvProperty) = '\0';
146 switch (PropertyId)
148 case ASM_NAME_NULL_PUBLIC_KEY:
149 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
150 if (name->haspubkey)
151 return S_OK;
152 return S_FALSE;
154 case ASM_NAME_NULL_CUSTOM:
155 return S_OK;
157 case ASM_NAME_NAME:
158 *pcbProperty = 0;
159 if (name->name)
161 lstrcpyW(pvProperty, name->name);
162 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
164 break;
166 case ASM_NAME_MAJOR_VERSION:
167 *pcbProperty = 0;
168 *((WORD *)pvProperty) = name->version[0];
169 if (name->versize >= 1)
170 *pcbProperty = sizeof(WORD);
171 break;
173 case ASM_NAME_MINOR_VERSION:
174 *pcbProperty = 0;
175 *((WORD *)pvProperty) = name->version[1];
176 if (name->versize >= 2)
177 *pcbProperty = sizeof(WORD);
178 break;
180 case ASM_NAME_BUILD_NUMBER:
181 *pcbProperty = 0;
182 *((WORD *)pvProperty) = name->version[2];
183 if (name->versize >= 3)
184 *pcbProperty = sizeof(WORD);
185 break;
187 case ASM_NAME_REVISION_NUMBER:
188 *pcbProperty = 0;
189 *((WORD *)pvProperty) = name->version[3];
190 if (name->versize >= 4)
191 *pcbProperty = sizeof(WORD);
192 break;
194 case ASM_NAME_CULTURE:
195 *pcbProperty = 0;
196 if (name->culture)
198 lstrcpyW(pvProperty, name->culture);
199 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
201 break;
203 case ASM_NAME_PUBLIC_KEY_TOKEN:
204 *pcbProperty = 0;
205 if (name->haspubkey)
207 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
208 *pcbProperty = sizeof(DWORD) * 2;
210 break;
212 default:
213 *pcbProperty = 0;
214 break;
217 return S_OK;
220 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
222 FIXME("(%p) stub!\n", iface);
223 return E_NOTIMPL;
226 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
227 LPOLESTR szDisplayName,
228 LPDWORD pccDisplayName,
229 DWORD dwDisplayFlags)
231 static const WCHAR equals[] = {'=',0};
232 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
233 WCHAR verstr[30], *cultureval = NULL;
234 DWORD size;
236 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
237 pccDisplayName, dwDisplayFlags);
239 if (dwDisplayFlags == 0)
241 if (!name->displayname || !*name->displayname)
242 return FUSION_E_INVALID_NAME;
244 size = strlenW(name->displayname) + 1;
246 if (*pccDisplayName < size)
248 *pccDisplayName = size;
249 return E_NOT_SUFFICIENT_BUFFER;
252 if (szDisplayName) strcpyW(szDisplayName, name->displayname);
253 *pccDisplayName = size;
255 return S_OK;
258 if (!name->name || !*name->name)
259 return FUSION_E_INVALID_NAME;
261 /* Verify buffer size is sufficient */
262 size = lstrlenW(name->name) + 1;
264 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
266 static const WCHAR spec[] = {'%','d',0};
267 static const WCHAR period[] = {'.',0};
268 DWORD i;
270 wsprintfW(verstr, spec, name->version[0]);
272 for (i = 1; i < name->versize; i++)
274 WCHAR value[6];
275 wsprintfW(value, spec, name->version[i]);
277 lstrcatW(verstr, period);
278 lstrcatW(verstr, value);
281 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
284 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
286 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
288 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
289 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
292 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
293 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
295 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
296 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
298 if (size > *pccDisplayName)
299 return S_FALSE;
301 /* Construct the string */
302 lstrcpyW(szDisplayName, name->name);
304 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
306 lstrcatW(szDisplayName, separator);
308 lstrcatW(szDisplayName, version);
309 lstrcatW(szDisplayName, equals);
310 lstrcatW(szDisplayName, verstr);
313 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
315 lstrcatW(szDisplayName, separator);
317 lstrcatW(szDisplayName, culture);
318 lstrcatW(szDisplayName, equals);
319 lstrcatW(szDisplayName, cultureval);
322 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
324 WCHAR pkt[CHARS_PER_PUBKEY + 1];
325 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
326 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
328 lstrcatW(szDisplayName, separator);
330 lstrcatW(szDisplayName, pubkey);
331 lstrcatW(szDisplayName, equals);
333 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
334 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
335 name->pubkey[7]);
337 lstrcatW(szDisplayName, pkt);
340 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
342 lstrcatW(szDisplayName, separator);
344 lstrcatW(szDisplayName, procarch);
345 lstrcatW(szDisplayName, equals);
346 lstrcatW(szDisplayName, name->procarch);
349 *pccDisplayName = size;
350 return S_OK;
353 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
354 REFIID refIID,
355 IUnknown *pUnkReserved1,
356 IUnknown *pUnkReserved2,
357 LPCOLESTR szReserved,
358 LONGLONG llReserved,
359 LPVOID pvReserved,
360 DWORD cbReserved,
361 LPVOID *ppReserved)
363 TRACE("(%p, %s, %p, %p, %s, %s, %p, %d, %p)\n", iface,
364 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
365 debugstr_w(szReserved), wine_dbgstr_longlong(llReserved),
366 pvReserved, cbReserved, ppReserved);
368 return E_NOTIMPL;
371 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
372 LPDWORD lpcwBuffer,
373 WCHAR *pwzName)
375 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
376 DWORD len;
378 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
380 if (name->name)
381 len = strlenW(name->name) + 1;
382 else
383 len = 0;
385 if (*lpcwBuffer < len)
387 *lpcwBuffer = len;
388 return E_NOT_SUFFICIENT_BUFFER;
390 if (!name->name) lpcwBuffer[0] = 0;
391 else strcpyW(pwzName, name->name);
393 *lpcwBuffer = len;
394 return S_OK;
397 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
398 LPDWORD pdwVersionHi,
399 LPDWORD pdwVersionLow)
401 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
403 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
405 *pdwVersionHi = 0;
406 *pdwVersionLow = 0;
408 if (name->versize != 4)
409 return FUSION_E_INVALID_NAME;
411 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
412 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
414 return S_OK;
417 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
418 IAssemblyName *pName,
419 DWORD flags)
421 IAssemblyNameImpl *name1 = impl_from_IAssemblyName(iface);
422 IAssemblyNameImpl *name2 = impl_from_IAssemblyName(pName);
424 TRACE("(%p, %p, 0x%08x)\n", iface, pName, flags);
426 if (!pName) return S_FALSE;
427 if (flags & ~ASM_CMPF_IL_ALL) FIXME("unsupported flags\n");
429 if ((flags & ASM_CMPF_NAME) && strcmpW(name1->name, name2->name)) return S_FALSE;
430 if (name1->versize && name2->versize)
432 if ((flags & ASM_CMPF_MAJOR_VERSION) &&
433 name1->version[0] != name2->version[0]) return S_FALSE;
434 if ((flags & ASM_CMPF_MINOR_VERSION) &&
435 name1->version[1] != name2->version[1]) return S_FALSE;
436 if ((flags & ASM_CMPF_BUILD_NUMBER) &&
437 name1->version[2] != name2->version[2]) return S_FALSE;
438 if ((flags & ASM_CMPF_REVISION_NUMBER) &&
439 name1->version[3] != name2->version[3]) return S_FALSE;
441 if ((flags & ASM_CMPF_PUBLIC_KEY_TOKEN) &&
442 name1->haspubkey && name2->haspubkey &&
443 memcmp(name1->pubkey, name2->pubkey, sizeof(name1->pubkey))) return S_FALSE;
445 if ((flags & ASM_CMPF_CULTURE) &&
446 name1->culture && name2->culture &&
447 strcmpW(name1->culture, name2->culture)) return S_FALSE;
449 return S_OK;
452 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
453 IAssemblyName **pName)
455 FIXME("(%p, %p) stub!\n", iface, pName);
456 return E_NOTIMPL;
459 static const IAssemblyNameVtbl AssemblyNameVtbl = {
460 IAssemblyNameImpl_QueryInterface,
461 IAssemblyNameImpl_AddRef,
462 IAssemblyNameImpl_Release,
463 IAssemblyNameImpl_SetProperty,
464 IAssemblyNameImpl_GetProperty,
465 IAssemblyNameImpl_Finalize,
466 IAssemblyNameImpl_GetDisplayName,
467 IAssemblyNameImpl_Reserved,
468 IAssemblyNameImpl_GetName,
469 IAssemblyNameImpl_GetVersion,
470 IAssemblyNameImpl_IsEqual,
471 IAssemblyNameImpl_Clone
474 /* Internal methods */
475 static inline IAssemblyNameImpl *unsafe_impl_from_IAssemblyName(IAssemblyName *iface)
477 assert(iface->lpVtbl == &AssemblyNameVtbl);
479 return impl_from_IAssemblyName(iface);
482 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
484 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
486 name->path = strdupW(path);
487 if (!name->path)
488 return E_OUTOFMEMORY;
490 return S_OK;
493 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
495 ULONG buffer_size = *len;
496 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
498 if (!name->path)
499 return S_OK;
501 if (!buf)
502 buffer_size = 0;
504 *len = lstrlenW(name->path) + 1;
506 if (*len <= buffer_size)
507 lstrcpyW(buf, name->path);
508 else
509 return E_NOT_SUFFICIENT_BUFFER;
511 return S_OK;
514 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
516 LPWSTR beg, end;
517 int i;
519 for (i = 0, beg = version; i < 4; i++)
521 if (!*beg)
522 return S_OK;
524 end = strchrW(beg, '.');
526 if (end) *end = '\0';
527 name->version[i] = atolW(beg);
528 name->versize++;
530 if (!end && i < 3)
531 return S_OK;
533 beg = end + 1;
536 return S_OK;
539 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
541 static const WCHAR empty[] = {0};
543 if (lstrlenW(culture) == 2)
544 name->culture = strdupW(culture);
545 else
546 name->culture = strdupW(empty);
548 return S_OK;
551 static BOOL is_hex(WCHAR c)
553 return ((c >= 'a' && c <= 'f') ||
554 (c >= 'A' && c <= 'F') ||
555 (c >= '0' && c <= '9'));
558 static BYTE hextobyte(WCHAR c)
560 if(c >= '0' && c <= '9')
561 return c - '0';
562 if(c >= 'A' && c <= 'F')
563 return c - 'A' + 10;
564 if(c >= 'a' && c <= 'f')
565 return c - 'a' + 10;
566 return 0;
569 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
571 int i;
572 BYTE val;
573 static const WCHAR nullstr[] = {'n','u','l','l',0};
575 if(lstrcmpiW(pubkey, nullstr) == 0)
576 return FUSION_E_PRIVATE_ASM_DISALLOWED;
578 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
579 return FUSION_E_INVALID_NAME;
581 for (i = 0; i < CHARS_PER_PUBKEY; i++)
582 if (!is_hex(pubkey[i]))
583 return FUSION_E_INVALID_NAME;
585 name->haspubkey = TRUE;
587 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
589 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
590 name->pubkey[i / 2] = val;
593 return S_OK;
596 static WCHAR *parse_value( const WCHAR *str, unsigned int len )
598 WCHAR *ret;
599 const WCHAR *p = str;
600 BOOL quoted = FALSE;
601 unsigned int i = 0;
603 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
604 if (*p == '\"')
606 quoted = TRUE;
607 p++;
609 while (*p && *p != '\"') ret[i++] = *p++;
610 if ((quoted && *p != '\"') || (!quoted && *p == '\"'))
612 HeapFree( GetProcessHeap(), 0, ret );
613 return NULL;
615 ret[i] = 0;
616 return ret;
619 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
621 LPWSTR str, save, ptr, ptr2, value;
622 HRESULT hr = S_OK;
623 BOOL done = FALSE;
625 if (!szAssemblyName)
626 return S_OK;
628 name->displayname = strdupW(szAssemblyName);
629 if (!name->displayname)
630 return E_OUTOFMEMORY;
632 str = strdupW(szAssemblyName);
633 save = str;
634 if (!str)
636 hr = E_OUTOFMEMORY;
637 goto done;
640 ptr = strchrW(str, ',');
641 if (ptr) *ptr = '\0';
643 /* no ',' but ' ' only */
644 if( !ptr && strchrW(str, ' ') )
646 hr = FUSION_E_INVALID_NAME;
647 goto done;
650 name->name = strdupW(str);
651 if (!name->name)
653 hr = E_OUTOFMEMORY;
654 goto done;
657 if (!ptr)
658 goto done;
660 str = ptr + 1;
661 while (!done)
663 ptr = strchrW(str, '=');
664 if (!ptr)
666 hr = FUSION_E_INVALID_NAME;
667 goto done;
670 *(ptr++) = '\0';
671 if (!*ptr)
673 hr = FUSION_E_INVALID_NAME;
674 goto done;
677 if (!(ptr2 = strchrW(ptr, ',')))
679 if (!(ptr2 = strchrW(ptr, '\0')))
681 hr = FUSION_E_INVALID_NAME;
682 goto done;
685 done = TRUE;
688 *ptr2 = '\0';
689 if (!(value = parse_value( ptr, ptr2 - ptr )))
691 hr = FUSION_E_INVALID_NAME;
692 goto done;
694 while (*str == ' ') str++;
696 if (!lstrcmpiW(str, version))
697 hr = parse_version( name, value );
698 else if (!lstrcmpiW(str, culture))
699 hr = parse_culture( name, value );
700 else if (!lstrcmpiW(str, pubkey))
701 hr = parse_pubkey( name, value );
702 else if (!lstrcmpiW(str, procarch))
704 name->procarch = value;
705 value = NULL;
707 HeapFree( GetProcessHeap(), 0, value );
709 if (FAILED(hr))
710 goto done;
712 str = ptr2 + 1;
715 done:
716 HeapFree(GetProcessHeap(), 0, save);
717 if (FAILED(hr))
719 HeapFree(GetProcessHeap(), 0, name->displayname);
720 HeapFree(GetProcessHeap(), 0, name->name);
721 HeapFree(GetProcessHeap(), 0, name->culture);
722 HeapFree(GetProcessHeap(), 0, name->procarch);
724 return hr;
727 /******************************************************************
728 * CreateAssemblyNameObject (FUSION.@)
730 HRESULT WINAPI CreateAssemblyNameObject(IAssemblyName **ppAssemblyNameObj,
731 LPCWSTR szAssemblyName, DWORD dwFlags,
732 LPVOID pvReserved)
734 IAssemblyNameImpl *name;
735 HRESULT hr;
737 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj,
738 debugstr_w(szAssemblyName), dwFlags, pvReserved);
740 if (!ppAssemblyNameObj)
741 return E_INVALIDARG;
743 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
744 (!szAssemblyName || !*szAssemblyName))
745 return E_INVALIDARG;
747 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
748 if (!name)
749 return E_OUTOFMEMORY;
751 name->IAssemblyName_iface.lpVtbl = &AssemblyNameVtbl;
752 name->ref = 1;
754 hr = parse_display_name(name, szAssemblyName);
755 if (FAILED(hr))
757 HeapFree(GetProcessHeap(), 0, name);
758 return hr;
761 *ppAssemblyNameObj = &name->IAssemblyName_iface;
763 return S_OK;