oleaut32: For automatic-value-getting in ITypeInfo::Invoke, it doesn't matter what...
[wine] / dlls / mapi32 / util.c
1 /*
2  * MAPI Utility functions
3  *
4  * Copyright 2004 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winternl.h"
33 #include "objbase.h"
34 #include "shlwapi.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "mapival.h"
38 #include "xcmc.h"
39 #include "msi.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
42
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 };
48
49 /**************************************************************************
50  *  ScInitMapiUtil (MAPI32.33)
51  *
52  * Initialise Mapi utility functions.
53  *
54  * PARAMS
55  *  ulReserved [I] Reserved, pass 0.
56  *
57  * RETURNS
58  *  Success: S_OK. Mapi utility functions may be called.
59  *  Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
60  *
61  * NOTES
62  *  Your application does not need to call this function unless it does not
63  *  call MAPIInitialize()/MAPIUninitialize().
64  */
65 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved)
66 {
67     FIXME("(0x%08x)stub!\n", ulReserved);
68     if (ulReserved)
69         return MAPI_E_INVALID_PARAMETER;
70     return S_OK;
71 }
72
73 /**************************************************************************
74  *  DeinitMapiUtil (MAPI32.34)
75  *
76  * Uninitialise Mapi utility functions.
77  *
78  * PARAMS
79  *  None.
80  *
81  * RETURNS
82  *  Nothing.
83  *
84  * NOTES
85  *  Your application does not need to call this function unless it does not
86  *  call MAPIInitialize()/MAPIUninitialize().
87  */
88 VOID WINAPI DeinitMapiUtil(void)
89 {
90     FIXME("()stub!\n");
91 }
92
93 typedef LPVOID *LPMAPIALLOCBUFFER;
94
95 /**************************************************************************
96  *  MAPIAllocateBuffer   (MAPI32.12)
97  *  MAPIAllocateBuffer@8 (MAPI32.13)
98  *
99  * Allocate a block of memory.
100  *
101  * PARAMS
102  *  cbSize    [I] Size of the block to allocate in bytes
103  *  lppBuffer [O] Destination for pointer to allocated memory
104  *
105  * RETURNS
106  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
107  *           length cbSize bytes.
108  *  Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
109  *           MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
110  *
111  * NOTES
112  *  Memory allocated with this function should be freed with MAPIFreeBuffer().
113  *  Further allocations of memory may be linked to the pointer returned using
114  *  MAPIAllocateMore(). Linked allocations are freed when the initial pointer
115  *  is feed.
116  */
117 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer)
118 {
119     LPMAPIALLOCBUFFER lpBuff;
120
121     TRACE("(%d,%p)\n", cbSize, lppBuffer);
122
123     if (!lppBuffer)
124         return E_INVALIDARG;
125
126     lpBuff = HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff));
127     if (!lpBuff)
128         return MAPI_E_NOT_ENOUGH_MEMORY;
129
130     TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1);
131     *lpBuff++ = NULL;
132     *lppBuffer = lpBuff;
133     return S_OK;
134 }
135
136 /**************************************************************************
137  *  MAPIAllocateMore    (MAPI32.14)
138  *  MAPIAllocateMore@12 (MAPI32.15)
139  *
140  * Allocate a block of memory linked to a previous allocation.
141  *
142  * PARAMS
143  *  cbSize    [I] Size of the block to allocate in bytes
144  *  lpOrig    [I] Initial allocation to link to, from MAPIAllocateBuffer()
145  *  lppBuffer [O] Destination for pointer to allocated memory
146  *
147  * RETURNS
148  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
149  *           length cbSize bytes.
150  *  Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
151  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
152  *
153  * NOTES
154  *  Memory allocated with this function and stored in *lppBuffer is freed
155  *  when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
156  */
157 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer)
158 {
159     LPMAPIALLOCBUFFER lpBuff = lpOrig;
160
161     TRACE("(%d,%p,%p)\n", cbSize, lpOrig, lppBuffer);
162
163     if (!lppBuffer || !lpBuff || !--lpBuff)
164         return E_INVALIDARG;
165
166     /* Find the last allocation in the chain */
167     while (*lpBuff)
168     {
169         TRACE("linked:%p->%p\n", lpBuff, *lpBuff);
170         lpBuff = *lpBuff;
171     }
172
173     if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer)))
174     {
175         *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1;
176         TRACE("linking %p->%p\n", lpBuff, *lpBuff);
177     }
178     return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY;
179 }
180
181 /**************************************************************************
182  *  MAPIFreeBuffer   (MAPI32.16)
183  *  MAPIFreeBuffer@4 (MAPI32.17)
184  *
185  * Free a block of memory and any linked allocations associated with it.
186  *
187  * PARAMS
188  *  lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
189  *
190  * RETURNS
191  *  S_OK.
192  */
193 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer)
194 {
195     LPMAPIALLOCBUFFER lpBuff = lpBuffer;
196
197     TRACE("(%p)\n", lpBuffer);
198
199     if (lpBuff && --lpBuff)
200     {
201         while (lpBuff)
202         {
203             LPVOID lpFree = lpBuff;
204
205             lpBuff = *lpBuff;
206
207             TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree);
208             HeapFree(GetProcessHeap(), 0, lpFree);
209         }
210     }
211     return S_OK;
212 }
213
214 /**************************************************************************
215  *  WrapProgress@20 (MAPI32.41)
216  */
217 HRESULT WINAPI WrapProgress(PVOID unk1, PVOID unk2, PVOID unk3, PVOID unk4, PVOID unk5)
218 {
219     /* Native does not implement this function */
220     return MAPI_E_NO_SUPPORT;
221 }
222
223 /*************************************************************************
224  * HrThisThreadAdviseSink@8 (MAPI32.42)
225  *
226  * Ensure that an advise sink is only notified in its originating thread.
227  *
228  * PARAMS
229  *  lpSink     [I] IMAPIAdviseSink interface to be protected
230  *  lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
231  *
232  * RETURNS
233  * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
234  * Failure: E_INVALIDARG, if any parameter is invalid.
235  */
236 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink)
237 {
238     FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink);
239
240     if (!lpSink || !lppNewSink)
241         return E_INVALIDARG;
242
243     /* Don't wrap the sink for now, just copy it */
244     *lppNewSink = lpSink;
245     IMAPIAdviseSink_AddRef(lpSink);
246     return S_OK;
247 }
248
249 /*************************************************************************
250  * FBinFromHex (MAPI32.44)
251  *
252  * Create an array of binary data from a string.
253  *
254  * PARAMS
255  *  lpszHex [I] String to convert to binary data
256  *  lpOut   [O] Destination for resulting binary data
257  *
258  * RETURNS
259  *  Success: TRUE. lpOut contains the decoded binary data.
260  *  Failure: FALSE, if lpszHex does not represent a binary string.
261  *
262  * NOTES
263  *  - lpOut must be at least half the length of lpszHex in bytes.
264  *  - Although the Mapi headers prototype this function as both
265  *    Ascii and Unicode, there is only one (Ascii) implementation. This
266  *    means that lpszHex is treated as an Ascii string (i.e. a single NUL
267  *    character in the byte stream terminates the string).
268  */
269 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut)
270 {
271     LPSTR lpStr = (LPSTR)lpszHex;
272
273     TRACE("(%p,%p)\n", lpszHex, lpOut);
274
275     while (*lpStr)
276     {
277         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
278             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
279             return FALSE;
280
281         *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0'];
282         lpStr += 2;
283     }
284     return TRUE;
285 }
286
287 /*************************************************************************
288  * HexFromBin (MAPI32.45)
289  *
290  * Create a string from an array of binary data.
291  *
292  * PARAMS
293  *  lpHex   [I] Binary data to convert to string
294  *  iCount  [I] Length of lpHex in bytes
295  *  lpszOut [O] Destination for resulting hex string
296  *
297  * RETURNS
298  *  Nothing.
299  *
300  * NOTES
301  *  - lpszOut must be at least 2 * iCount + 1 bytes characters long.
302  *  - Although the Mapi headers prototype this function as both
303  *    Ascii and Unicode, there is only one (Ascii) implementation. This
304  *    means that the resulting string is not properly NUL terminated
305  *    if the caller expects it to be a Unicode string.
306  */
307 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut)
308 {
309     static const char hexDigits[] = { "0123456789ABCDEF" };
310     LPSTR lpStr = (LPSTR)lpszOut;
311
312     TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut);
313
314     while (iCount-- > 0)
315     {
316         *lpStr++ = hexDigits[*lpHex >> 4];
317         *lpStr++ = hexDigits[*lpHex & 0xf];
318         lpHex++;
319     }
320     *lpStr = '\0';
321 }
322
323 /*************************************************************************
324  * SwapPlong@8 (MAPI32.47)
325  *
326  * Swap the bytes in a ULONG array.
327  *
328  * PARAMS
329  *  lpData [O] Array to swap bytes in
330  *  ulLen  [I] Number of ULONG element to swap the bytes of
331  *
332  * RETURNS
333  *  Nothing.
334  */
335 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen)
336 {
337     ULONG i;
338
339     for (i = 0; i < ulLen; i++)
340         lpData[i] = RtlUlongByteSwap(lpData[i]);
341 }
342
343 /*************************************************************************
344  * SwapPword@8 (MAPI32.48)
345  *
346  * Swap the bytes in a USHORT array.
347  *
348  * PARAMS
349  *  lpData [O] Array to swap bytes in
350  *  ulLen  [I] Number of USHORT element to swap the bytes of
351  *
352  * RETURNS
353  *  Nothing.
354  */
355 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen)
356 {
357     ULONG i;
358
359     for (i = 0; i < ulLen; i++)
360         lpData[i] = RtlUshortByteSwap(lpData[i]);
361 }
362
363 /**************************************************************************
364  *  MNLS_lstrlenW@4 (MAPI32.62)
365  *
366  * Calculate the length of a Unicode string.
367  *
368  * PARAMS
369  *  lpszStr [I] String to calculate the length of
370  *
371  * RETURNS
372  *  The length of lpszStr in Unicode characters.
373  */
374 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr)
375 {
376     TRACE("(%s)\n", debugstr_w(lpszStr));
377     return strlenW(lpszStr);
378 }
379
380 /*************************************************************************
381  * MNLS_lstrcmpW@8 (MAPI32.63)
382  *
383  * Compare two Unicode strings.
384  *
385  * PARAMS
386  *  lpszLeft  [I] First string to compare
387  *  lpszRight [I] Second string to compare
388  *
389  * RETURNS
390  *  An integer less than, equal to or greater than 0, indicating that
391  *  lpszLeft is less than, the same, or greater than lpszRight.
392  */
393 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight)
394 {
395     TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight));
396     return strcmpW(lpszLeft, lpszRight);
397 }
398
399 /*************************************************************************
400  * MNLS_lstrcpyW@8 (MAPI32.64)
401  *
402  * Copy a Unicode string to another string.
403  *
404  * PARAMS
405  *  lpszDest [O] Destination string
406  *  lpszSrc  [I] Source string
407  *
408  * RETURNS
409  *  The length lpszDest in Unicode characters.
410  */
411 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc)
412 {
413     ULONG len;
414
415     TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc));
416     len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR);
417     memcpy(lpszDest, lpszSrc, len);
418     return len;
419 }
420
421 /*************************************************************************
422  * MNLS_CompareStringW@12 (MAPI32.65)
423  *
424  * Compare two Unicode strings.
425  *
426  * PARAMS
427  *  dwCp      [I] Code page for the comparison
428  *  lpszLeft  [I] First string to compare
429  *  lpszRight [I] Second string to compare
430  *
431  * RETURNS
432  *  CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
433  *  lpszLeft is less than, the same, or greater than lpszRight.
434  */
435 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight)
436 {
437     INT ret;
438
439     TRACE("0x%08x,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight));
440     ret = MNLS_lstrcmpW(lpszLeft, lpszRight);
441     return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL;
442 }
443
444 /**************************************************************************
445  *  FEqualNames@8 (MAPI32.72)
446  *
447  * Compare two Mapi names.
448  *
449  * PARAMS
450  *  lpName1 [I] First name to compare to lpName2
451  *  lpName2 [I] Second name to compare to lpName1
452  *
453  * RETURNS
454  *  TRUE, if the names are the same,
455  *  FALSE, Otherwise.
456  */
457 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
458 {
459     TRACE("(%p,%p)\n", lpName1, lpName2);
460
461     if (!lpName1 || !lpName2 ||
462         !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) ||
463         lpName1->ulKind != lpName2->ulKind)
464         return FALSE;
465
466     if (lpName1->ulKind == MNID_STRING)
467         return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName);
468
469     return lpName1->Kind.lID == lpName2->Kind.lID ? TRUE : FALSE;
470 }
471
472 /**************************************************************************
473  *  IsBadBoundedStringPtr@8 (MAPI32.71)
474  *
475  * Determine if a string pointer is valid.
476  *
477  * PARAMS
478  *  lpszStr [I] String to check
479  *  ulLen   [I] Maximum length of lpszStr
480  *
481  * RETURNS
482  *  TRUE, if lpszStr is invalid or longer than ulLen,
483  *  FALSE, otherwise.
484  */
485 BOOL WINAPI IsBadBoundedStringPtr(LPCSTR lpszStr, ULONG ulLen)
486 {
487     if (!lpszStr || IsBadStringPtrA(lpszStr, -1) || strlen(lpszStr) >= ulLen)
488         return TRUE;
489     return FALSE;
490 }
491
492 /**************************************************************************
493  *  FtAddFt@16 (MAPI32.121)
494  *
495  * Add two FILETIME's together.
496  *
497  * PARAMS
498  *  ftLeft  [I] FILETIME to add to ftRight
499  *  ftRight [I] FILETIME to add to ftLeft
500  *
501  * RETURNS
502  *  The sum of ftLeft and ftRight
503  */
504 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight)
505 {
506     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
507
508     return *pl + *pr;
509 }
510
511 /**************************************************************************
512  *  FtSubFt@16 (MAPI32.123)
513  *
514  * Subtract two FILETIME's together.
515  *
516  * PARAMS
517  *  ftLeft  [I] Initial FILETIME
518  *  ftRight [I] FILETIME to subtract from ftLeft
519  *
520  * RETURNS
521  *  The remainder after ftRight is subtracted from ftLeft.
522  */
523 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight)
524 {
525     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
526
527     return *pr - *pl;
528 }
529
530 /**************************************************************************
531  *  FtMulDw@12 (MAPI32.124)
532  *
533  * Multiply a FILETIME by a DWORD.
534  *
535  * PARAMS
536  *  dwLeft  [I] DWORD to multiply with ftRight
537  *  ftRight [I] FILETIME to multiply with dwLeft
538  *
539  * RETURNS
540  *  The product of dwLeft and ftRight
541  */
542 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight)
543 {
544     LONGLONG *pr = (LONGLONG*)&ftRight;
545
546     return (LONGLONG)dwLeft * (*pr);
547 }
548
549 /**************************************************************************
550  *  FtMulDwDw@8 (MAPI32.125)
551  *
552  * Multiply two DWORD, giving the result as a FILETIME.
553  *
554  * PARAMS
555  *  dwLeft  [I] DWORD to multiply with dwRight
556  *  dwRight [I] DWORD to multiply with dwLeft
557  *
558  * RETURNS
559  *  The product of ftMultiplier and ftMultiplicand as a FILETIME.
560  */
561 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight)
562 {
563     return (LONGLONG)dwLeft * (LONGLONG)dwRight;
564 }
565
566 /**************************************************************************
567  *  FtNegFt@8 (MAPI32.126)
568  *
569  * Negate a FILETIME.
570  *
571  * PARAMS
572  *  ft [I] FILETIME to negate
573  *
574  * RETURNS
575  *  The negation of ft.
576  */
577 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft)
578 {
579     LONGLONG *p = (LONGLONG*)&ft;
580
581     return - *p;
582 }
583
584 /**************************************************************************
585  *  UlAddRef@4 (MAPI32.128)
586  *
587  * Add a reference to an object.
588  *
589  * PARAMS
590  *  lpUnk [I] Object to add a reference to.
591  *
592  * RETURNS
593  *  The new reference count of the object, or 0 if lpUnk is NULL.
594  *
595  * NOTES
596  * See IUnknown_AddRef.
597  */
598 ULONG WINAPI UlAddRef(void *lpUnk)
599 {
600     TRACE("(%p)\n", lpUnk);
601
602     if (!lpUnk)
603         return 0UL;
604     return IUnknown_AddRef((LPUNKNOWN)lpUnk);
605 }
606
607 /**************************************************************************
608  *  UlRelease@4 (MAPI32.129)
609  *
610  * Remove a reference from an object.
611  *
612  * PARAMS
613  *  lpUnk [I] Object to remove reference from.
614  *
615  * RETURNS
616  *  The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
617  *  non-NULL and this function returns 0, the object pointed to by lpUnk has
618  *  been released.
619  *
620  * NOTES
621  * See IUnknown_Release.
622  */
623 ULONG WINAPI UlRelease(void *lpUnk)
624 {
625     TRACE("(%p)\n", lpUnk);
626
627     if (!lpUnk)
628         return 0UL;
629     return IUnknown_Release((LPUNKNOWN)lpUnk);
630 }
631
632 /**************************************************************************
633  *  UFromSz@4 (MAPI32.133)
634  *
635  * Read an integer from a string
636  *
637  * PARAMS
638  *  lpszStr [I] String to read the integer from.
639  *
640  * RETURNS
641  *  Success: The integer read from lpszStr.
642  *  Failure: 0, if the first character in lpszStr is not 0-9.
643  *
644  * NOTES
645  *  This function does not accept whitespace and stops at the first non-digit
646  *  character.
647  */
648 UINT WINAPI UFromSz(LPCSTR lpszStr)
649 {
650     ULONG ulRet = 0;
651
652     TRACE("(%s)\n", debugstr_a(lpszStr));
653
654     if (lpszStr)
655     {
656         while (*lpszStr >= '0' && *lpszStr <= '9')
657         {
658             ulRet = ulRet * 10 + (*lpszStr - '0');
659             lpszStr = CharNextA(lpszStr);
660         }
661     }
662     return ulRet;
663 }
664
665 /*************************************************************************
666  * OpenStreamOnFile@24 (MAPI32.147)
667  *
668  * Create a stream on a file.
669  *
670  * PARAMS
671  *  lpAlloc    [I] Memory allocation function
672  *  lpFree     [I] Memory free function
673  *  ulFlags    [I] Flags controlling the opening process
674  *  lpszPath   [I] Path of file to create stream on
675  *  lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
676  *  lppStream  [O] Destination for created stream
677  *
678  * RETURNS
679  * Success: S_OK. lppStream contains the new stream object
680  * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
681  *          describing the error.
682  */
683 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree,
684                                 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix,
685                                 LPSTREAM *lppStream)
686 {
687     WCHAR szBuff[MAX_PATH];
688     DWORD dwMode = STGM_READWRITE, dwAttributes = 0;
689     HRESULT hRet;
690
691     TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags,
692           debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream);
693
694     if (lppStream)
695         *lppStream = NULL;
696
697     if (ulFlags & SOF_UNIQUEFILENAME)
698     {
699         FIXME("Should generate a temporary name\n");
700         return E_INVALIDARG;
701     }
702
703     if (!lpszPath || !lppStream)
704         return E_INVALIDARG;
705
706     /* FIXME: Should probably munge mode and attributes, and should handle
707      *        Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
708      *        we are being passed Unicode strings; MSDN doesn't say).
709      *        This implementation is just enough for Outlook97 to start.
710      */
711     MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH);
712     hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE,
713                                   NULL, lppStream);
714     return hRet;
715 }
716
717 /*************************************************************************
718  * UlFromSzHex@4 (MAPI32.155)
719  *
720  * Read an integer from a hexadecimal string.
721  *
722  * PARAMS
723  *  lpSzHex [I] String containing the hexadecimal number to read
724  *
725  * RETURNS
726  * Success: The number represented by lpszHex.
727  * Failure: 0, if lpszHex does not contain a hex string.
728  *
729  * NOTES
730  *  This function does not accept whitespace and stops at the first non-hex
731  *  character.
732  */
733 ULONG WINAPI UlFromSzHex(LPCWSTR lpszHex)
734 {
735     LPCSTR lpStr = (LPCSTR)lpszHex;
736     ULONG ulRet = 0;
737
738     TRACE("(%s)\n", debugstr_a(lpStr));
739
740     while (*lpStr)
741     {
742         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
743             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
744             break;
745
746         ulRet = ulRet * 16 + ((digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']);
747         lpStr += 2;
748     }
749     return ulRet;
750 }
751
752 /************************************************************************
753  * FBadEntryList@4 (MAPI32.190)
754  *
755  * Determine is an entry list is invalid.
756  *
757  * PARAMS
758  *  lpEntryList [I] List to check
759  *
760  * RETURNS
761  *  TRUE, if lpEntryList is invalid,
762  *  FALSE, otherwise.
763  */
764 BOOL WINAPI FBadEntryList(LPENTRYLIST lpEntryList)
765 {
766     ULONG i;
767
768     if (IsBadReadPtr(lpEntryList, sizeof(*lpEntryList)) ||
769         IsBadReadPtr(lpEntryList->lpbin,
770                      lpEntryList->cValues * sizeof(*lpEntryList->lpbin)))
771         return TRUE;
772
773     for (i = 0; i < lpEntryList->cValues; i++)
774         if(IsBadReadPtr(lpEntryList->lpbin[i].lpb, lpEntryList->lpbin[i].cb))
775             return TRUE;
776
777     return FALSE;
778 }
779
780 /*************************************************************************
781  * CbOfEncoded@4 (MAPI32.207)
782  *
783  * Return the length of an encoded string.
784  *
785  * PARAMS
786  *  lpSzEnc [I] Encoded string to get the length of.
787  *
788  * RETURNS
789  * The length of the encoded string in bytes.
790  */
791 ULONG WINAPI CbOfEncoded(LPCSTR lpszEnc)
792 {
793     ULONG ulRet = 0;
794
795     TRACE("(%s)\n", debugstr_a(lpszEnc));
796
797     if (lpszEnc)
798         ulRet = (((strlen(lpszEnc) | 3) >> 2) + 1) * 3;
799     return ulRet;
800 }
801
802 /*************************************************************************
803  * cmc_query_configuration (MAPI32.235)
804  *
805  * Retrieves the configuration information for the installed CMC
806  *
807  * PARAMS
808  *  session          [I]   MAPI session handle
809  *  item             [I]   Enumerated variable that identifies which 
810  *                         configuration information is being requested
811  *  reference        [O]   Buffer where configuration information is written
812  *  config_extensions[I/O] Path of file to create stream on
813  *
814  * RETURNS
815  * A CMD define
816  */
817 CMC_return_code WINAPI cmc_query_configuration(
818   CMC_session_id session,
819   CMC_enum item,
820   CMC_buffer reference,
821   CMC_extension  *config_extensions)
822 {
823         FIXME("stub\n");
824         return CMC_E_NOT_SUPPORTED;
825 }
826
827 /**************************************************************************
828  *  FGetComponentPath   (MAPI32.254)
829  *  FGetComponentPath@20 (MAPI32.255)
830  *
831  * Return the installed component path, usually to the private mapi32.dll.
832  *
833  * PARAMS
834  *  component       [I] Component ID
835  *  qualifier       [I] Application LCID
836  *  dll_path        [O] returned component path
837  *  dll_path_length [I] component path length
838  *  install         [I] install mode
839  *
840  * RETURNS
841  *  Success: TRUE.
842  *  Failure: FALSE.
843  *
844  * NOTES
845  *  Previously documented in Q229700 "How to locate the correct path
846  *  to the Mapisvc.inf file in Microsoft Outlook".
847  */
848 BOOL WINAPI FGetComponentPath(LPCSTR component, LPCSTR qualifier, LPSTR dll_path,
849                               DWORD dll_path_length, BOOL install)
850 {
851     BOOL ret = FALSE;
852     HMODULE hmsi;
853
854     TRACE("%s %s %p %u %d\n", component, qualifier, dll_path, dll_path_length, install);
855
856     dll_path[0] = 0;
857
858     hmsi = LoadLibraryA("msi.dll");
859     if (hmsi)
860     {
861         FARPROC pMsiProvideQualifiedComponentA = GetProcAddress(hmsi, "MsiProvideQualifiedComponentA");
862
863         if (pMsiProvideQualifiedComponentA)
864         {
865             static const char * const fmt[] = { "%d\\NT", "%d\\95", "%d" };
866             char lcid_ver[20];
867             UINT i;
868
869             for (i = 0; i < sizeof(fmt)/sizeof(fmt[0]); i++)
870             {
871                 /* FIXME: what's the correct behaviour here? */
872                 if (!qualifier || qualifier == lcid_ver)
873                 {
874                     sprintf(lcid_ver, fmt[i], GetUserDefaultUILanguage());
875                     qualifier = lcid_ver;
876                 }
877
878                 if (pMsiProvideQualifiedComponentA(component, qualifier,
879                         install ? INSTALLMODE_DEFAULT : INSTALLMODE_EXISTING,
880                         dll_path, &dll_path_length) == ERROR_SUCCESS)
881                 {
882                     ret = TRUE;
883                     break;
884                 }
885
886                 if (qualifier != lcid_ver) break;
887             }
888         }
889         FreeLibrary(hmsi);
890     }
891     return ret;
892 }