[MAPI32] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / mapi32 / util.c
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 < ARRAY_SIZE(fmt); 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 }