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