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