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