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