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