1 /* 2 * MAPI Utility functions 3 * 4 * Copyright 2004 Jon Griffiths 5 * Copyright 2009 Owen Rudge for CodeWeavers 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 #include <stdio.h> 24 25 #define COBJMACROS 26 #define NONAMELESSUNION 27 #define NONAMELESSSTRUCT 28 #include "windef.h" 29 #include "winbase.h" 30 #include "winreg.h" 31 #include "winuser.h" 32 #include "winerror.h" 33 #include "winternl.h" 34 #include "objbase.h" 35 #include "shlwapi.h" 36 #include "wine/debug.h" 37 #include "wine/unicode.h" 38 #include "mapival.h" 39 #include "xcmc.h" 40 #include "msi.h" 41 #include "util.h" 42 43 WINE_DEFAULT_DEBUG_CHANNEL(mapi); 44 45 static const BYTE digitsToHex[] = { 46 0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15, 47 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 48 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13, 49 14,15 }; 50 51 MAPI_FUNCTIONS mapiFunctions; 52 53 /************************************************************************** 54 * ScInitMapiUtil (MAPI32.33) 55 * 56 * Initialise Mapi utility functions. 57 * 58 * PARAMS 59 * ulReserved [I] Reserved, pass 0. 60 * 61 * RETURNS 62 * Success: S_OK. Mapi utility functions may be called. 63 * Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0. 64 * 65 * NOTES 66 * Your application does not need to call this function unless it does not 67 * call MAPIInitialize()/MAPIUninitialize(). 68 */ 69 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved) 70 { 71 if (mapiFunctions.ScInitMapiUtil) 72 return mapiFunctions.ScInitMapiUtil(ulReserved); 73 74 FIXME("(0x%08x)stub!\n", ulReserved); 75 if (ulReserved) 76 return MAPI_E_INVALID_PARAMETER; 77 return S_OK; 78 } 79 80 /************************************************************************** 81 * DeinitMapiUtil (MAPI32.34) 82 * 83 * Uninitialise Mapi utility functions. 84 * 85 * PARAMS 86 * None. 87 * 88 * RETURNS 89 * Nothing. 90 * 91 * NOTES 92 * Your application does not need to call this function unless it does not 93 * call MAPIInitialize()/MAPIUninitialize(). 94 */ 95 VOID WINAPI DeinitMapiUtil(void) 96 { 97 if (mapiFunctions.DeinitMapiUtil) 98 mapiFunctions.DeinitMapiUtil(); 99 else 100 FIXME("()stub!\n"); 101 } 102 103 typedef LPVOID *LPMAPIALLOCBUFFER; 104 105 /************************************************************************** 106 * MAPIAllocateBuffer (MAPI32.12) 107 * MAPIAllocateBuffer@8 (MAPI32.13) 108 * 109 * Allocate a block of memory. 110 * 111 * PARAMS 112 * cbSize [I] Size of the block to allocate in bytes 113 * lppBuffer [O] Destination for pointer to allocated memory 114 * 115 * RETURNS 116 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of 117 * length cbSize bytes. 118 * Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL. 119 * MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails. 120 * 121 * NOTES 122 * Memory allocated with this function should be freed with MAPIFreeBuffer(). 123 * Further allocations of memory may be linked to the pointer returned using 124 * MAPIAllocateMore(). Linked allocations are freed when the initial pointer 125 * is feed. 126 */ 127 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer) 128 { 129 LPMAPIALLOCBUFFER lpBuff; 130 131 TRACE("(%d,%p)\n", cbSize, lppBuffer); 132 133 if (mapiFunctions.MAPIAllocateBuffer) 134 return mapiFunctions.MAPIAllocateBuffer(cbSize, lppBuffer); 135 136 if (!lppBuffer) 137 return E_INVALIDARG; 138 139 lpBuff = HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff)); 140 if (!lpBuff) 141 return MAPI_E_NOT_ENOUGH_MEMORY; 142 143 TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1); 144 *lpBuff++ = NULL; 145 *lppBuffer = lpBuff; 146 return S_OK; 147 } 148 149 /************************************************************************** 150 * MAPIAllocateMore (MAPI32.14) 151 * MAPIAllocateMore@12 (MAPI32.15) 152 * 153 * Allocate a block of memory linked to a previous allocation. 154 * 155 * PARAMS 156 * cbSize [I] Size of the block to allocate in bytes 157 * lpOrig [I] Initial allocation to link to, from MAPIAllocateBuffer() 158 * lppBuffer [O] Destination for pointer to allocated memory 159 * 160 * RETURNS 161 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of 162 * length cbSize bytes. 163 * Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid. 164 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails. 165 * 166 * NOTES 167 * Memory allocated with this function and stored in *lppBuffer is freed 168 * when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently. 169 */ 170 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer) 171 { 172 LPMAPIALLOCBUFFER lpBuff = lpOrig; 173 174 TRACE("(%d,%p,%p)\n", cbSize, lpOrig, lppBuffer); 175 176 if (mapiFunctions.MAPIAllocateMore) 177 return mapiFunctions.MAPIAllocateMore(cbSize, lpOrig, lppBuffer); 178 179 if (!lppBuffer || !lpBuff || !--lpBuff) 180 return E_INVALIDARG; 181 182 /* Find the last allocation in the chain */ 183 while (*lpBuff) 184 { 185 TRACE("linked:%p->%p\n", lpBuff, *lpBuff); 186 lpBuff = *lpBuff; 187 } 188 189 if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer))) 190 { 191 *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1; 192 TRACE("linking %p->%p\n", lpBuff, *lpBuff); 193 } 194 return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY; 195 } 196 197 /************************************************************************** 198 * MAPIFreeBuffer (MAPI32.16) 199 * MAPIFreeBuffer@4 (MAPI32.17) 200 * 201 * Free a block of memory and any linked allocations associated with it. 202 * 203 * PARAMS 204 * lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer() 205 * 206 * RETURNS 207 * S_OK. 208 */ 209 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer) 210 { 211 LPMAPIALLOCBUFFER lpBuff = lpBuffer; 212 213 TRACE("(%p)\n", lpBuffer); 214 215 if (mapiFunctions.MAPIFreeBuffer) 216 return mapiFunctions.MAPIFreeBuffer(lpBuffer); 217 218 if (lpBuff && --lpBuff) 219 { 220 while (lpBuff) 221 { 222 LPVOID lpFree = lpBuff; 223 224 lpBuff = *lpBuff; 225 226 TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree); 227 HeapFree(GetProcessHeap(), 0, lpFree); 228 } 229 } 230 return S_OK; 231 } 232 233 /************************************************************************** 234 * WrapProgress@20 (MAPI32.41) 235 */ 236 HRESULT WINAPI WrapProgress(PVOID unk1, PVOID unk2, PVOID unk3, PVOID unk4, PVOID unk5) 237 { 238 /* Native does not implement this function */ 239 return MAPI_E_NO_SUPPORT; 240 } 241 242 /************************************************************************* 243 * HrThisThreadAdviseSink@8 (MAPI32.42) 244 * 245 * Ensure that an advise sink is only notified in its originating thread. 246 * 247 * PARAMS 248 * lpSink [I] IMAPIAdviseSink interface to be protected 249 * lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface 250 * 251 * RETURNS 252 * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink. 253 * Failure: E_INVALIDARG, if any parameter is invalid. 254 */ 255 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink) 256 { 257 if (mapiFunctions.HrThisThreadAdviseSink) 258 return mapiFunctions.HrThisThreadAdviseSink(lpSink, lppNewSink); 259 260 FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink); 261 262 if (!lpSink || !lppNewSink) 263 return E_INVALIDARG; 264 265 /* Don't wrap the sink for now, just copy it */ 266 *lppNewSink = lpSink; 267 IMAPIAdviseSink_AddRef(lpSink); 268 return S_OK; 269 } 270 271 /************************************************************************* 272 * FBinFromHex (MAPI32.44) 273 * 274 * Create an array of binary data from a string. 275 * 276 * PARAMS 277 * lpszHex [I] String to convert to binary data 278 * lpOut [O] Destination for resulting binary data 279 * 280 * RETURNS 281 * Success: TRUE. lpOut contains the decoded binary data. 282 * Failure: FALSE, if lpszHex does not represent a binary string. 283 * 284 * NOTES 285 * - lpOut must be at least half the length of lpszHex in bytes. 286 * - Although the Mapi headers prototype this function as both 287 * Ascii and Unicode, there is only one (Ascii) implementation. This 288 * means that lpszHex is treated as an Ascii string (i.e. a single NUL 289 * character in the byte stream terminates the string). 290 */ 291 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut) 292 { 293 LPSTR lpStr = (LPSTR)lpszHex; 294 295 TRACE("(%p,%p)\n", lpszHex, lpOut); 296 297 while (*lpStr) 298 { 299 if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff || 300 lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff) 301 return FALSE; 302 303 *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']; 304 lpStr += 2; 305 } 306 return TRUE; 307 } 308 309 /************************************************************************* 310 * HexFromBin (MAPI32.45) 311 * 312 * Create a string from an array of binary data. 313 * 314 * PARAMS 315 * lpHex [I] Binary data to convert to string 316 * iCount [I] Length of lpHex in bytes 317 * lpszOut [O] Destination for resulting hex string 318 * 319 * RETURNS 320 * Nothing. 321 * 322 * NOTES 323 * - lpszOut must be at least 2 * iCount + 1 bytes characters long. 324 * - Although the Mapi headers prototype this function as both 325 * Ascii and Unicode, there is only one (Ascii) implementation. This 326 * means that the resulting string is not properly NUL terminated 327 * if the caller expects it to be a Unicode string. 328 */ 329 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut) 330 { 331 static const char hexDigits[] = { "0123456789ABCDEF" }; 332 LPSTR lpStr = (LPSTR)lpszOut; 333 334 TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut); 335 336 while (iCount-- > 0) 337 { 338 *lpStr++ = hexDigits[*lpHex >> 4]; 339 *lpStr++ = hexDigits[*lpHex & 0xf]; 340 lpHex++; 341 } 342 *lpStr = '\0'; 343 } 344 345 /************************************************************************* 346 * SwapPlong@8 (MAPI32.47) 347 * 348 * Swap the bytes in a ULONG array. 349 * 350 * PARAMS 351 * lpData [O] Array to swap bytes in 352 * ulLen [I] Number of ULONG element to swap the bytes of 353 * 354 * RETURNS 355 * Nothing. 356 */ 357 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen) 358 { 359 ULONG i; 360 361 for (i = 0; i < ulLen; i++) 362 lpData[i] = RtlUlongByteSwap(lpData[i]); 363 } 364 365 /************************************************************************* 366 * SwapPword@8 (MAPI32.48) 367 * 368 * Swap the bytes in a USHORT array. 369 * 370 * PARAMS 371 * lpData [O] Array to swap bytes in 372 * ulLen [I] Number of USHORT element to swap the bytes of 373 * 374 * RETURNS 375 * Nothing. 376 */ 377 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen) 378 { 379 ULONG i; 380 381 for (i = 0; i < ulLen; i++) 382 lpData[i] = RtlUshortByteSwap(lpData[i]); 383 } 384 385 /************************************************************************** 386 * MNLS_lstrlenW@4 (MAPI32.62) 387 * 388 * Calculate the length of a Unicode string. 389 * 390 * PARAMS 391 * lpszStr [I] String to calculate the length of 392 * 393 * RETURNS 394 * The length of lpszStr in Unicode characters. 395 */ 396 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr) 397 { 398 TRACE("(%s)\n", debugstr_w(lpszStr)); 399 return strlenW(lpszStr); 400 } 401 402 /************************************************************************* 403 * MNLS_lstrcmpW@8 (MAPI32.63) 404 * 405 * Compare two Unicode strings. 406 * 407 * PARAMS 408 * lpszLeft [I] First string to compare 409 * lpszRight [I] Second string to compare 410 * 411 * RETURNS 412 * An integer less than, equal to or greater than 0, indicating that 413 * lpszLeft is less than, the same, or greater than lpszRight. 414 */ 415 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight) 416 { 417 TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight)); 418 return strcmpW(lpszLeft, lpszRight); 419 } 420 421 /************************************************************************* 422 * MNLS_lstrcpyW@8 (MAPI32.64) 423 * 424 * Copy a Unicode string to another string. 425 * 426 * PARAMS 427 * lpszDest [O] Destination string 428 * lpszSrc [I] Source string 429 * 430 * RETURNS 431 * The length lpszDest in Unicode characters. 432 */ 433 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc) 434 { 435 ULONG len; 436 437 TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc)); 438 len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR); 439 memcpy(lpszDest, lpszSrc, len); 440 return len; 441 } 442 443 /************************************************************************* 444 * MNLS_CompareStringW@12 (MAPI32.65) 445 * 446 * Compare two Unicode strings. 447 * 448 * PARAMS 449 * dwCp [I] Code page for the comparison 450 * lpszLeft [I] First string to compare 451 * lpszRight [I] Second string to compare 452 * 453 * RETURNS 454 * CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that 455 * lpszLeft is less than, the same, or greater than lpszRight. 456 */ 457 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight) 458 { 459 INT ret; 460 461 TRACE("0x%08x,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight)); 462 ret = MNLS_lstrcmpW(lpszLeft, lpszRight); 463 return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL; 464 } 465 466 /************************************************************************** 467 * FEqualNames@8 (MAPI32.72) 468 * 469 * Compare two Mapi names. 470 * 471 * PARAMS 472 * lpName1 [I] First name to compare to lpName2 473 * lpName2 [I] Second name to compare to lpName1 474 * 475 * RETURNS 476 * TRUE, if the names are the same, 477 * FALSE, Otherwise. 478 */ 479 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2) 480 { 481 TRACE("(%p,%p)\n", lpName1, lpName2); 482 483 if (!lpName1 || !lpName2 || 484 !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) || 485 lpName1->ulKind != lpName2->ulKind) 486 return FALSE; 487 488 if (lpName1->ulKind == MNID_STRING) 489 return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName); 490 491 return lpName1->Kind.lID == lpName2->Kind.lID ? TRUE : FALSE; 492 } 493 494 /************************************************************************** 495 * IsBadBoundedStringPtr@8 (MAPI32.71) 496 * 497 * Determine if a string pointer is valid. 498 * 499 * PARAMS 500 * lpszStr [I] String to check 501 * ulLen [I] Maximum length of lpszStr 502 * 503 * RETURNS 504 * TRUE, if lpszStr is invalid or longer than ulLen, 505 * FALSE, otherwise. 506 */ 507 BOOL WINAPI IsBadBoundedStringPtr(LPCSTR lpszStr, ULONG ulLen) 508 { 509 if (!lpszStr || IsBadStringPtrA(lpszStr, -1) || strlen(lpszStr) >= ulLen) 510 return TRUE; 511 return FALSE; 512 } 513 514 /************************************************************************** 515 * FtAddFt@16 (MAPI32.121) 516 * 517 * Add two FILETIME's together. 518 * 519 * PARAMS 520 * ftLeft [I] FILETIME to add to ftRight 521 * ftRight [I] FILETIME to add to ftLeft 522 * 523 * RETURNS 524 * The sum of ftLeft and ftRight 525 */ 526 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight) 527 { 528 LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; 529 530 return *pl + *pr; 531 } 532 533 /************************************************************************** 534 * FtSubFt@16 (MAPI32.123) 535 * 536 * Subtract two FILETIME's together. 537 * 538 * PARAMS 539 * ftLeft [I] Initial FILETIME 540 * ftRight [I] FILETIME to subtract from ftLeft 541 * 542 * RETURNS 543 * The remainder after ftRight is subtracted from ftLeft. 544 */ 545 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight) 546 { 547 LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; 548 549 return *pr - *pl; 550 } 551 552 /************************************************************************** 553 * FtMulDw@12 (MAPI32.124) 554 * 555 * Multiply a FILETIME by a DWORD. 556 * 557 * PARAMS 558 * dwLeft [I] DWORD to multiply with ftRight 559 * ftRight [I] FILETIME to multiply with dwLeft 560 * 561 * RETURNS 562 * The product of dwLeft and ftRight 563 */ 564 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight) 565 { 566 LONGLONG *pr = (LONGLONG*)&ftRight; 567 568 return (LONGLONG)dwLeft * (*pr); 569 } 570 571 /************************************************************************** 572 * FtMulDwDw@8 (MAPI32.125) 573 * 574 * Multiply two DWORD, giving the result as a FILETIME. 575 * 576 * PARAMS 577 * dwLeft [I] DWORD to multiply with dwRight 578 * dwRight [I] DWORD to multiply with dwLeft 579 * 580 * RETURNS 581 * The product of ftMultiplier and ftMultiplicand as a FILETIME. 582 */ 583 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight) 584 { 585 return (LONGLONG)dwLeft * (LONGLONG)dwRight; 586 } 587 588 /************************************************************************** 589 * FtNegFt@8 (MAPI32.126) 590 * 591 * Negate a FILETIME. 592 * 593 * PARAMS 594 * ft [I] FILETIME to negate 595 * 596 * RETURNS 597 * The negation of ft. 598 */ 599 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft) 600 { 601 LONGLONG *p = (LONGLONG*)&ft; 602 603 return - *p; 604 } 605 606 /************************************************************************** 607 * UlAddRef@4 (MAPI32.128) 608 * 609 * Add a reference to an object. 610 * 611 * PARAMS 612 * lpUnk [I] Object to add a reference to. 613 * 614 * RETURNS 615 * The new reference count of the object, or 0 if lpUnk is NULL. 616 * 617 * NOTES 618 * See IUnknown_AddRef. 619 */ 620 ULONG WINAPI UlAddRef(void *lpUnk) 621 { 622 TRACE("(%p)\n", lpUnk); 623 624 if (!lpUnk) 625 return 0UL; 626 return IUnknown_AddRef((LPUNKNOWN)lpUnk); 627 } 628 629 /************************************************************************** 630 * UlRelease@4 (MAPI32.129) 631 * 632 * Remove a reference from an object. 633 * 634 * PARAMS 635 * lpUnk [I] Object to remove reference from. 636 * 637 * RETURNS 638 * The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is 639 * non-NULL and this function returns 0, the object pointed to by lpUnk has 640 * been released. 641 * 642 * NOTES 643 * See IUnknown_Release. 644 */ 645 ULONG WINAPI UlRelease(void *lpUnk) 646 { 647 TRACE("(%p)\n", lpUnk); 648 649 if (!lpUnk) 650 return 0UL; 651 return IUnknown_Release((LPUNKNOWN)lpUnk); 652 } 653 654 /************************************************************************** 655 * UFromSz@4 (MAPI32.133) 656 * 657 * Read an integer from a string 658 * 659 * PARAMS 660 * lpszStr [I] String to read the integer from. 661 * 662 * RETURNS 663 * Success: The integer read from lpszStr. 664 * Failure: 0, if the first character in lpszStr is not 0-9. 665 * 666 * NOTES 667 * This function does not accept whitespace and stops at the first non-digit 668 * character. 669 */ 670 UINT WINAPI UFromSz(LPCSTR lpszStr) 671 { 672 ULONG ulRet = 0; 673 674 TRACE("(%s)\n", debugstr_a(lpszStr)); 675 676 if (lpszStr) 677 { 678 while (*lpszStr >= '0' && *lpszStr <= '9') 679 { 680 ulRet = ulRet * 10 + (*lpszStr - '0'); 681 lpszStr++; 682 } 683 } 684 return ulRet; 685 } 686 687 /************************************************************************* 688 * OpenStreamOnFile@24 (MAPI32.147) 689 * 690 * Create a stream on a file. 691 * 692 * PARAMS 693 * lpAlloc [I] Memory allocation function 694 * lpFree [I] Memory free function 695 * ulFlags [I] Flags controlling the opening process 696 * lpszPath [I] Path of file to create stream on 697 * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME) 698 * lppStream [O] Destination for created stream 699 * 700 * RETURNS 701 * Success: S_OK. lppStream contains the new stream object 702 * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code 703 * describing the error. 704 */ 705 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree, 706 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix, 707 LPSTREAM *lppStream) 708 { 709 WCHAR szBuff[MAX_PATH]; 710 DWORD dwMode = STGM_READWRITE, dwAttributes = 0; 711 HRESULT hRet; 712 713 TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags, 714 debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream); 715 716 if (mapiFunctions.OpenStreamOnFile) 717 return mapiFunctions.OpenStreamOnFile(lpAlloc, lpFree, ulFlags, lpszPath, lpszPrefix, lppStream); 718 719 if (lppStream) 720 *lppStream = NULL; 721 722 if (ulFlags & SOF_UNIQUEFILENAME) 723 { 724 FIXME("Should generate a temporary name\n"); 725 return E_INVALIDARG; 726 } 727 728 if (!lpszPath || !lppStream) 729 return E_INVALIDARG; 730 731 /* FIXME: Should probably munge mode and attributes, and should handle 732 * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if 733 * we are being passed Unicode strings; MSDN doesn't say). 734 * This implementation is just enough for Outlook97 to start. 735 */ 736 MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH); 737 hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE, 738 NULL, lppStream); 739 return hRet; 740 } 741 742 /************************************************************************* 743 * UlFromSzHex@4 (MAPI32.155) 744 * 745 * Read an integer from a hexadecimal string. 746 * 747 * PARAMS 748 * lpSzHex [I] String containing the hexadecimal number to read 749 * 750 * RETURNS 751 * Success: The number represented by lpszHex. 752 * Failure: 0, if lpszHex does not contain a hex string. 753 * 754 * NOTES 755 * This function does not accept whitespace and stops at the first non-hex 756 * character. 757 */ 758 ULONG WINAPI UlFromSzHex(LPCWSTR lpszHex) 759 { 760 LPCSTR lpStr = (LPCSTR)lpszHex; 761 ULONG ulRet = 0; 762 763 TRACE("(%s)\n", debugstr_a(lpStr)); 764 765 while (*lpStr) 766 { 767 if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff || 768 lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff) 769 break; 770 771 ulRet = ulRet * 16 + ((digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']); 772 lpStr += 2; 773 } 774 return ulRet; 775 } 776 777 /************************************************************************ 778 * FBadEntryList@4 (MAPI32.190) 779 * 780 * Determine is an entry list is invalid. 781 * 782 * PARAMS 783 * lpEntryList [I] List to check 784 * 785 * RETURNS 786 * TRUE, if lpEntryList is invalid, 787 * FALSE, otherwise. 788 */ 789 BOOL WINAPI FBadEntryList(LPENTRYLIST lpEntryList) 790 { 791 ULONG i; 792 793 if (IsBadReadPtr(lpEntryList, sizeof(*lpEntryList)) || 794 IsBadReadPtr(lpEntryList->lpbin, 795 lpEntryList->cValues * sizeof(*lpEntryList->lpbin))) 796 return TRUE; 797 798 for (i = 0; i < lpEntryList->cValues; i++) 799 if(IsBadReadPtr(lpEntryList->lpbin[i].lpb, lpEntryList->lpbin[i].cb)) 800 return TRUE; 801 802 return FALSE; 803 } 804 805 /************************************************************************* 806 * CbOfEncoded@4 (MAPI32.207) 807 * 808 * Return the length of an encoded string. 809 * 810 * PARAMS 811 * lpSzEnc [I] Encoded string to get the length of. 812 * 813 * RETURNS 814 * The length of the encoded string in bytes. 815 */ 816 ULONG WINAPI CbOfEncoded(LPCSTR lpszEnc) 817 { 818 ULONG ulRet = 0; 819 820 TRACE("(%s)\n", debugstr_a(lpszEnc)); 821 822 if (lpszEnc) 823 ulRet = (((strlen(lpszEnc) | 3) >> 2) + 1) * 3; 824 return ulRet; 825 } 826 827 /************************************************************************* 828 * cmc_query_configuration (MAPI32.235) 829 * 830 * Retrieves the configuration information for the installed CMC 831 * 832 * PARAMS 833 * session [I] MAPI session handle 834 * item [I] Enumerated variable that identifies which 835 * configuration information is being requested 836 * reference [O] Buffer where configuration information is written 837 * config_extensions[I/O] Path of file to create stream on 838 * 839 * RETURNS 840 * A CMD define 841 */ 842 CMC_return_code WINAPI cmc_query_configuration( 843 CMC_session_id session, 844 CMC_enum item, 845 CMC_buffer reference, 846 CMC_extension *config_extensions) 847 { 848 FIXME("stub\n"); 849 return CMC_E_NOT_SUPPORTED; 850 } 851 852 /************************************************************************** 853 * FGetComponentPath (MAPI32.254) 854 * FGetComponentPath@20 (MAPI32.255) 855 * 856 * Return the installed component path, usually to the private mapi32.dll. 857 * 858 * PARAMS 859 * component [I] Component ID 860 * qualifier [I] Application LCID 861 * dll_path [O] returned component path 862 * dll_path_length [I] component path length 863 * install [I] install mode 864 * 865 * RETURNS 866 * Success: TRUE. 867 * Failure: FALSE. 868 * 869 * NOTES 870 * Previously documented in Q229700 "How to locate the correct path 871 * to the Mapisvc.inf file in Microsoft Outlook". 872 */ 873 BOOL WINAPI FGetComponentPath(LPCSTR component, LPCSTR qualifier, LPSTR dll_path, 874 DWORD dll_path_length, BOOL install) 875 { 876 BOOL ret = FALSE; 877 HMODULE hmsi; 878 879 TRACE("%s %s %p %u %d\n", component, qualifier, dll_path, dll_path_length, install); 880 881 if (mapiFunctions.FGetComponentPath) 882 return mapiFunctions.FGetComponentPath(component, qualifier, dll_path, dll_path_length, install); 883 884 dll_path[0] = 0; 885 886 hmsi = LoadLibraryA("msi.dll"); 887 if (hmsi) 888 { 889 UINT (WINAPI *pMsiProvideQualifiedComponentA)(LPCSTR, LPCSTR, DWORD, LPSTR, LPDWORD); 890 891 pMsiProvideQualifiedComponentA = (void *)GetProcAddress(hmsi, "MsiProvideQualifiedComponentA"); 892 if (pMsiProvideQualifiedComponentA) 893 { 894 static const char * const fmt[] = { "%d\\NT", "%d\\95", "%d" }; 895 char lcid_ver[20]; 896 UINT i; 897 898 for (i = 0; i < sizeof(fmt)/sizeof(fmt[0]); i++) 899 { 900 /* FIXME: what's the correct behaviour here? */ 901 if (!qualifier || qualifier == lcid_ver) 902 { 903 sprintf(lcid_ver, fmt[i], GetUserDefaultUILanguage()); 904 qualifier = lcid_ver; 905 } 906 907 if (pMsiProvideQualifiedComponentA(component, qualifier, 908 install ? INSTALLMODE_DEFAULT : INSTALLMODE_EXISTING, 909 dll_path, &dll_path_length) == ERROR_SUCCESS) 910 { 911 ret = TRUE; 912 break; 913 } 914 915 if (qualifier != lcid_ver) break; 916 } 917 } 918 FreeLibrary(hmsi); 919 } 920 return ret; 921 } 922 923 /************************************************************************** 924 * HrQueryAllRows (MAPI32.75) 925 */ 926 HRESULT WINAPI HrQueryAllRows(LPMAPITABLE lpTable, LPSPropTagArray lpPropTags, 927 LPSRestriction lpRestriction, LPSSortOrderSet lpSortOrderSet, 928 LONG crowsMax, LPSRowSet *lppRows) 929 { 930 if (mapiFunctions.HrQueryAllRows) 931 return mapiFunctions.HrQueryAllRows(lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows); 932 933 FIXME("(%p, %p, %p, %p, %d, %p): stub\n", lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows); 934 *lppRows = NULL; 935 return MAPI_E_CALL_FAILED; 936 } 937 938 static HMODULE mapi_provider; 939 static HMODULE mapi_ex_provider; 940 941 /************************************************************************** 942 * load_mapi_provider 943 * 944 * Attempts to load a MAPI provider from the specified registry key. 945 * 946 * Returns a handle to the loaded module in `mapi_provider' if successful. 947 */ 948 static void load_mapi_provider(HKEY hkeyMail, LPCWSTR valueName, HMODULE *mapi_provider) 949 { 950 static const WCHAR mapi32_dll[] = {'m','a','p','i','3','2','.','d','l','l',0 }; 951 952 DWORD dwType, dwLen = 0; 953 LPWSTR dllPath; 954 955 /* Check if we have a value set for DLLPath */ 956 if ((RegQueryValueExW(hkeyMail, valueName, NULL, &dwType, NULL, &dwLen) == ERROR_SUCCESS) && 957 ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) && (dwLen > 0)) 958 { 959 dllPath = HeapAlloc(GetProcessHeap(), 0, dwLen); 960 961 if (dllPath) 962 { 963 RegQueryValueExW(hkeyMail, valueName, NULL, NULL, (LPBYTE)dllPath, &dwLen); 964 965 /* Check that this value doesn't refer to mapi32.dll (eg, as Outlook does) */ 966 if (lstrcmpiW(dllPath, mapi32_dll) != 0) 967 { 968 if (dwType == REG_EXPAND_SZ) 969 { 970 DWORD dwExpandLen; 971 LPWSTR dllPathExpanded; 972 973 /* Expand the path if necessary */ 974 dwExpandLen = ExpandEnvironmentStringsW(dllPath, NULL, 0); 975 dllPathExpanded = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * dwExpandLen + 1); 976 977 if (dllPathExpanded) 978 { 979 ExpandEnvironmentStringsW(dllPath, dllPathExpanded, dwExpandLen + 1); 980 981 HeapFree(GetProcessHeap(), 0, dllPath); 982 dllPath = dllPathExpanded; 983 } 984 } 985 986 /* Load the DLL */ 987 TRACE("loading %s\n", debugstr_w(dllPath)); 988 *mapi_provider = LoadLibraryW(dllPath); 989 } 990 991 HeapFree(GetProcessHeap(), 0, dllPath); 992 } 993 } 994 } 995 996 /************************************************************************** 997 * load_mapi_providers 998 * 999 * Scans the registry for MAPI providers and attempts to load a Simple and 1000 * Extended MAPI library. 1001 * 1002 * Returns TRUE if at least one library loaded, FALSE otherwise. 1003 */ 1004 void load_mapi_providers(void) 1005 { 1006 static const WCHAR regkey_mail[] = { 1007 'S','o','f','t','w','a','r','e','\\','C','l','i','e','n','t','s','\\', 1008 'M','a','i','l',0 }; 1009 1010 static const WCHAR regkey_dllpath[] = {'D','L','L','P','a','t','h',0 }; 1011 static const WCHAR regkey_dllpath_ex[] = {'D','L','L','P','a','t','h','E','x',0 }; 1012 static const WCHAR regkey_backslash[] = { '\\', 0 }; 1013 1014 HKEY hkeyMail; 1015 DWORD dwType, dwLen = 0; 1016 LPWSTR appName = NULL, appKey = NULL; 1017 1018 TRACE("()\n"); 1019 1020 /* Open the Mail key */ 1021 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, regkey_mail, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS) 1022 return; 1023 1024 /* Check if we have a default value set, and the length of it */ 1025 if ((RegQueryValueExW(hkeyMail, NULL, NULL, &dwType, NULL, &dwLen) != ERROR_SUCCESS) || 1026 !((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) || (dwLen == 0)) 1027 goto cleanUp; 1028 1029 appName = HeapAlloc(GetProcessHeap(), 0, dwLen); 1030 1031 if (!appName) 1032 goto cleanUp; 1033 1034 /* Get the value, and get the path to the app key */ 1035 RegQueryValueExW(hkeyMail, NULL, NULL, NULL, (LPBYTE)appName, &dwLen); 1036 1037 TRACE("appName: %s\n", debugstr_w(appName)); 1038 1039 appKey = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(regkey_mail) + 1040 lstrlenW(regkey_backslash) + lstrlenW(appName) + 1)); 1041 1042 if (!appKey) 1043 goto cleanUp; 1044 1045 lstrcpyW(appKey, regkey_mail); 1046 lstrcatW(appKey, regkey_backslash); 1047 lstrcatW(appKey, appName); 1048 1049 RegCloseKey(hkeyMail); 1050 1051 TRACE("appKey: %s\n", debugstr_w(appKey)); 1052 1053 /* Open the app's key */ 1054 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, appKey, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS) 1055 goto cleanUp; 1056 1057 /* Try to load the providers */ 1058 load_mapi_provider(hkeyMail, regkey_dllpath, &mapi_provider); 1059 load_mapi_provider(hkeyMail, regkey_dllpath_ex, &mapi_ex_provider); 1060 1061 /* Now try to load our function pointers */ 1062 ZeroMemory(&mapiFunctions, sizeof(mapiFunctions)); 1063 1064 /* Simple MAPI functions */ 1065 if (mapi_provider) 1066 { 1067 mapiFunctions.MAPIAddress = (void*) GetProcAddress(mapi_provider, "MAPIAddress"); 1068 mapiFunctions.MAPIDeleteMail = (void*) GetProcAddress(mapi_provider, "MAPIDeleteMail"); 1069 mapiFunctions.MAPIDetails = (void*) GetProcAddress(mapi_provider, "MAPIDetails"); 1070 mapiFunctions.MAPIFindNext = (void*) GetProcAddress(mapi_provider, "MAPIFindNext"); 1071 mapiFunctions.MAPILogoff = (void*) GetProcAddress(mapi_provider, "MAPILogoff"); 1072 mapiFunctions.MAPILogon = (void*) GetProcAddress(mapi_provider, "MAPILogon"); 1073 mapiFunctions.MAPIReadMail = (void*) GetProcAddress(mapi_provider, "MAPIReadMail"); 1074 mapiFunctions.MAPIResolveName = (void*) GetProcAddress(mapi_provider, "MAPIResolveName"); 1075 mapiFunctions.MAPISaveMail = (void*) GetProcAddress(mapi_provider, "MAPISaveMail"); 1076 mapiFunctions.MAPISendDocuments = (void*) GetProcAddress(mapi_provider, "MAPISendDocuments"); 1077 mapiFunctions.MAPISendMail = (void*) GetProcAddress(mapi_provider, "MAPISendMail"); 1078 } 1079 1080 /* Extended MAPI functions */ 1081 if (mapi_ex_provider) 1082 { 1083 mapiFunctions.MAPIInitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIInitialize"); 1084 mapiFunctions.MAPILogonEx = (void*) GetProcAddress(mapi_ex_provider, "MAPILogonEx"); 1085 mapiFunctions.MAPIUninitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIUninitialize"); 1086 1087 mapiFunctions.DeinitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "DeinitMapiUtil@0"); 1088 mapiFunctions.DllCanUnloadNow = (void*) GetProcAddress(mapi_ex_provider, "DllCanUnloadNow"); 1089 mapiFunctions.DllGetClassObject = (void*) GetProcAddress(mapi_ex_provider, "DllGetClassObject"); 1090 mapiFunctions.FGetComponentPath = (void*) GetProcAddress(mapi_ex_provider, "FGetComponentPath"); 1091 mapiFunctions.HrThisThreadAdviseSink = (void*) GetProcAddress(mapi_ex_provider, "HrThisThreadAdviseSink@8"); 1092 mapiFunctions.HrQueryAllRows = (void*) GetProcAddress(mapi_ex_provider, "HrQueryAllRows@24"); 1093 mapiFunctions.MAPIAdminProfiles = (void*) GetProcAddress(mapi_ex_provider, "MAPIAdminProfiles"); 1094 mapiFunctions.MAPIAllocateBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateBuffer"); 1095 mapiFunctions.MAPIAllocateMore = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateMore"); 1096 mapiFunctions.MAPIFreeBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIFreeBuffer"); 1097 mapiFunctions.MAPIGetDefaultMalloc = (void*) GetProcAddress(mapi_ex_provider, "MAPIGetDefaultMalloc@0"); 1098 mapiFunctions.MAPIOpenLocalFormContainer = (void *) GetProcAddress(mapi_ex_provider, "MAPIOpenLocalFormContainer"); 1099 mapiFunctions.OpenStreamOnFile = (void*) GetProcAddress(mapi_ex_provider, "OpenStreamOnFile@24"); 1100 mapiFunctions.ScInitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "ScInitMapiUtil@4"); 1101 } 1102 1103 cleanUp: 1104 RegCloseKey(hkeyMail); 1105 HeapFree(GetProcessHeap(), 0, appKey); 1106 HeapFree(GetProcessHeap(), 0, appName); 1107 } 1108 1109 /************************************************************************** 1110 * unload_mapi_providers 1111 * 1112 * Unloads any loaded MAPI libraries. 1113 */ 1114 void unload_mapi_providers(void) 1115 { 1116 TRACE("()\n"); 1117 1118 FreeLibrary(mapi_provider); 1119 FreeLibrary(mapi_ex_provider); 1120 } 1121