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