2 * MAPI Utility functions
4 * Copyright 2004 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mapi
);
43 static const BYTE digitsToHex
[] = {
44 0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15,
45 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
46 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,
49 /**************************************************************************
50 * ScInitMapiUtil (MAPI32.33)
52 * Initialise Mapi utility functions.
55 * ulReserved [I] Reserved, pass 0.
58 * Success: S_OK. Mapi utility functions may be called.
59 * Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
62 * Your application does not need to call this function unless it does not
63 * call MAPIInitialize()/MAPIUninitialize().
65 SCODE WINAPI
ScInitMapiUtil(ULONG ulReserved
)
67 FIXME("(0x%08x)stub!\n", ulReserved
);
69 return MAPI_E_INVALID_PARAMETER
;
73 /**************************************************************************
74 * DeinitMapiUtil (MAPI32.34)
76 * Uninitialise Mapi utility functions.
85 * Your application does not need to call this function unless it does not
86 * call MAPIInitialize()/MAPIUninitialize().
88 VOID WINAPI
DeinitMapiUtil(void)
93 typedef LPVOID
*LPMAPIALLOCBUFFER
;
95 /**************************************************************************
96 * MAPIAllocateBuffer (MAPI32.12)
97 * MAPIAllocateBuffer@8 (MAPI32.13)
99 * Allocate a block of memory.
102 * cbSize [I] Size of the block to allocate in bytes
103 * lppBuffer [O] Destination for pointer to allocated memory
106 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
107 * length cbSize bytes.
108 * Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
109 * MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
112 * Memory allocated with this function should be freed with MAPIFreeBuffer().
113 * Further allocations of memory may be linked to the pointer returned using
114 * MAPIAllocateMore(). Linked allocations are freed when the initial pointer
117 SCODE WINAPI
MAPIAllocateBuffer(ULONG cbSize
, LPVOID
*lppBuffer
)
119 LPMAPIALLOCBUFFER lpBuff
;
121 TRACE("(%d,%p)\n", cbSize
, lppBuffer
);
126 lpBuff
= HeapAlloc(GetProcessHeap(), 0, cbSize
+ sizeof(*lpBuff
));
128 return MAPI_E_NOT_ENOUGH_MEMORY
;
130 TRACE("initial allocation:%p, returning %p\n", lpBuff
, lpBuff
+ 1);
136 /**************************************************************************
137 * MAPIAllocateMore (MAPI32.14)
138 * MAPIAllocateMore@12 (MAPI32.15)
140 * Allocate a block of memory linked to a previous allocation.
143 * cbSize [I] Size of the block to allocate in bytes
144 * lpOrig [I] Initial allocation to link to, from MAPIAllocateBuffer()
145 * lppBuffer [O] Destination for pointer to allocated memory
148 * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
149 * length cbSize bytes.
150 * Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
151 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
154 * Memory allocated with this function and stored in *lppBuffer is freed
155 * when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
157 SCODE WINAPI
MAPIAllocateMore(ULONG cbSize
, LPVOID lpOrig
, LPVOID
*lppBuffer
)
159 LPMAPIALLOCBUFFER lpBuff
= lpOrig
;
161 TRACE("(%d,%p,%p)\n", cbSize
, lpOrig
, lppBuffer
);
163 if (!lppBuffer
|| !lpBuff
|| !--lpBuff
)
166 /* Find the last allocation in the chain */
169 TRACE("linked:%p->%p\n", lpBuff
, *lpBuff
);
173 if (SUCCEEDED(MAPIAllocateBuffer(cbSize
, lppBuffer
)))
175 *lpBuff
= ((LPMAPIALLOCBUFFER
)*lppBuffer
) - 1;
176 TRACE("linking %p->%p\n", lpBuff
, *lpBuff
);
178 return *lppBuffer
? S_OK
: MAPI_E_NOT_ENOUGH_MEMORY
;
181 /**************************************************************************
182 * MAPIFreeBuffer (MAPI32.16)
183 * MAPIFreeBuffer@4 (MAPI32.17)
185 * Free a block of memory and any linked allocations associated with it.
188 * lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
193 ULONG WINAPI
MAPIFreeBuffer(LPVOID lpBuffer
)
195 LPMAPIALLOCBUFFER lpBuff
= lpBuffer
;
197 TRACE("(%p)\n", lpBuffer
);
199 if (lpBuff
&& --lpBuff
)
203 LPVOID lpFree
= lpBuff
;
207 TRACE("linked:%p->%p, freeing %p\n", lpFree
, lpBuff
, lpFree
);
208 HeapFree(GetProcessHeap(), 0, lpFree
);
214 /**************************************************************************
215 * WrapProgress@20 (MAPI32.41)
217 HRESULT WINAPI
WrapProgress(PVOID unk1
, PVOID unk2
, PVOID unk3
, PVOID unk4
, PVOID unk5
)
219 /* Native does not implement this function */
220 return MAPI_E_NO_SUPPORT
;
223 /*************************************************************************
224 * HrThisThreadAdviseSink@8 (MAPI32.42)
226 * Ensure that an advise sink is only notified in its originating thread.
229 * lpSink [I] IMAPIAdviseSink interface to be protected
230 * lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
233 * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
234 * Failure: E_INVALIDARG, if any parameter is invalid.
236 HRESULT WINAPI
HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink
, LPMAPIADVISESINK
* lppNewSink
)
238 FIXME("(%p,%p)semi-stub\n", lpSink
, lppNewSink
);
240 if (!lpSink
|| !lppNewSink
)
243 /* Don't wrap the sink for now, just copy it */
244 *lppNewSink
= lpSink
;
245 IMAPIAdviseSink_AddRef(lpSink
);
249 /*************************************************************************
250 * FBinFromHex (MAPI32.44)
252 * Create an array of binary data from a string.
255 * lpszHex [I] String to convert to binary data
256 * lpOut [O] Destination for resulting binary data
259 * Success: TRUE. lpOut contains the decoded binary data.
260 * Failure: FALSE, if lpszHex does not represent a binary string.
263 * - lpOut must be at least half the length of lpszHex in bytes.
264 * - Although the Mapi headers prototype this function as both
265 * Ascii and Unicode, there is only one (Ascii) implementation. This
266 * means that lpszHex is treated as an Ascii string (i.e. a single NUL
267 * character in the byte stream terminates the string).
269 BOOL WINAPI
FBinFromHex(LPWSTR lpszHex
, LPBYTE lpOut
)
271 LPSTR lpStr
= (LPSTR
)lpszHex
;
273 TRACE("(%p,%p)\n", lpszHex
, lpOut
);
277 if (lpStr
[0] < '0' || lpStr
[0] > 'f' || digitsToHex
[lpStr
[0] - '0'] == 0xff ||
278 lpStr
[1] < '0' || lpStr
[1] > 'f' || digitsToHex
[lpStr
[1] - '0'] == 0xff)
281 *lpOut
++ = (digitsToHex
[lpStr
[0] - '0'] << 4) | digitsToHex
[lpStr
[1] - '0'];
287 /*************************************************************************
288 * HexFromBin (MAPI32.45)
290 * Create a string from an array of binary data.
293 * lpHex [I] Binary data to convert to string
294 * iCount [I] Length of lpHex in bytes
295 * lpszOut [O] Destination for resulting hex string
301 * - lpszOut must be at least 2 * iCount + 1 bytes characters long.
302 * - Although the Mapi headers prototype this function as both
303 * Ascii and Unicode, there is only one (Ascii) implementation. This
304 * means that the resulting string is not properly NUL terminated
305 * if the caller expects it to be a Unicode string.
307 void WINAPI
HexFromBin(LPBYTE lpHex
, int iCount
, LPWSTR lpszOut
)
309 static const char hexDigits
[] = { "0123456789ABCDEF" };
310 LPSTR lpStr
= (LPSTR
)lpszOut
;
312 TRACE("(%p,%d,%p)\n", lpHex
, iCount
, lpszOut
);
316 *lpStr
++ = hexDigits
[*lpHex
>> 4];
317 *lpStr
++ = hexDigits
[*lpHex
& 0xf];
323 /*************************************************************************
324 * SwapPlong@8 (MAPI32.47)
326 * Swap the bytes in a ULONG array.
329 * lpData [O] Array to swap bytes in
330 * ulLen [I] Number of ULONG element to swap the bytes of
335 VOID WINAPI
SwapPlong(PULONG lpData
, ULONG ulLen
)
339 for (i
= 0; i
< ulLen
; i
++)
340 lpData
[i
] = RtlUlongByteSwap(lpData
[i
]);
343 /*************************************************************************
344 * SwapPword@8 (MAPI32.48)
346 * Swap the bytes in a USHORT array.
349 * lpData [O] Array to swap bytes in
350 * ulLen [I] Number of USHORT element to swap the bytes of
355 VOID WINAPI
SwapPword(PUSHORT lpData
, ULONG ulLen
)
359 for (i
= 0; i
< ulLen
; i
++)
360 lpData
[i
] = RtlUshortByteSwap(lpData
[i
]);
363 /**************************************************************************
364 * MNLS_lstrlenW@4 (MAPI32.62)
366 * Calculate the length of a Unicode string.
369 * lpszStr [I] String to calculate the length of
372 * The length of lpszStr in Unicode characters.
374 ULONG WINAPI
MNLS_lstrlenW(LPCWSTR lpszStr
)
376 TRACE("(%s)\n", debugstr_w(lpszStr
));
377 return strlenW(lpszStr
);
380 /*************************************************************************
381 * MNLS_lstrcmpW@8 (MAPI32.63)
383 * Compare two Unicode strings.
386 * lpszLeft [I] First string to compare
387 * lpszRight [I] Second string to compare
390 * An integer less than, equal to or greater than 0, indicating that
391 * lpszLeft is less than, the same, or greater than lpszRight.
393 INT WINAPI
MNLS_lstrcmpW(LPCWSTR lpszLeft
, LPCWSTR lpszRight
)
395 TRACE("(%s,%s)\n", debugstr_w(lpszLeft
), debugstr_w(lpszRight
));
396 return strcmpW(lpszLeft
, lpszRight
);
399 /*************************************************************************
400 * MNLS_lstrcpyW@8 (MAPI32.64)
402 * Copy a Unicode string to another string.
405 * lpszDest [O] Destination string
406 * lpszSrc [I] Source string
409 * The length lpszDest in Unicode characters.
411 ULONG WINAPI
MNLS_lstrcpyW(LPWSTR lpszDest
, LPCWSTR lpszSrc
)
415 TRACE("(%p,%s)\n", lpszDest
, debugstr_w(lpszSrc
));
416 len
= (strlenW(lpszSrc
) + 1) * sizeof(WCHAR
);
417 memcpy(lpszDest
, lpszSrc
, len
);
421 /*************************************************************************
422 * MNLS_CompareStringW@12 (MAPI32.65)
424 * Compare two Unicode strings.
427 * dwCp [I] Code page for the comparison
428 * lpszLeft [I] First string to compare
429 * lpszRight [I] Second string to compare
432 * CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
433 * lpszLeft is less than, the same, or greater than lpszRight.
435 INT WINAPI
MNLS_CompareStringW(DWORD dwCp
, LPCWSTR lpszLeft
, LPCWSTR lpszRight
)
439 TRACE("0x%08x,%s,%s\n", dwCp
, debugstr_w(lpszLeft
), debugstr_w(lpszRight
));
440 ret
= MNLS_lstrcmpW(lpszLeft
, lpszRight
);
441 return ret
< 0 ? CSTR_LESS_THAN
: ret
? CSTR_GREATER_THAN
: CSTR_EQUAL
;
444 /**************************************************************************
445 * FEqualNames@8 (MAPI32.72)
447 * Compare two Mapi names.
450 * lpName1 [I] First name to compare to lpName2
451 * lpName2 [I] Second name to compare to lpName1
454 * TRUE, if the names are the same,
457 BOOL WINAPI
FEqualNames(LPMAPINAMEID lpName1
, LPMAPINAMEID lpName2
)
459 TRACE("(%p,%p)\n", lpName1
, lpName2
);
461 if (!lpName1
|| !lpName2
||
462 !IsEqualGUID(lpName1
->lpguid
, lpName2
->lpguid
) ||
463 lpName1
->ulKind
!= lpName2
->ulKind
)
466 if (lpName1
->ulKind
== MNID_STRING
)
467 return !strcmpW(lpName1
->Kind
.lpwstrName
, lpName2
->Kind
.lpwstrName
);
469 return lpName1
->Kind
.lID
== lpName2
->Kind
.lID
? TRUE
: FALSE
;
472 /**************************************************************************
473 * IsBadBoundedStringPtr@8 (MAPI32.71)
475 * Determine if a string pointer is valid.
478 * lpszStr [I] String to check
479 * ulLen [I] Maximum length of lpszStr
482 * TRUE, if lpszStr is invalid or longer than ulLen,
485 BOOL WINAPI
IsBadBoundedStringPtr(LPCSTR lpszStr
, ULONG ulLen
)
487 if (!lpszStr
|| IsBadStringPtrA(lpszStr
, -1) || strlen(lpszStr
) >= ulLen
)
492 /**************************************************************************
493 * FtAddFt@16 (MAPI32.121)
495 * Add two FILETIME's together.
498 * ftLeft [I] FILETIME to add to ftRight
499 * ftRight [I] FILETIME to add to ftLeft
502 * The sum of ftLeft and ftRight
504 LONGLONG WINAPI
MAPI32_FtAddFt(FILETIME ftLeft
, FILETIME ftRight
)
506 LONGLONG
*pl
= (LONGLONG
*)&ftLeft
, *pr
= (LONGLONG
*)&ftRight
;
511 /**************************************************************************
512 * FtSubFt@16 (MAPI32.123)
514 * Subtract two FILETIME's together.
517 * ftLeft [I] Initial FILETIME
518 * ftRight [I] FILETIME to subtract from ftLeft
521 * The remainder after ftRight is subtracted from ftLeft.
523 LONGLONG WINAPI
MAPI32_FtSubFt(FILETIME ftLeft
, FILETIME ftRight
)
525 LONGLONG
*pl
= (LONGLONG
*)&ftLeft
, *pr
= (LONGLONG
*)&ftRight
;
530 /**************************************************************************
531 * FtMulDw@12 (MAPI32.124)
533 * Multiply a FILETIME by a DWORD.
536 * dwLeft [I] DWORD to multiply with ftRight
537 * ftRight [I] FILETIME to multiply with dwLeft
540 * The product of dwLeft and ftRight
542 LONGLONG WINAPI
MAPI32_FtMulDw(DWORD dwLeft
, FILETIME ftRight
)
544 LONGLONG
*pr
= (LONGLONG
*)&ftRight
;
546 return (LONGLONG
)dwLeft
* (*pr
);
549 /**************************************************************************
550 * FtMulDwDw@8 (MAPI32.125)
552 * Multiply two DWORD, giving the result as a FILETIME.
555 * dwLeft [I] DWORD to multiply with dwRight
556 * dwRight [I] DWORD to multiply with dwLeft
559 * The product of ftMultiplier and ftMultiplicand as a FILETIME.
561 LONGLONG WINAPI
MAPI32_FtMulDwDw(DWORD dwLeft
, DWORD dwRight
)
563 return (LONGLONG
)dwLeft
* (LONGLONG
)dwRight
;
566 /**************************************************************************
567 * FtNegFt@8 (MAPI32.126)
572 * ft [I] FILETIME to negate
575 * The negation of ft.
577 LONGLONG WINAPI
MAPI32_FtNegFt(FILETIME ft
)
579 LONGLONG
*p
= (LONGLONG
*)&ft
;
584 /**************************************************************************
585 * UlAddRef@4 (MAPI32.128)
587 * Add a reference to an object.
590 * lpUnk [I] Object to add a reference to.
593 * The new reference count of the object, or 0 if lpUnk is NULL.
596 * See IUnknown_AddRef.
598 ULONG WINAPI
UlAddRef(void *lpUnk
)
600 TRACE("(%p)\n", lpUnk
);
604 return IUnknown_AddRef((LPUNKNOWN
)lpUnk
);
607 /**************************************************************************
608 * UlRelease@4 (MAPI32.129)
610 * Remove a reference from an object.
613 * lpUnk [I] Object to remove reference from.
616 * The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
617 * non-NULL and this function returns 0, the object pointed to by lpUnk has
621 * See IUnknown_Release.
623 ULONG WINAPI
UlRelease(void *lpUnk
)
625 TRACE("(%p)\n", lpUnk
);
629 return IUnknown_Release((LPUNKNOWN
)lpUnk
);
632 /**************************************************************************
633 * UFromSz@4 (MAPI32.133)
635 * Read an integer from a string
638 * lpszStr [I] String to read the integer from.
641 * Success: The integer read from lpszStr.
642 * Failure: 0, if the first character in lpszStr is not 0-9.
645 * This function does not accept whitespace and stops at the first non-digit
648 UINT WINAPI
UFromSz(LPCSTR lpszStr
)
652 TRACE("(%s)\n", debugstr_a(lpszStr
));
656 while (*lpszStr
>= '0' && *lpszStr
<= '9')
658 ulRet
= ulRet
* 10 + (*lpszStr
- '0');
665 /*************************************************************************
666 * OpenStreamOnFile@24 (MAPI32.147)
668 * Create a stream on a file.
671 * lpAlloc [I] Memory allocation function
672 * lpFree [I] Memory free function
673 * ulFlags [I] Flags controlling the opening process
674 * lpszPath [I] Path of file to create stream on
675 * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
676 * lppStream [O] Destination for created stream
679 * Success: S_OK. lppStream contains the new stream object
680 * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
681 * describing the error.
683 HRESULT WINAPI
OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc
, LPFREEBUFFER lpFree
,
684 ULONG ulFlags
, LPWSTR lpszPath
, LPWSTR lpszPrefix
,
687 WCHAR szBuff
[MAX_PATH
];
688 DWORD dwMode
= STGM_READWRITE
, dwAttributes
= 0;
691 TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc
, lpFree
, ulFlags
,
692 debugstr_a((LPSTR
)lpszPath
), debugstr_a((LPSTR
)lpszPrefix
), lppStream
);
697 if (ulFlags
& SOF_UNIQUEFILENAME
)
699 FIXME("Should generate a temporary name\n");
703 if (!lpszPath
|| !lppStream
)
706 /* FIXME: Should probably munge mode and attributes, and should handle
707 * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
708 * we are being passed Unicode strings; MSDN doesn't say).
709 * This implementation is just enough for Outlook97 to start.
711 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)lpszPath
, -1, szBuff
, MAX_PATH
);
712 hRet
= SHCreateStreamOnFileEx(szBuff
, dwMode
, dwAttributes
, TRUE
,
717 /*************************************************************************
718 * UlFromSzHex@4 (MAPI32.155)
720 * Read an integer from a hexadecimal string.
723 * lpSzHex [I] String containing the hexadecimal number to read
726 * Success: The number represented by lpszHex.
727 * Failure: 0, if lpszHex does not contain a hex string.
730 * This function does not accept whitespace and stops at the first non-hex
733 ULONG WINAPI
UlFromSzHex(LPCWSTR lpszHex
)
735 LPCSTR lpStr
= (LPCSTR
)lpszHex
;
738 TRACE("(%s)\n", debugstr_a(lpStr
));
742 if (lpStr
[0] < '0' || lpStr
[0] > 'f' || digitsToHex
[lpStr
[0] - '0'] == 0xff ||
743 lpStr
[1] < '0' || lpStr
[1] > 'f' || digitsToHex
[lpStr
[1] - '0'] == 0xff)
746 ulRet
= ulRet
* 16 + ((digitsToHex
[lpStr
[0] - '0'] << 4) | digitsToHex
[lpStr
[1] - '0']);
752 /************************************************************************
753 * FBadEntryList@4 (MAPI32.190)
755 * Determine is an entry list is invalid.
758 * lpEntryList [I] List to check
761 * TRUE, if lpEntryList is invalid,
764 BOOL WINAPI
FBadEntryList(LPENTRYLIST lpEntryList
)
768 if (IsBadReadPtr(lpEntryList
, sizeof(*lpEntryList
)) ||
769 IsBadReadPtr(lpEntryList
->lpbin
,
770 lpEntryList
->cValues
* sizeof(*lpEntryList
->lpbin
)))
773 for (i
= 0; i
< lpEntryList
->cValues
; i
++)
774 if(IsBadReadPtr(lpEntryList
->lpbin
[i
].lpb
, lpEntryList
->lpbin
[i
].cb
))
780 /*************************************************************************
781 * CbOfEncoded@4 (MAPI32.207)
783 * Return the length of an encoded string.
786 * lpSzEnc [I] Encoded string to get the length of.
789 * The length of the encoded string in bytes.
791 ULONG WINAPI
CbOfEncoded(LPCSTR lpszEnc
)
795 TRACE("(%s)\n", debugstr_a(lpszEnc
));
798 ulRet
= (((strlen(lpszEnc
) | 3) >> 2) + 1) * 3;
802 /*************************************************************************
803 * cmc_query_configuration (MAPI32.235)
805 * Retrieves the configuration information for the installed CMC
808 * session [I] MAPI session handle
809 * item [I] Enumerated variable that identifies which
810 * configuration information is being requested
811 * reference [O] Buffer where configuration information is written
812 * config_extensions[I/O] Path of file to create stream on
817 CMC_return_code WINAPI
cmc_query_configuration(
818 CMC_session_id session
,
820 CMC_buffer reference
,
821 CMC_extension
*config_extensions
)
824 return CMC_E_NOT_SUPPORTED
;
827 /**************************************************************************
828 * FGetComponentPath (MAPI32.254)
829 * FGetComponentPath@20 (MAPI32.255)
831 * Return the installed component path, usually to the private mapi32.dll.
834 * component [I] Component ID
835 * qualifier [I] Application LCID
836 * dll_path [O] returned component path
837 * dll_path_length [I] component path length
838 * install [I] install mode
845 * Previously documented in Q229700 "How to locate the correct path
846 * to the Mapisvc.inf file in Microsoft Outlook".
848 BOOL WINAPI
FGetComponentPath(LPCSTR component
, LPCSTR qualifier
, LPSTR dll_path
,
849 DWORD dll_path_length
, BOOL install
)
854 TRACE("%s %s %p %u %d\n", component
, qualifier
, dll_path
, dll_path_length
, install
);
858 hmsi
= LoadLibraryA("msi.dll");
861 FARPROC pMsiProvideQualifiedComponentA
= GetProcAddress(hmsi
, "MsiProvideQualifiedComponentA");
863 if (pMsiProvideQualifiedComponentA
)
865 static const char * const fmt
[] = { "%d\\NT", "%d\\95", "%d" };
869 for (i
= 0; i
< sizeof(fmt
)/sizeof(fmt
[0]); i
++)
871 /* FIXME: what's the correct behaviour here? */
872 if (!qualifier
|| qualifier
== lcid_ver
)
874 sprintf(lcid_ver
, fmt
[i
], GetUserDefaultUILanguage());
875 qualifier
= lcid_ver
;
878 if (pMsiProvideQualifiedComponentA(component
, qualifier
,
879 install
? INSTALLMODE_DEFAULT
: INSTALLMODE_EXISTING
,
880 dll_path
, &dll_path_length
) == ERROR_SUCCESS
)
886 if (qualifier
!= lcid_ver
) break;
894 /**************************************************************************
895 * HrQueryAllRows (MAPI32.75)
897 HRESULT WINAPI
HrQueryAllRows(LPMAPITABLE lpTable
, LPSPropTagArray lpPropTags
,
898 LPSRestriction lpRestriction
, LPSSortOrderSet lpSortOrderSet
,
899 LONG crowsMax
, LPSRowSet
*lppRows
)
901 FIXME("(%p, %p, %p, %p, %d, %p): stub\n", lpTable
, lpPropTags
, lpRestriction
, lpSortOrderSet
, crowsMax
, lppRows
);
903 return MAPI_E_CALL_FAILED
;