mf/session: Forward more events to the application.
[wine/zf.git] / dlls / mapi32 / util.c
blob8f0036e68730aeba4930588bfea361941414459b
1 /*
2 * MAPI Utility functions
4 * Copyright 2004 Jon Griffiths
5 * Copyright 2009 Owen Rudge for CodeWeavers
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.
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.
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
22 #include <stdarg.h>
23 #include <stdio.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winternl.h"
33 #include "objbase.h"
34 #include "shlwapi.h"
35 #include "wine/debug.h"
36 #include "mapival.h"
37 #include "xcmc.h"
38 #include "msi.h"
39 #include "util.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
43 static const BYTE digitsToHex[] = {
44 0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15,
45 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
46 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,
47 14,15 };
49 MAPI_FUNCTIONS mapiFunctions;
51 /**************************************************************************
52 * ScInitMapiUtil (MAPI32.33)
54 * Initialise Mapi utility functions.
56 * PARAMS
57 * ulReserved [I] Reserved, pass 0.
59 * RETURNS
60 * Success: S_OK. Mapi utility functions may be called.
61 * Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
63 * NOTES
64 * Your application does not need to call this function unless it does not
65 * call MAPIInitialize()/MAPIUninitialize().
67 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved)
69 if (mapiFunctions.ScInitMapiUtil)
70 return mapiFunctions.ScInitMapiUtil(ulReserved);
72 FIXME("(0x%08x)stub!\n", ulReserved);
73 if (ulReserved)
74 return MAPI_E_INVALID_PARAMETER;
75 return S_OK;
78 /**************************************************************************
79 * DeinitMapiUtil (MAPI32.34)
81 * Uninitialise Mapi utility functions.
83 * PARAMS
84 * None.
86 * RETURNS
87 * Nothing.
89 * NOTES
90 * Your application does not need to call this function unless it does not
91 * call MAPIInitialize()/MAPIUninitialize().
93 VOID WINAPI DeinitMapiUtil(void)
95 if (mapiFunctions.DeinitMapiUtil)
96 mapiFunctions.DeinitMapiUtil();
97 else
98 FIXME("()stub!\n");
101 typedef LPVOID *LPMAPIALLOCBUFFER;
103 /**************************************************************************
104 * MAPIAllocateBuffer (MAPI32.12)
105 * MAPIAllocateBuffer@8 (MAPI32.13)
107 * Allocate a block of memory.
109 * PARAMS
110 * cbSize [I] Size of the block to allocate in bytes
111 * lppBuffer [O] Destination for pointer to allocated memory
113 * RETURNS
114 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
115 * length cbSize bytes.
116 * Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
117 * MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
119 * NOTES
120 * Memory allocated with this function should be freed with MAPIFreeBuffer().
121 * Further allocations of memory may be linked to the pointer returned using
122 * MAPIAllocateMore(). Linked allocations are freed when the initial pointer
123 * is feed.
125 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer)
127 LPMAPIALLOCBUFFER lpBuff;
129 TRACE("(%d,%p)\n", cbSize, lppBuffer);
131 if (mapiFunctions.MAPIAllocateBuffer)
132 return mapiFunctions.MAPIAllocateBuffer(cbSize, lppBuffer);
134 if (!lppBuffer)
135 return E_INVALIDARG;
137 lpBuff = HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff));
138 if (!lpBuff)
139 return MAPI_E_NOT_ENOUGH_MEMORY;
141 TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1);
142 *lpBuff++ = NULL;
143 *lppBuffer = lpBuff;
144 return S_OK;
147 /**************************************************************************
148 * MAPIAllocateMore (MAPI32.14)
149 * MAPIAllocateMore@12 (MAPI32.15)
151 * Allocate a block of memory linked to a previous allocation.
153 * PARAMS
154 * cbSize [I] Size of the block to allocate in bytes
155 * lpOrig [I] Initial allocation to link to, from MAPIAllocateBuffer()
156 * lppBuffer [O] Destination for pointer to allocated memory
158 * RETURNS
159 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
160 * length cbSize bytes.
161 * Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
162 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
164 * NOTES
165 * Memory allocated with this function and stored in *lppBuffer is freed
166 * when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
168 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer)
170 LPMAPIALLOCBUFFER lpBuff = lpOrig;
172 TRACE("(%d,%p,%p)\n", cbSize, lpOrig, lppBuffer);
174 if (mapiFunctions.MAPIAllocateMore)
175 return mapiFunctions.MAPIAllocateMore(cbSize, lpOrig, lppBuffer);
177 if (!lppBuffer || !lpBuff || !--lpBuff)
178 return E_INVALIDARG;
180 /* Find the last allocation in the chain */
181 while (*lpBuff)
183 TRACE("linked:%p->%p\n", lpBuff, *lpBuff);
184 lpBuff = *lpBuff;
187 if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer)))
189 *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1;
190 TRACE("linking %p->%p\n", lpBuff, *lpBuff);
192 return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY;
195 /**************************************************************************
196 * MAPIFreeBuffer (MAPI32.16)
197 * MAPIFreeBuffer@4 (MAPI32.17)
199 * Free a block of memory and any linked allocations associated with it.
201 * PARAMS
202 * lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
204 * RETURNS
205 * S_OK.
207 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer)
209 LPMAPIALLOCBUFFER lpBuff = lpBuffer;
211 TRACE("(%p)\n", lpBuffer);
213 if (mapiFunctions.MAPIFreeBuffer)
214 return mapiFunctions.MAPIFreeBuffer(lpBuffer);
216 if (lpBuff && --lpBuff)
218 while (lpBuff)
220 LPVOID lpFree = lpBuff;
222 lpBuff = *lpBuff;
224 TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree);
225 HeapFree(GetProcessHeap(), 0, lpFree);
228 return S_OK;
231 /**************************************************************************
232 * WrapProgress@20 (MAPI32.41)
234 HRESULT WINAPI WrapProgress(PVOID unk1, PVOID unk2, PVOID unk3, PVOID unk4, PVOID unk5)
236 /* Native does not implement this function */
237 return MAPI_E_NO_SUPPORT;
240 /*************************************************************************
241 * HrDispatchNotifications@4 (MAPI32.239)
243 HRESULT WINAPI HrDispatchNotifications(ULONG flags)
245 FIXME("(%08x)\n", flags);
246 return S_OK;
249 /*************************************************************************
250 * HrThisThreadAdviseSink@8 (MAPI32.42)
252 * Ensure that an advise sink is only notified in its originating thread.
254 * PARAMS
255 * lpSink [I] IMAPIAdviseSink interface to be protected
256 * lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
258 * RETURNS
259 * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
260 * Failure: E_INVALIDARG, if any parameter is invalid.
262 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink)
264 if (mapiFunctions.HrThisThreadAdviseSink)
265 return mapiFunctions.HrThisThreadAdviseSink(lpSink, lppNewSink);
267 FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink);
269 if (!lpSink || !lppNewSink)
270 return E_INVALIDARG;
272 /* Don't wrap the sink for now, just copy it */
273 *lppNewSink = lpSink;
274 IMAPIAdviseSink_AddRef(lpSink);
275 return S_OK;
278 /*************************************************************************
279 * FBinFromHex (MAPI32.44)
281 * Create an array of binary data from a string.
283 * PARAMS
284 * lpszHex [I] String to convert to binary data
285 * lpOut [O] Destination for resulting binary data
287 * RETURNS
288 * Success: TRUE. lpOut contains the decoded binary data.
289 * Failure: FALSE, if lpszHex does not represent a binary string.
291 * NOTES
292 * - lpOut must be at least half the length of lpszHex in bytes.
293 * - Although the Mapi headers prototype this function as both
294 * Ascii and Unicode, there is only one (Ascii) implementation. This
295 * means that lpszHex is treated as an Ascii string (i.e. a single NUL
296 * character in the byte stream terminates the string).
298 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut)
300 LPSTR lpStr = (LPSTR)lpszHex;
302 TRACE("(%p,%p)\n", lpszHex, lpOut);
304 while (*lpStr)
306 if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
307 lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
308 return FALSE;
310 *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0'];
311 lpStr += 2;
313 return TRUE;
316 /*************************************************************************
317 * HexFromBin (MAPI32.45)
319 * Create a string from an array of binary data.
321 * PARAMS
322 * lpHex [I] Binary data to convert to string
323 * iCount [I] Length of lpHex in bytes
324 * lpszOut [O] Destination for resulting hex string
326 * RETURNS
327 * Nothing.
329 * NOTES
330 * - lpszOut must be at least 2 * iCount + 1 bytes characters long.
331 * - Although the Mapi headers prototype this function as both
332 * Ascii and Unicode, there is only one (Ascii) implementation. This
333 * means that the resulting string is not properly NUL terminated
334 * if the caller expects it to be a Unicode string.
336 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut)
338 static const char hexDigits[] = { "0123456789ABCDEF" };
339 LPSTR lpStr = (LPSTR)lpszOut;
341 TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut);
343 while (iCount-- > 0)
345 *lpStr++ = hexDigits[*lpHex >> 4];
346 *lpStr++ = hexDigits[*lpHex & 0xf];
347 lpHex++;
349 *lpStr = '\0';
352 /*************************************************************************
353 * SwapPlong@8 (MAPI32.47)
355 * Swap the bytes in a ULONG array.
357 * PARAMS
358 * lpData [O] Array to swap bytes in
359 * ulLen [I] Number of ULONG element to swap the bytes of
361 * RETURNS
362 * Nothing.
364 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen)
366 ULONG i;
368 for (i = 0; i < ulLen; i++)
369 lpData[i] = RtlUlongByteSwap(lpData[i]);
372 /*************************************************************************
373 * SwapPword@8 (MAPI32.48)
375 * Swap the bytes in a USHORT array.
377 * PARAMS
378 * lpData [O] Array to swap bytes in
379 * ulLen [I] Number of USHORT element to swap the bytes of
381 * RETURNS
382 * Nothing.
384 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen)
386 ULONG i;
388 for (i = 0; i < ulLen; i++)
389 lpData[i] = RtlUshortByteSwap(lpData[i]);
392 /**************************************************************************
393 * MNLS_lstrlenW@4 (MAPI32.62)
395 * Calculate the length of a Unicode string.
397 * PARAMS
398 * lpszStr [I] String to calculate the length of
400 * RETURNS
401 * The length of lpszStr in Unicode characters.
403 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr)
405 TRACE("(%s)\n", debugstr_w(lpszStr));
406 return lstrlenW(lpszStr);
409 /*************************************************************************
410 * MNLS_lstrcmpW@8 (MAPI32.63)
412 * Compare two Unicode strings.
414 * PARAMS
415 * lpszLeft [I] First string to compare
416 * lpszRight [I] Second string to compare
418 * RETURNS
419 * An integer less than, equal to or greater than 0, indicating that
420 * lpszLeft is less than, the same, or greater than lpszRight.
422 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight)
424 TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight));
425 return lstrcmpW(lpszLeft, lpszRight);
428 /*************************************************************************
429 * MNLS_lstrcpyW@8 (MAPI32.64)
431 * Copy a Unicode string to another string.
433 * PARAMS
434 * lpszDest [O] Destination string
435 * lpszSrc [I] Source string
437 * RETURNS
438 * The length lpszDest in Unicode characters.
440 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc)
442 ULONG len;
444 TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc));
445 len = (lstrlenW(lpszSrc) + 1) * sizeof(WCHAR);
446 memcpy(lpszDest, lpszSrc, len);
447 return len;
450 /*************************************************************************
451 * MNLS_CompareStringW@12 (MAPI32.65)
453 * Compare two Unicode strings.
455 * PARAMS
456 * dwCp [I] Code page for the comparison
457 * lpszLeft [I] First string to compare
458 * lpszRight [I] Second string to compare
460 * RETURNS
461 * CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
462 * lpszLeft is less than, the same, or greater than lpszRight.
464 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight)
466 INT ret;
468 TRACE("0x%08x,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight));
469 ret = MNLS_lstrcmpW(lpszLeft, lpszRight);
470 return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL;
473 /**************************************************************************
474 * FEqualNames@8 (MAPI32.72)
476 * Compare two Mapi names.
478 * PARAMS
479 * lpName1 [I] First name to compare to lpName2
480 * lpName2 [I] Second name to compare to lpName1
482 * RETURNS
483 * TRUE, if the names are the same,
484 * FALSE, Otherwise.
486 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
488 TRACE("(%p,%p)\n", lpName1, lpName2);
490 if (!lpName1 || !lpName2 ||
491 !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) ||
492 lpName1->ulKind != lpName2->ulKind)
493 return FALSE;
495 if (lpName1->ulKind == MNID_STRING)
496 return !lstrcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName);
498 return lpName1->Kind.lID == lpName2->Kind.lID;
501 /**************************************************************************
502 * IsBadBoundedStringPtr@8 (MAPI32.71)
504 * Determine if a string pointer is valid.
506 * PARAMS
507 * lpszStr [I] String to check
508 * ulLen [I] Maximum length of lpszStr
510 * RETURNS
511 * TRUE, if lpszStr is invalid or longer than ulLen,
512 * FALSE, otherwise.
514 BOOL WINAPI IsBadBoundedStringPtr(LPCSTR lpszStr, ULONG ulLen)
516 if (!lpszStr || IsBadStringPtrA(lpszStr, -1) || strlen(lpszStr) >= ulLen)
517 return TRUE;
518 return FALSE;
521 /**************************************************************************
522 * FtAddFt@16 (MAPI32.121)
524 * Add two FILETIME's together.
526 * PARAMS
527 * ftLeft [I] FILETIME to add to ftRight
528 * ftRight [I] FILETIME to add to ftLeft
530 * RETURNS
531 * The sum of ftLeft and ftRight
533 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight)
535 LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
537 return *pl + *pr;
540 /**************************************************************************
541 * FtSubFt@16 (MAPI32.123)
543 * Subtract two FILETIME's together.
545 * PARAMS
546 * ftLeft [I] Initial FILETIME
547 * ftRight [I] FILETIME to subtract from ftLeft
549 * RETURNS
550 * The remainder after ftRight is subtracted from ftLeft.
552 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight)
554 LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
556 return *pr - *pl;
559 /**************************************************************************
560 * FtMulDw@12 (MAPI32.124)
562 * Multiply a FILETIME by a DWORD.
564 * PARAMS
565 * dwLeft [I] DWORD to multiply with ftRight
566 * ftRight [I] FILETIME to multiply with dwLeft
568 * RETURNS
569 * The product of dwLeft and ftRight
571 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight)
573 LONGLONG *pr = (LONGLONG*)&ftRight;
575 return (LONGLONG)dwLeft * (*pr);
578 /**************************************************************************
579 * FtMulDwDw@8 (MAPI32.125)
581 * Multiply two DWORD, giving the result as a FILETIME.
583 * PARAMS
584 * dwLeft [I] DWORD to multiply with dwRight
585 * dwRight [I] DWORD to multiply with dwLeft
587 * RETURNS
588 * The product of ftMultiplier and ftMultiplicand as a FILETIME.
590 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight)
592 return (LONGLONG)dwLeft * (LONGLONG)dwRight;
595 /**************************************************************************
596 * FtNegFt@8 (MAPI32.126)
598 * Negate a FILETIME.
600 * PARAMS
601 * ft [I] FILETIME to negate
603 * RETURNS
604 * The negation of ft.
606 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft)
608 LONGLONG *p = (LONGLONG*)&ft;
610 return - *p;
613 /**************************************************************************
614 * UlAddRef@4 (MAPI32.128)
616 * Add a reference to an object.
618 * PARAMS
619 * lpUnk [I] Object to add a reference to.
621 * RETURNS
622 * The new reference count of the object, or 0 if lpUnk is NULL.
624 * NOTES
625 * See IUnknown_AddRef.
627 ULONG WINAPI UlAddRef(void *lpUnk)
629 TRACE("(%p)\n", lpUnk);
631 if (!lpUnk)
632 return 0UL;
633 return IUnknown_AddRef((LPUNKNOWN)lpUnk);
636 /**************************************************************************
637 * UlRelease@4 (MAPI32.129)
639 * Remove a reference from an object.
641 * PARAMS
642 * lpUnk [I] Object to remove reference from.
644 * RETURNS
645 * The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
646 * non-NULL and this function returns 0, the object pointed to by lpUnk has
647 * been released.
649 * NOTES
650 * See IUnknown_Release.
652 ULONG WINAPI UlRelease(void *lpUnk)
654 TRACE("(%p)\n", lpUnk);
656 if (!lpUnk)
657 return 0UL;
658 return IUnknown_Release((LPUNKNOWN)lpUnk);
661 /**************************************************************************
662 * UFromSz@4 (MAPI32.133)
664 * Read an integer from a string
666 * PARAMS
667 * lpszStr [I] String to read the integer from.
669 * RETURNS
670 * Success: The integer read from lpszStr.
671 * Failure: 0, if the first character in lpszStr is not 0-9.
673 * NOTES
674 * This function does not accept whitespace and stops at the first non-digit
675 * character.
677 UINT WINAPI UFromSz(LPCSTR lpszStr)
679 ULONG ulRet = 0;
681 TRACE("(%s)\n", debugstr_a(lpszStr));
683 if (lpszStr)
685 while (*lpszStr >= '0' && *lpszStr <= '9')
687 ulRet = ulRet * 10 + (*lpszStr - '0');
688 lpszStr++;
691 return ulRet;
694 /*************************************************************************
695 * OpenStreamOnFile@24 (MAPI32.147)
697 * Create a stream on a file.
699 * PARAMS
700 * lpAlloc [I] Memory allocation function
701 * lpFree [I] Memory free function
702 * ulFlags [I] Flags controlling the opening process
703 * lpszPath [I] Path of file to create stream on
704 * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
705 * lppStream [O] Destination for created stream
707 * RETURNS
708 * Success: S_OK. lppStream contains the new stream object
709 * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
710 * describing the error.
712 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree,
713 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix,
714 LPSTREAM *lppStream)
716 WCHAR szBuff[MAX_PATH];
717 DWORD dwMode = STGM_READWRITE, dwAttributes = 0;
718 HRESULT hRet;
720 TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags,
721 debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream);
723 if (mapiFunctions.OpenStreamOnFile)
724 return mapiFunctions.OpenStreamOnFile(lpAlloc, lpFree, ulFlags, lpszPath, lpszPrefix, lppStream);
726 if (lppStream)
727 *lppStream = NULL;
729 if (ulFlags & SOF_UNIQUEFILENAME)
731 FIXME("Should generate a temporary name\n");
732 return E_INVALIDARG;
735 if (!lpszPath || !lppStream)
736 return E_INVALIDARG;
738 /* FIXME: Should probably munge mode and attributes, and should handle
739 * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
740 * we are being passed Unicode strings; MSDN doesn't say).
741 * This implementation is just enough for Outlook97 to start.
743 MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH);
744 hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE,
745 NULL, lppStream);
746 return hRet;
749 /*************************************************************************
750 * UlFromSzHex@4 (MAPI32.155)
752 * Read an integer from a hexadecimal string.
754 * PARAMS
755 * lpSzHex [I] String containing the hexadecimal number to read
757 * RETURNS
758 * Success: The number represented by lpszHex.
759 * Failure: 0, if lpszHex does not contain a hex string.
761 * NOTES
762 * This function does not accept whitespace and stops at the first non-hex
763 * character.
765 ULONG WINAPI UlFromSzHex(LPCWSTR lpszHex)
767 LPCSTR lpStr = (LPCSTR)lpszHex;
768 ULONG ulRet = 0;
770 TRACE("(%s)\n", debugstr_a(lpStr));
772 while (*lpStr)
774 if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
775 lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
776 break;
778 ulRet = ulRet * 16 + ((digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']);
779 lpStr += 2;
781 return ulRet;
784 /************************************************************************
785 * FBadEntryList@4 (MAPI32.190)
787 * Determine is an entry list is invalid.
789 * PARAMS
790 * lpEntryList [I] List to check
792 * RETURNS
793 * TRUE, if lpEntryList is invalid,
794 * FALSE, otherwise.
796 BOOL WINAPI FBadEntryList(LPENTRYLIST lpEntryList)
798 ULONG i;
800 if (IsBadReadPtr(lpEntryList, sizeof(*lpEntryList)) ||
801 IsBadReadPtr(lpEntryList->lpbin,
802 lpEntryList->cValues * sizeof(*lpEntryList->lpbin)))
803 return TRUE;
805 for (i = 0; i < lpEntryList->cValues; i++)
806 if(IsBadReadPtr(lpEntryList->lpbin[i].lpb, lpEntryList->lpbin[i].cb))
807 return TRUE;
809 return FALSE;
812 /*************************************************************************
813 * CbOfEncoded@4 (MAPI32.207)
815 * Return the length of an encoded string.
817 * PARAMS
818 * lpSzEnc [I] Encoded string to get the length of.
820 * RETURNS
821 * The length of the encoded string in bytes.
823 ULONG WINAPI CbOfEncoded(LPCSTR lpszEnc)
825 ULONG ulRet = 0;
827 TRACE("(%s)\n", debugstr_a(lpszEnc));
829 if (lpszEnc)
830 ulRet = (((strlen(lpszEnc) | 3) >> 2) + 1) * 3;
831 return ulRet;
834 /*************************************************************************
835 * cmc_query_configuration (MAPI32.235)
837 * Retrieves the configuration information for the installed CMC
839 * PARAMS
840 * session [I] MAPI session handle
841 * item [I] Enumerated variable that identifies which
842 * configuration information is being requested
843 * reference [O] Buffer where configuration information is written
844 * config_extensions[I/O] Path of file to create stream on
846 * RETURNS
847 * A CMD define
849 CMC_return_code WINAPI cmc_query_configuration(
850 CMC_session_id session,
851 CMC_enum item,
852 CMC_buffer reference,
853 CMC_extension *config_extensions)
855 FIXME("stub\n");
856 return CMC_E_NOT_SUPPORTED;
859 /**************************************************************************
860 * FGetComponentPath (MAPI32.254)
861 * FGetComponentPath@20 (MAPI32.255)
863 * Return the installed component path, usually to the private mapi32.dll.
865 * PARAMS
866 * component [I] Component ID
867 * qualifier [I] Application LCID
868 * dll_path [O] returned component path
869 * dll_path_length [I] component path length
870 * install [I] install mode
872 * RETURNS
873 * Success: TRUE.
874 * Failure: FALSE.
876 * NOTES
877 * Previously documented in Q229700 "How to locate the correct path
878 * to the Mapisvc.inf file in Microsoft Outlook".
880 BOOL WINAPI FGetComponentPath(LPCSTR component, LPCSTR qualifier, LPSTR dll_path,
881 DWORD dll_path_length, BOOL install)
883 BOOL ret = FALSE;
884 HMODULE hmsi;
886 TRACE("%s %s %p %u %d\n", component, qualifier, dll_path, dll_path_length, install);
888 if (mapiFunctions.FGetComponentPath)
889 return mapiFunctions.FGetComponentPath(component, qualifier, dll_path, dll_path_length, install);
891 dll_path[0] = 0;
893 hmsi = LoadLibraryA("msi.dll");
894 if (hmsi)
896 UINT (WINAPI *pMsiProvideQualifiedComponentA)(LPCSTR, LPCSTR, DWORD, LPSTR, LPDWORD);
898 pMsiProvideQualifiedComponentA = (void *)GetProcAddress(hmsi, "MsiProvideQualifiedComponentA");
899 if (pMsiProvideQualifiedComponentA)
901 static const char * const fmt[] = { "%d\\NT", "%d\\95", "%d" };
902 char lcid_ver[20];
903 UINT i;
905 for (i = 0; i < ARRAY_SIZE(fmt); i++)
907 /* FIXME: what's the correct behaviour here? */
908 if (!qualifier || qualifier == lcid_ver)
910 sprintf(lcid_ver, fmt[i], GetUserDefaultUILanguage());
911 qualifier = lcid_ver;
914 if (pMsiProvideQualifiedComponentA(component, qualifier,
915 install ? INSTALLMODE_DEFAULT : INSTALLMODE_EXISTING,
916 dll_path, &dll_path_length) == ERROR_SUCCESS)
918 ret = TRUE;
919 break;
922 if (qualifier != lcid_ver) break;
925 FreeLibrary(hmsi);
927 return ret;
930 /**************************************************************************
931 * HrQueryAllRows (MAPI32.75)
933 HRESULT WINAPI HrQueryAllRows(LPMAPITABLE lpTable, LPSPropTagArray lpPropTags,
934 LPSRestriction lpRestriction, LPSSortOrderSet lpSortOrderSet,
935 LONG crowsMax, LPSRowSet *lppRows)
937 if (mapiFunctions.HrQueryAllRows)
938 return mapiFunctions.HrQueryAllRows(lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows);
940 FIXME("(%p, %p, %p, %p, %d, %p): stub\n", lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows);
941 *lppRows = NULL;
942 return MAPI_E_CALL_FAILED;
945 /**************************************************************************
946 * WrapCompressedRTFStream (MAPI32.186)
948 HRESULT WINAPI WrapCompressedRTFStream(LPSTREAM compressed, ULONG flags, LPSTREAM *uncompressed)
950 if (mapiFunctions.WrapCompressedRTFStream)
951 return mapiFunctions.WrapCompressedRTFStream(compressed, flags, uncompressed);
953 FIXME("(%p, 0x%08x, %p): stub\n", compressed, flags, uncompressed);
954 return MAPI_E_NO_SUPPORT;
957 static HMODULE mapi_provider;
958 static HMODULE mapi_ex_provider;
960 /**************************************************************************
961 * load_mapi_provider
963 * Attempts to load a MAPI provider from the specified registry key.
965 * Returns a handle to the loaded module in `mapi_provider' if successful.
967 static void load_mapi_provider(HKEY hkeyMail, LPCWSTR valueName, HMODULE *mapi_provider)
969 DWORD dwType, dwLen = 0;
970 LPWSTR dllPath;
972 /* Check if we have a value set for DLLPath */
973 if ((RegQueryValueExW(hkeyMail, valueName, NULL, &dwType, NULL, &dwLen) == ERROR_SUCCESS) &&
974 ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) && (dwLen > 0))
976 dllPath = HeapAlloc(GetProcessHeap(), 0, dwLen);
978 if (dllPath)
980 RegQueryValueExW(hkeyMail, valueName, NULL, NULL, (LPBYTE)dllPath, &dwLen);
982 /* Check that this value doesn't refer to mapi32.dll (eg, as Outlook does) */
983 if (lstrcmpiW(dllPath, L"mapi32.dll") != 0)
985 if (dwType == REG_EXPAND_SZ)
987 DWORD dwExpandLen;
988 LPWSTR dllPathExpanded;
990 /* Expand the path if necessary */
991 dwExpandLen = ExpandEnvironmentStringsW(dllPath, NULL, 0);
992 dllPathExpanded = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * dwExpandLen + 1);
994 if (dllPathExpanded)
996 ExpandEnvironmentStringsW(dllPath, dllPathExpanded, dwExpandLen + 1);
998 HeapFree(GetProcessHeap(), 0, dllPath);
999 dllPath = dllPathExpanded;
1003 /* Load the DLL */
1004 TRACE("loading %s\n", debugstr_w(dllPath));
1005 *mapi_provider = LoadLibraryW(dllPath);
1008 HeapFree(GetProcessHeap(), 0, dllPath);
1013 /**************************************************************************
1014 * load_mapi_providers
1016 * Scans the registry for MAPI providers and attempts to load a Simple and
1017 * Extended MAPI library.
1019 * Returns TRUE if at least one library loaded, FALSE otherwise.
1021 void load_mapi_providers(void)
1023 static const WCHAR regkey_mail[] = L"Software\\Clients\\Mail";
1025 HKEY hkeyMail;
1026 DWORD dwType, dwLen = 0;
1027 LPWSTR appName = NULL, appKey = NULL;
1029 TRACE("()\n");
1031 /* Open the Mail key */
1032 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, regkey_mail, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS)
1033 return;
1035 /* Check if we have a default value set, and the length of it */
1036 if ((RegQueryValueExW(hkeyMail, NULL, NULL, &dwType, NULL, &dwLen) != ERROR_SUCCESS) ||
1037 !((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) || (dwLen == 0))
1038 goto cleanUp;
1040 appName = HeapAlloc(GetProcessHeap(), 0, dwLen);
1042 if (!appName)
1043 goto cleanUp;
1045 /* Get the value, and get the path to the app key */
1046 RegQueryValueExW(hkeyMail, NULL, NULL, NULL, (LPBYTE)appName, &dwLen);
1048 TRACE("appName: %s\n", debugstr_w(appName));
1050 appKey = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(regkey_mail) +
1051 lstrlenW(L"\\") + lstrlenW(appName) + 1));
1053 if (!appKey)
1054 goto cleanUp;
1056 lstrcpyW(appKey, regkey_mail);
1057 lstrcatW(appKey, L"\\");
1058 lstrcatW(appKey, appName);
1060 RegCloseKey(hkeyMail);
1062 TRACE("appKey: %s\n", debugstr_w(appKey));
1064 /* Open the app's key */
1065 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, appKey, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS)
1066 goto cleanUp;
1068 /* Try to load the providers */
1069 load_mapi_provider(hkeyMail, L"DLLPath", &mapi_provider);
1070 load_mapi_provider(hkeyMail, L"DLLPathEx", &mapi_ex_provider);
1072 /* Now try to load our function pointers */
1073 ZeroMemory(&mapiFunctions, sizeof(mapiFunctions));
1075 /* Simple MAPI functions */
1076 if (mapi_provider)
1078 mapiFunctions.MAPIAddress = (void*) GetProcAddress(mapi_provider, "MAPIAddress");
1079 mapiFunctions.MAPIDeleteMail = (void*) GetProcAddress(mapi_provider, "MAPIDeleteMail");
1080 mapiFunctions.MAPIDetails = (void*) GetProcAddress(mapi_provider, "MAPIDetails");
1081 mapiFunctions.MAPIFindNext = (void*) GetProcAddress(mapi_provider, "MAPIFindNext");
1082 mapiFunctions.MAPILogoff = (void*) GetProcAddress(mapi_provider, "MAPILogoff");
1083 mapiFunctions.MAPILogon = (void*) GetProcAddress(mapi_provider, "MAPILogon");
1084 mapiFunctions.MAPIReadMail = (void*) GetProcAddress(mapi_provider, "MAPIReadMail");
1085 mapiFunctions.MAPIResolveName = (void*) GetProcAddress(mapi_provider, "MAPIResolveName");
1086 mapiFunctions.MAPISaveMail = (void*) GetProcAddress(mapi_provider, "MAPISaveMail");
1087 mapiFunctions.MAPISendDocuments = (void*) GetProcAddress(mapi_provider, "MAPISendDocuments");
1088 mapiFunctions.MAPISendMail = (void*) GetProcAddress(mapi_provider, "MAPISendMail");
1089 mapiFunctions.MAPISendMailW = (void*) GetProcAddress(mapi_provider, "MAPISendMailW");
1092 /* Extended MAPI functions */
1093 if (mapi_ex_provider)
1095 mapiFunctions.MAPIInitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIInitialize");
1096 mapiFunctions.MAPILogonEx = (void*) GetProcAddress(mapi_ex_provider, "MAPILogonEx");
1097 mapiFunctions.MAPIUninitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIUninitialize");
1099 mapiFunctions.DeinitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "DeinitMapiUtil@0");
1100 mapiFunctions.DllCanUnloadNow = (void*) GetProcAddress(mapi_ex_provider, "DllCanUnloadNow");
1101 mapiFunctions.DllGetClassObject = (void*) GetProcAddress(mapi_ex_provider, "DllGetClassObject");
1102 mapiFunctions.FGetComponentPath = (void*) GetProcAddress(mapi_ex_provider, "FGetComponentPath");
1103 mapiFunctions.HrThisThreadAdviseSink = (void*) GetProcAddress(mapi_ex_provider, "HrThisThreadAdviseSink@8");
1104 mapiFunctions.HrQueryAllRows = (void*) GetProcAddress(mapi_ex_provider, "HrQueryAllRows@24");
1105 mapiFunctions.MAPIAdminProfiles = (void*) GetProcAddress(mapi_ex_provider, "MAPIAdminProfiles");
1106 mapiFunctions.MAPIAllocateBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateBuffer");
1107 mapiFunctions.MAPIAllocateMore = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateMore");
1108 mapiFunctions.MAPIFreeBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIFreeBuffer");
1109 mapiFunctions.MAPIGetDefaultMalloc = (void*) GetProcAddress(mapi_ex_provider, "MAPIGetDefaultMalloc@0");
1110 mapiFunctions.MAPIOpenLocalFormContainer = (void *) GetProcAddress(mapi_ex_provider, "MAPIOpenLocalFormContainer");
1111 mapiFunctions.OpenStreamOnFile = (void*) GetProcAddress(mapi_ex_provider, "OpenStreamOnFile@24");
1112 mapiFunctions.ScInitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "ScInitMapiUtil@4");
1113 mapiFunctions.WrapCompressedRTFStream = (void*) GetProcAddress(mapi_ex_provider, "WrapCompressedRTFStream@12");
1116 cleanUp:
1117 RegCloseKey(hkeyMail);
1118 HeapFree(GetProcessHeap(), 0, appKey);
1119 HeapFree(GetProcessHeap(), 0, appName);
1122 /**************************************************************************
1123 * unload_mapi_providers
1125 * Unloads any loaded MAPI libraries.
1127 void unload_mapi_providers(void)
1129 TRACE("()\n");
1131 FreeLibrary(mapi_provider);
1132 FreeLibrary(mapi_ex_provider);