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