fdb8497d677cb56542bf98f60ac384b4ed5fbc8d
[reactos.git] / reactos / dll / win32 / mapi32 / util.c
1 /*
2 * MAPI Utility functions
3 *
4 * Copyright 2004 Jon Griffiths
5 * Copyright 2009 Owen Rudge for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <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 goto cleanUp;
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 mapiFunctions.DllGetClassObject = (void*) GetProcAddress(mapi_ex_provider, "DllGetClassObject");
1061 }
1062
1063 cleanUp:
1064 RegCloseKey(hkeyMail);
1065 HeapFree(GetProcessHeap(), 0, appKey);
1066 HeapFree(GetProcessHeap(), 0, appName);
1067 }
1068
1069 /**************************************************************************
1070 * unload_mapi_providers
1071 *
1072 * Unloads any loaded MAPI libraries.
1073 */
1074 void unload_mapi_providers(void)
1075 {
1076 TRACE("()\n");
1077
1078 FreeLibrary(mapi_provider);
1079 FreeLibrary(mapi_ex_provider);
1080 }