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