commdlg: File name and extension offsets are not guaranteed to be the same in W-...
[wine/gsoc_dplay.git] / dlls / wintrust / wintrust_main.c
blobcb6724fe68086357e96664c938dd7151591604a9
1 /*
2 * Copyright 2001 Rein Klazes
3 * Copyright 2007 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
22 #include <stdarg.h>
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "guiddef.h"
31 #include "wintrust.h"
32 #include "softpub.h"
33 #include "mscat.h"
34 #include "objbase.h"
35 #include "winuser.h"
36 #include "wintrust_priv.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
42 /***********************************************************************
43 * DllMain (WINTRUST.@)
45 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
47 switch(reason)
49 case DLL_PROCESS_ATTACH:
50 DisableThreadLibraryCalls( inst );
51 break;
53 return TRUE;
56 /***********************************************************************
57 * TrustIsCertificateSelfSigned (WINTRUST.@)
59 BOOL WINAPI TrustIsCertificateSelfSigned( PCCERT_CONTEXT cert )
61 BOOL ret;
63 TRACE("%p\n", cert);
64 ret = CertCompareCertificateName(cert->dwCertEncodingType,
65 &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
66 return ret;
69 static LONG WINTRUST_DefaultVerify(HWND hwnd, GUID *actionID,
70 WINTRUST_DATA *data)
72 DWORD err = ERROR_SUCCESS;
73 CRYPT_PROVIDER_DATA *provData;
74 BOOL ret;
76 TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
78 provData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_DATA));
79 if (!provData)
80 goto oom;
81 provData->cbStruct = sizeof(CRYPT_PROVIDER_DATA);
83 provData->padwTrustStepErrors =
84 WINTRUST_Alloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
85 if (!provData->padwTrustStepErrors)
86 goto oom;
87 provData->cdwTrustStepErrors = TRUSTERROR_MAX_STEPS;
89 provData->u.pPDSip = WINTRUST_Alloc(sizeof(PROVDATA_SIP));
90 if (!provData->u.pPDSip)
91 goto oom;
92 provData->u.pPDSip->cbStruct = sizeof(PROVDATA_SIP);
94 provData->psPfns = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_FUNCTIONS));
95 if (!provData->psPfns)
96 goto oom;
97 provData->psPfns->cbStruct = sizeof(CRYPT_PROVIDER_FUNCTIONS);
98 ret = WintrustLoadFunctionPointers(actionID, provData->psPfns);
99 if (!ret)
101 err = GetLastError();
102 goto error;
105 data->hWVTStateData = (HANDLE)provData;
106 provData->pWintrustData = data;
107 if (hwnd == INVALID_HANDLE_VALUE)
108 provData->hWndParent = GetDesktopWindow();
109 else
110 provData->hWndParent = hwnd;
111 provData->pgActionID = actionID;
112 WintrustGetRegPolicyFlags(&provData->dwRegPolicySettings);
114 err = provData->psPfns->pfnInitialize(provData);
115 if (err)
116 goto done;
117 err = provData->psPfns->pfnObjectTrust(provData);
118 if (err)
119 goto done;
120 err = provData->psPfns->pfnSignatureTrust(provData);
121 if (err)
122 goto done;
123 err = provData->psPfns->pfnCertificateTrust(provData);
124 if (err)
125 goto done;
126 err = provData->psPfns->pfnFinalPolicy(provData);
127 goto done;
129 oom:
130 err = ERROR_OUTOFMEMORY;
131 error:
132 if (provData)
134 WINTRUST_Free(provData->padwTrustStepErrors);
135 WINTRUST_Free(provData->u.pPDSip);
136 WINTRUST_Free(provData->psPfns);
137 WINTRUST_Free(provData);
139 done:
140 TRACE("returning %08x\n", err);
141 return err;
144 static LONG WINTRUST_DefaultClose(HWND hwnd, GUID *actionID,
145 WINTRUST_DATA *data)
147 DWORD err = ERROR_SUCCESS;
148 CRYPT_PROVIDER_DATA *provData = (CRYPT_PROVIDER_DATA *)data->hWVTStateData;
150 TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
152 if (provData)
154 err = provData->psPfns->pfnCleanupPolicy(provData);
155 WINTRUST_Free(provData->padwTrustStepErrors);
156 WINTRUST_Free(provData->u.pPDSip);
157 WINTRUST_Free(provData->psPfns);
158 WINTRUST_Free(provData);
159 data->hWVTStateData = NULL;
161 TRACE("returning %08x\n", err);
162 return err;
165 static LONG WINTRUST_DefaultVerifyAndClose(HWND hwnd, GUID *actionID,
166 WINTRUST_DATA *data)
168 LONG err;
170 TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
172 err = WINTRUST_DefaultVerify(hwnd, actionID, data);
173 WINTRUST_DefaultClose(hwnd, actionID, data);
174 TRACE("returning %08x\n", err);
175 return err;
178 static LONG WINTRUST_PublishedSoftware(HWND hwnd, GUID *actionID,
179 WINTRUST_DATA *data)
181 WINTRUST_DATA wintrust_data = { sizeof(wintrust_data), 0 };
182 /* Undocumented: the published software action is passed a path,
183 * and pSIPClientData points to a WIN_TRUST_SUBJECT_FILE.
185 LPCWSTR path = (LPCWSTR)data->u.pFile;
186 LPWIN_TRUST_SUBJECT_FILE subjectFile =
187 (LPWIN_TRUST_SUBJECT_FILE)data->pSIPClientData;
188 WINTRUST_FILE_INFO fileInfo = { sizeof(fileInfo), 0 };
190 TRACE("subjectFile->hFile: %p\n", subjectFile->hFile);
191 TRACE("subjectFile->lpPath: %s\n", debugstr_w(subjectFile->lpPath));
192 fileInfo.pcwszFilePath = path;
193 fileInfo.hFile = subjectFile->hFile;
194 wintrust_data.u.pFile = &fileInfo;
195 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
196 wintrust_data.dwUIChoice = WTD_UI_NONE;
198 return WINTRUST_DefaultVerifyAndClose(hwnd, actionID, &wintrust_data);
201 static void dump_file_info(WINTRUST_FILE_INFO *pFile)
203 TRACE("%p\n", pFile);
204 if (pFile)
206 TRACE("cbStruct: %d\n", pFile->cbStruct);
207 TRACE("pcwszFilePath: %s\n", debugstr_w(pFile->pcwszFilePath));
208 TRACE("hFile: %p\n", pFile->hFile);
209 TRACE("pgKnownSubject: %s\n", debugstr_guid(pFile->pgKnownSubject));
213 static void dump_catalog_info(WINTRUST_CATALOG_INFO *catalog)
215 TRACE("%p\n", catalog);
216 if (catalog)
218 TRACE("cbStruct: %d\n", catalog->cbStruct);
219 TRACE("dwCatalogVersion: %d\n", catalog->dwCatalogVersion);
220 TRACE("pcwszCatalogFilePath: %s\n",
221 debugstr_w(catalog->pcwszCatalogFilePath));
222 TRACE("pcwszMemberTag: %s\n", debugstr_w(catalog->pcwszMemberTag));
223 TRACE("pcwszMemberFilePath: %s\n",
224 debugstr_w(catalog->pcwszMemberFilePath));
225 TRACE("hMemberFile: %p\n", catalog->hMemberFile);
226 TRACE("pbCalculatedFileHash: %p\n", catalog->pbCalculatedFileHash);
227 TRACE("cbCalculatedFileHash: %d\n", catalog->cbCalculatedFileHash);
228 TRACE("pcCatalogContext: %p\n", catalog->pcCatalogContext);
232 static void dump_blob_info(WINTRUST_BLOB_INFO *blob)
234 TRACE("%p\n", blob);
235 if (blob)
237 TRACE("cbStruct: %d\n", blob->cbStruct);
238 TRACE("gSubject: %s\n", debugstr_guid(&blob->gSubject));
239 TRACE("pcwszDisplayName: %s\n", debugstr_w(blob->pcwszDisplayName));
240 TRACE("cbMemObject: %d\n", blob->cbMemObject);
241 TRACE("pbMemObject: %p\n", blob->pbMemObject);
242 TRACE("cbMemSignedMsg: %d\n", blob->cbMemSignedMsg);
243 TRACE("pbMemSignedMsg: %p\n", blob->pbMemSignedMsg);
247 static void dump_sgnr_info(WINTRUST_SGNR_INFO *sgnr)
249 TRACE("%p\n", sgnr);
250 if (sgnr)
252 TRACE("cbStruct: %d\n", sgnr->cbStruct);
253 TRACE("pcwszDisplayName: %s\n", debugstr_w(sgnr->pcwszDisplayName));
254 TRACE("psSignerInfo: %p\n", sgnr->psSignerInfo);
255 TRACE("chStores: %d\n", sgnr->chStores);
259 static void dump_cert_info(WINTRUST_CERT_INFO *cert)
261 TRACE("%p\n", cert);
262 if (cert)
264 TRACE("cbStruct: %d\n", cert->cbStruct);
265 TRACE("pcwszDisplayName: %s\n", debugstr_w(cert->pcwszDisplayName));
266 TRACE("psCertContext: %p\n", cert->psCertContext);
267 TRACE("chStores: %d\n", cert->chStores);
268 TRACE("dwFlags: %08x\n", cert->dwFlags);
269 TRACE("psftVerifyAsOf: %p\n", cert->psftVerifyAsOf);
273 static void dump_wintrust_data(WINTRUST_DATA *data)
275 TRACE("%p\n", data);
276 if (data)
278 TRACE("cbStruct: %d\n", data->cbStruct);
279 TRACE("pPolicyCallbackData: %p\n", data->pPolicyCallbackData);
280 TRACE("pSIPClientData: %p\n", data->pSIPClientData);
281 TRACE("dwUIChoice: %d\n", data->dwUIChoice);
282 TRACE("fdwRevocationChecks: %08x\n", data->fdwRevocationChecks);
283 TRACE("dwUnionChoice: %d\n", data->dwUnionChoice);
284 switch (data->dwUnionChoice)
286 case WTD_CHOICE_FILE:
287 dump_file_info(data->u.pFile);
288 break;
289 case WTD_CHOICE_CATALOG:
290 dump_catalog_info(data->u.pCatalog);
291 break;
292 case WTD_CHOICE_BLOB:
293 dump_blob_info(data->u.pBlob);
294 break;
295 case WTD_CHOICE_SIGNER:
296 dump_sgnr_info(data->u.pSgnr);
297 break;
298 case WTD_CHOICE_CERT:
299 dump_cert_info(data->u.pCert);
300 break;
302 TRACE("dwStateAction: %d\n", data->dwStateAction);
303 TRACE("hWVTStateData: %p\n", data->hWVTStateData);
304 TRACE("pwszURLReference: %s\n", debugstr_w(data->pwszURLReference));
305 TRACE("dwProvFlags: %08x\n", data->dwProvFlags);
306 TRACE("dwUIContext: %d\n", data->dwUIContext);
310 /***********************************************************************
311 * WinVerifyTrust (WINTRUST.@)
313 * Verifies an object by calling the specified trust provider.
315 * PARAMS
316 * hwnd [I] Handle to a caller window.
317 * ActionID [I] Pointer to a GUID that identifies the action to perform.
318 * ActionData [I] Information used by the trust provider to verify the object.
320 * RETURNS
321 * Success: Zero.
322 * Failure: A TRUST_E_* error code.
324 * NOTES
325 * Trust providers can be found at:
326 * HKLM\SOFTWARE\Microsoft\Cryptography\Providers\Trust\
328 LONG WINAPI WinVerifyTrust( HWND hwnd, GUID *ActionID, LPVOID ActionData )
330 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
331 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
332 static const GUID published_software = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
333 static const GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
334 static const GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
335 static const GUID generic_chain_verify = WINTRUST_ACTION_GENERIC_CHAIN_VERIFY;
336 LONG err = ERROR_SUCCESS;
337 WINTRUST_DATA *actionData = (WINTRUST_DATA *)ActionData;
339 TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(ActionID), ActionData);
340 dump_wintrust_data(ActionData);
342 /* Support for known old-style callers: */
343 if (IsEqualGUID(ActionID, &published_software))
344 err = WINTRUST_PublishedSoftware(hwnd, ActionID, ActionData);
345 else
347 /* Check known actions to warn of possible problems */
348 if (!IsEqualGUID(ActionID, &unknown) &&
349 !IsEqualGUID(ActionID, &generic_verify_v2) &&
350 !IsEqualGUID(ActionID, &generic_cert_verify) &&
351 !IsEqualGUID(ActionID, &generic_chain_verify))
352 WARN("unknown action %s, default behavior may not be right\n",
353 debugstr_guid(ActionID));
354 switch (actionData->dwStateAction)
356 case WTD_STATEACTION_IGNORE:
357 err = WINTRUST_DefaultVerifyAndClose(hwnd, ActionID, ActionData);
358 break;
359 case WTD_STATEACTION_VERIFY:
360 err = WINTRUST_DefaultVerify(hwnd, ActionID, ActionData);
361 break;
362 case WTD_STATEACTION_CLOSE:
363 err = WINTRUST_DefaultClose(hwnd, ActionID, ActionData);
364 break;
365 default:
366 FIXME("unimplemented for %d\n", actionData->dwStateAction);
370 TRACE("returning %08x\n", err);
371 return err;
374 /***********************************************************************
375 * WinVerifyTrustEx (WINTRUST.@)
377 HRESULT WINAPI WinVerifyTrustEx( HWND hwnd, GUID *ActionID,
378 WINTRUST_DATA* ActionData )
380 return WinVerifyTrust(hwnd, ActionID, ActionData);
383 /***********************************************************************
384 * WTHelperGetProvSignerFromChain (WINTRUST.@)
386 CRYPT_PROVIDER_SGNR * WINAPI WTHelperGetProvSignerFromChain(
387 CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSigner,
388 DWORD idxCounterSigner)
390 CRYPT_PROVIDER_SGNR *sgnr;
392 TRACE("(%p %d %d %d)\n", pProvData, idxSigner, fCounterSigner,
393 idxCounterSigner);
395 if (idxSigner >= pProvData->csSigners || !pProvData->pasSigners)
396 return NULL;
397 sgnr = &pProvData->pasSigners[idxSigner];
398 if (fCounterSigner)
400 if (idxCounterSigner >= sgnr->csCounterSigners ||
401 !sgnr->pasCounterSigners)
402 return NULL;
403 sgnr = &sgnr->pasCounterSigners[idxCounterSigner];
405 TRACE("returning %p\n", sgnr);
406 return sgnr;
409 /***********************************************************************
410 * WTHelperGetProvCertFromChain (WINTRUST.@)
412 CRYPT_PROVIDER_CERT * WINAPI WTHelperGetProvCertFromChain(
413 CRYPT_PROVIDER_SGNR *pSgnr, DWORD idxCert)
415 CRYPT_PROVIDER_CERT *cert;
417 TRACE("(%p %d)\n", pSgnr, idxCert);
419 if (idxCert >= pSgnr->csCertChain || !pSgnr->pasCertChain)
420 return NULL;
421 cert = &pSgnr->pasCertChain[idxCert];
422 TRACE("returning %p\n", cert);
423 return cert;
426 /***********************************************************************
427 * WTHelperProvDataFromStateData (WINTRUST.@)
429 CRYPT_PROVIDER_DATA * WINAPI WTHelperProvDataFromStateData(HANDLE hStateData)
431 TRACE("%p\n", hStateData);
432 return (CRYPT_PROVIDER_DATA *)hStateData;
435 static const WCHAR Software_Publishing[] = {
436 'S','o','f','t','w','a','r','e','\\',
437 'M','i','c','r','o','s','o','f','t','\\',
438 'W','i','n','d','o','w','s','\\',
439 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
440 'W','i','n','t','r','u','s','t','\\',
441 'T','r','u','s','t',' ','P','r','o','v','i','d','e','r','s','\\',
442 'S','o','f','t','w','a','r','e',' ',
443 'P','u','b','l','i','s','h','i','n','g',0 };
444 static const WCHAR State[] = { 'S','t','a','t','e',0 };
446 /***********************************************************************
447 * WintrustGetRegPolicyFlags (WINTRUST.@)
449 void WINAPI WintrustGetRegPolicyFlags( DWORD* pdwPolicyFlags )
451 HKEY key;
452 LONG r;
454 TRACE("%p\n", pdwPolicyFlags);
456 *pdwPolicyFlags = 0;
457 r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0, NULL, 0,
458 KEY_READ, NULL, &key, NULL);
459 if (!r)
461 DWORD size = sizeof(DWORD);
463 r = RegQueryValueExW(key, State, NULL, NULL, (LPBYTE)pdwPolicyFlags,
464 &size);
465 RegCloseKey(key);
466 if (r)
468 /* Failed to query, create and return default value */
469 *pdwPolicyFlags = WTPF_IGNOREREVOCATIONONTS |
470 WTPF_OFFLINEOKNBU_COM |
471 WTPF_OFFLINEOKNBU_IND |
472 WTPF_OFFLINEOK_COM |
473 WTPF_OFFLINEOK_IND;
474 WintrustSetRegPolicyFlags(*pdwPolicyFlags);
479 /***********************************************************************
480 * WintrustSetRegPolicyFlags (WINTRUST.@)
482 BOOL WINAPI WintrustSetRegPolicyFlags( DWORD dwPolicyFlags)
484 HKEY key;
485 LONG r;
487 TRACE("%x\n", dwPolicyFlags);
489 r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0,
490 NULL, 0, KEY_WRITE, NULL, &key, NULL);
491 if (!r)
493 r = RegSetValueExW(key, State, 0, REG_DWORD, (LPBYTE)&dwPolicyFlags,
494 sizeof(DWORD));
495 RegCloseKey(key);
497 if (r) SetLastError(r);
498 return r == ERROR_SUCCESS;
501 /* Utility functions */
502 void * WINAPI WINTRUST_Alloc(DWORD cb)
504 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
507 void * WINAPI WINTRUST_ReAlloc(void *ptr, DWORD cb)
509 return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, cb);
512 void WINAPI WINTRUST_Free(void *p)
514 HeapFree(GetProcessHeap(), 0, p);
517 BOOL WINAPI WINTRUST_AddStore(CRYPT_PROVIDER_DATA *data, HCERTSTORE store)
519 BOOL ret = FALSE;
521 if (data->chStores)
522 data->pahStores = WINTRUST_ReAlloc(data->pahStores,
523 (data->chStores + 1) * sizeof(HCERTSTORE));
524 else
526 data->pahStores = WINTRUST_Alloc(sizeof(HCERTSTORE));
527 data->chStores = 0;
529 if (data->pahStores)
531 data->pahStores[data->chStores++] = CertDuplicateStore(store);
532 ret = TRUE;
534 else
535 SetLastError(ERROR_OUTOFMEMORY);
536 return ret;
539 BOOL WINAPI WINTRUST_AddSgnr(CRYPT_PROVIDER_DATA *data,
540 BOOL fCounterSigner, DWORD idxSigner, CRYPT_PROVIDER_SGNR *sgnr)
542 BOOL ret = FALSE;
544 if (sgnr->cbStruct > sizeof(CRYPT_PROVIDER_SGNR))
546 SetLastError(ERROR_INVALID_PARAMETER);
547 return FALSE;
549 if (fCounterSigner)
551 FIXME("unimplemented for counter signers\n");
552 SetLastError(ERROR_INVALID_PARAMETER);
553 return FALSE;
555 if (data->csSigners)
556 data->pasSigners = WINTRUST_ReAlloc(data->pasSigners,
557 (data->csSigners + 1) * sizeof(CRYPT_PROVIDER_SGNR));
558 else
560 data->pasSigners = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR));
561 data->csSigners = 0;
563 if (data->pasSigners)
565 if (idxSigner < data->csSigners)
566 memmove(&data->pasSigners[idxSigner],
567 &data->pasSigners[idxSigner + 1],
568 (data->csSigners - idxSigner) * sizeof(CRYPT_PROVIDER_SGNR));
569 ret = TRUE;
570 if (sgnr->cbStruct == sizeof(CRYPT_PROVIDER_SGNR))
572 /* The PSDK says psSigner should be allocated using pfnAlloc, but
573 * it doesn't say anything about ownership. Since callers are
574 * internal, assume ownership is passed, and just store the
575 * pointer.
577 memcpy(&data->pasSigners[idxSigner], sgnr,
578 sizeof(CRYPT_PROVIDER_SGNR));
580 else
581 memset(&data->pasSigners[idxSigner], 0,
582 sizeof(CRYPT_PROVIDER_SGNR));
583 data->csSigners++;
585 else
586 SetLastError(ERROR_OUTOFMEMORY);
587 return ret;
590 BOOL WINAPI WINTRUST_AddCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
591 BOOL fCounterSigner, DWORD idxCounterSigner, PCCERT_CONTEXT pCert2Add)
593 BOOL ret = FALSE;
595 if (fCounterSigner)
597 FIXME("unimplemented for counter signers\n");
598 SetLastError(ERROR_INVALID_PARAMETER);
599 return FALSE;
601 if (data->pasSigners[idxSigner].csCertChain)
602 data->pasSigners[idxSigner].pasCertChain =
603 WINTRUST_ReAlloc(data->pasSigners[idxSigner].pasCertChain,
604 (data->pasSigners[idxSigner].csCertChain + 1) *
605 sizeof(CRYPT_PROVIDER_CERT));
606 else
608 data->pasSigners[idxSigner].pasCertChain =
609 WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_CERT));
610 data->pasSigners[idxSigner].csCertChain = 0;
612 if (data->pasSigners[idxSigner].pasCertChain)
614 CRYPT_PROVIDER_CERT *cert = &data->pasSigners[idxSigner].pasCertChain[
615 data->pasSigners[idxSigner].csCertChain];
617 cert->cbStruct = sizeof(CRYPT_PROVIDER_CERT);
618 cert->pCert = CertDuplicateCertificateContext(pCert2Add);
619 data->pasSigners[idxSigner].csCertChain++;
620 ret = TRUE;
622 else
623 SetLastError(ERROR_OUTOFMEMORY);
624 return ret;