| /* |
| * MAPI Utility functions |
| * |
| * Copyright 2004 Jon Griffiths |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <stdarg.h> |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winreg.h" |
| #include "winerror.h" |
| #include "winternl.h" |
| #include "objbase.h" |
| #include "shlwapi.h" |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| #include "mapival.h" |
| #include "xcmc.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(mapi); |
| |
| /************************************************************************** |
| * ScInitMapiUtil (MAPI32.33) |
| * |
| * Initialise Mapi utility functions. |
| * |
| * PARAMS |
| * ulReserved [I] Reserved, pass 0. |
| * |
| * RETURNS |
| * Success: S_OK. Mapi utility functions may be called. |
| * Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0. |
| * |
| * NOTES |
| * Your application does not need to call this function unless it does not |
| * call MAPIInitialize()/MAPIUninitialize(). |
| */ |
| SCODE WINAPI ScInitMapiUtil(ULONG ulReserved) |
| { |
| FIXME("(0x%08lx)stub!\n", ulReserved); |
| if (ulReserved) |
| return MAPI_E_INVALID_PARAMETER; |
| return S_OK; |
| } |
| |
| /************************************************************************** |
| * DeinitMapiUtil (MAPI32.34) |
| * |
| * Uninitialise Mapi utility functions. |
| * |
| * PARAMS |
| * None. |
| * |
| * RETURNS |
| * Nothing. |
| * |
| * NOTES |
| * Your application does not need to call this function unless it does not |
| * call MAPIInitialize()/MAPIUninitialize(). |
| */ |
| VOID WINAPI DeinitMapiUtil(void) |
| { |
| FIXME("()stub!\n"); |
| } |
| |
| typedef LPVOID *LPMAPIALLOCBUFFER; |
| |
| /************************************************************************** |
| * MAPIAllocateBuffer (MAPI32.12) |
| * MAPIAllocateBuffer@8 (MAPI32.13) |
| * |
| * Allocate a block of memory. |
| * |
| * PARAMS |
| * cbSize [I] Size of the block to allocate in bytes |
| * lppBuffer [O] Destination for pointer to allocated memory |
| * |
| * RETURNS |
| * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of |
| * length cbSize bytes. |
| * Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL. |
| * MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails. |
| * |
| * NOTES |
| * Memory allocated with this function should be freed with MAPIFreeBuffer(). |
| * Further allocations of memory may be linked to the pointer returned using |
| * MAPIAllocateMore(). Linked allocations are freed when the initial pointer |
| * is feed. |
| */ |
| SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer) |
| { |
| LPMAPIALLOCBUFFER lpBuff; |
| |
| TRACE("(%ld,%p)\n", cbSize, lppBuffer); |
| |
| if (!lppBuffer) |
| return E_INVALIDARG; |
| |
| lpBuff = (LPMAPIALLOCBUFFER)HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff)); |
| if (!lpBuff) |
| return MAPI_E_NOT_ENOUGH_MEMORY; |
| |
| TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1); |
| *lpBuff++ = NULL; |
| *lppBuffer = lpBuff; |
| return S_OK; |
| } |
| |
| /************************************************************************** |
| * MAPIAllocateMore (MAPI32.14) |
| * MAPIAllocateMore@12 (MAPI32.15) |
| * |
| * Allocate a block of memory linked to a previous allocation. |
| * |
| * PARAMS |
| * cbSize [I] Size of the block to allocate in bytes |
| * lpOrig [I] Initial allocation to link to, from MAPIAllocateBuffer() |
| * lppBuffer [O] Destination for pointer to allocated memory |
| * |
| * RETURNS |
| * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of |
| * length cbSize bytes. |
| * Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid. |
| * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails. |
| * |
| * NOTES |
| * Memory allocated with this function and stored in *lppBuffer is freed |
| * when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently. |
| */ |
| SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer) |
| { |
| LPMAPIALLOCBUFFER lpBuff = lpOrig; |
| |
| TRACE("(%ld,%p,%p)\n", cbSize, lpOrig, lppBuffer); |
| |
| if (!lppBuffer || !lpBuff || !--lpBuff) |
| return E_INVALIDARG; |
| |
| /* Find the last allocation in the chain */ |
| while (*lpBuff) |
| { |
| TRACE("linked:%p->%p\n", lpBuff, *lpBuff); |
| lpBuff = *lpBuff; |
| } |
| |
| if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer))) |
| { |
| *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1; |
| TRACE("linking %p->%p\n", lpBuff, *lpBuff); |
| } |
| return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY; |
| } |
| |
| /************************************************************************** |
| * MAPIFreeBuffer (MAPI32.16) |
| * MAPIFreeBuffer@4 (MAPI32.17) |
| * |
| * Free a block of memory and any linked allocations associated with it. |
| * |
| * PARAMS |
| * lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer() |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer) |
| { |
| LPMAPIALLOCBUFFER lpBuff = lpBuffer; |
| |
| TRACE("(%p)\n", lpBuffer); |
| |
| if (lpBuff && --lpBuff) |
| { |
| while (lpBuff) |
| { |
| LPVOID lpFree = lpBuff; |
| |
| lpBuff = *lpBuff; |
| |
| TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree); |
| HeapFree(GetProcessHeap(), 0, lpFree); |
| } |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * HrThisThreadAdviseSink@8 (MAPI32.42) |
| * |
| * Ensure that an advise sink is only notified in its originating thread. |
| * |
| * PARAMS |
| * lpSink [I] IMAPIAdviseSink interface to be protected |
| * lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface |
| * |
| * RETURNS |
| * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink. |
| * Failure: E_INVALIDARG, if any parameter is invalid. |
| */ |
| HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink) |
| { |
| FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink); |
| |
| if (!lpSink || !lppNewSink) |
| return E_INVALIDARG; |
| |
| /* Don't wrap the sink for now, just copy it */ |
| *lppNewSink = lpSink; |
| IMAPIAdviseSink_AddRef(lpSink); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * FBinFromHex (MAPI32.44) |
| * |
| * Create an array of binary data from a string. |
| * |
| * PARAMS |
| * lpszHex [I] String to convert to binary data |
| * lpOut [O] Destination for resulting binary data |
| * |
| * RETURNS |
| * Success: TRUE. lpOut contains the decoded binary data. |
| * Failure: FALSE, if lpszHex does not represent a binary string. |
| * |
| * NOTES |
| * - lpOut must be at least half the length of lpszHex in bytes. |
| * - Although the Mapi headers prototype this function as both |
| * Ascii and Unicode, there is only one (Ascii) implementation. This |
| * means that lpszHex is treated as an Ascii string (i.e. a single NUL |
| * character in the byte stream terminates the string). |
| */ |
| BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut) |
| { |
| static const BYTE digitsToHex[] = { |
| 0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15, |
| 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, |
| 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13, |
| 14,15 }; |
| LPSTR lpStr = (LPSTR)lpszHex; |
| |
| TRACE("(%p,%p)\n", lpszHex, lpOut); |
| |
| while (*lpStr) |
| { |
| if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff || |
| lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff) |
| return FALSE; |
| |
| *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']; |
| lpStr += 2; |
| } |
| return TRUE; |
| } |
| |
| /************************************************************************* |
| * HexFromBin (MAPI32.45) |
| * |
| * Create a string from an array of binary data. |
| * |
| * PARAMS |
| * lpHex [I] Binary data to convert to string |
| * iCount [I] Length of lpHex in bytes |
| * lpszOut [O] Destination for resulting hex string |
| * |
| * RETURNS |
| * Nothing. |
| * |
| * NOTES |
| * - lpszOut must be at least 2 * iCount + 1 bytes characters long. |
| * - Although the Mapi headers prototype this function as both |
| * Ascii and Unicode, there is only one (Ascii) implementation. This |
| * means that the resulting string is not properly NUL terminated |
| * if the caller expects it to be a Unicode string. |
| */ |
| void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut) |
| { |
| static const char hexDigits[] = { "0123456789ABCDEF" }; |
| LPSTR lpStr = (LPSTR)lpszOut; |
| |
| TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut); |
| |
| while (iCount-- > 0) |
| { |
| *lpStr++ = hexDigits[*lpHex >> 4]; |
| *lpStr++ = hexDigits[*lpHex & 0xf]; |
| lpHex++; |
| } |
| *lpStr = '\0'; |
| } |
| |
| /************************************************************************* |
| * SwapPlong@8 (MAPI32.47) |
| * |
| * Swap the bytes in a ULONG array. |
| * |
| * PARAMS |
| * lpData [O] Array to swap bytes in |
| * ulLen [I] Number of ULONG element to swap the bytes of |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen) |
| { |
| ULONG i; |
| |
| for (i = 0; i < ulLen; i++) |
| lpData[i] = RtlUlongByteSwap(lpData[i]); |
| } |
| |
| /************************************************************************* |
| * SwapPword@8 (MAPI32.48) |
| * |
| * Swap the bytes in a USHORT array. |
| * |
| * PARAMS |
| * lpData [O] Array to swap bytes in |
| * ulLen [I] Number of USHORT element to swap the bytes of |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen) |
| { |
| ULONG i; |
| |
| for (i = 0; i < ulLen; i++) |
| lpData[i] = RtlUshortByteSwap(lpData[i]); |
| } |
| |
| /************************************************************************** |
| * MNLS_lstrlenW@4 (MAPI32.62) |
| * |
| * Calculate the length of a Unicode string. |
| * |
| * PARAMS |
| * lpszStr [I] String to calculate the length of |
| * |
| * RETURNS |
| * The length of lpszStr in Unicode characters. |
| */ |
| ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr) |
| { |
| TRACE("(%s)\n", debugstr_w(lpszStr)); |
| return strlenW(lpszStr); |
| } |
| |
| /************************************************************************* |
| * MNLS_lstrcmpW@8 (MAPI32.63) |
| * |
| * Compare two Unicode strings. |
| * |
| * PARAMS |
| * lpszLeft [I] First string to compare |
| * lpszRight [I] Second string to compare |
| * |
| * RETURNS |
| * An integer less than, equal to or greater than 0, indicating that |
| * lpszLeft is less than, the same, or greater than lpszRight. |
| */ |
| INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight) |
| { |
| TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight)); |
| return strcmpW(lpszLeft, lpszRight); |
| } |
| |
| /************************************************************************* |
| * MNLS_lstrcpyW@8 (MAPI32.64) |
| * |
| * Copy a Unicode string to another string. |
| * |
| * PARAMS |
| * lpszDest [O] Destination string |
| * lpszSrc [I] Source string |
| * |
| * RETURNS |
| * The length lpszDest in Unicode characters. |
| */ |
| ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc) |
| { |
| ULONG len; |
| |
| TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc)); |
| len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR); |
| memcpy(lpszDest, lpszSrc, len); |
| return len; |
| } |
| |
| /************************************************************************* |
| * MNLS_CompareStringW@12 (MAPI32.65) |
| * |
| * Compare two Unicode strings. |
| * |
| * PARAMS |
| * dwCp [I] Code page for the comparison |
| * lpszLeft [I] First string to compare |
| * lpszRight [I] Second string to compare |
| * |
| * RETURNS |
| * CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that |
| * lpszLeft is less than, the same, or greater than lpszRight. |
| */ |
| INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight) |
| { |
| INT ret; |
| |
| TRACE("0x%08lx,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight)); |
| ret = MNLS_lstrcmpW(lpszLeft, lpszRight); |
| return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL; |
| } |
| |
| /************************************************************************** |
| * FEqualNames@8 (MAPI32.72) |
| * |
| * Compare two Mapi names. |
| * |
| * PARAMS |
| * lpName1 [I] First name to compare to lpName2 |
| * lpName2 [I] Second name to compare to lpName1 |
| * |
| * RETURNS |
| * TRUE, if the names are the same, |
| * FALSE, Otherwise. |
| */ |
| BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2) |
| { |
| TRACE("(%p,%p)\n", lpName1, lpName2); |
| |
| if (!lpName1 || !lpName2 || |
| !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) || |
| lpName1->ulKind != lpName2->ulKind) |
| return FALSE; |
| |
| if (lpName1->ulKind == MNID_STRING) |
| return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName); |
| |
| return lpName1->Kind.lID == lpName2->Kind.lID ? TRUE : FALSE; |
| } |
| |
| /************************************************************************** |
| * FtAddFt@16 (MAPI32.121) |
| * |
| * Add two FILETIME's together. |
| * |
| * PARAMS |
| * ftLeft [I] FILETIME to add to ftRight |
| * ftRight [I] FILETIME to add to ftLeft |
| * |
| * RETURNS |
| * The sum of ftLeft and ftRight |
| */ |
| LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight) |
| { |
| LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; |
| |
| return *pl + *pr; |
| } |
| |
| /************************************************************************** |
| * FtSubFt@16 (MAPI32.123) |
| * |
| * Subtract two FILETIME's together. |
| * |
| * PARAMS |
| * ftLeft [I] Initial FILETIME |
| * ftRight [I] FILETIME to subtract from ftLeft |
| * |
| * RETURNS |
| * The remainder after ftRight is subtracted from ftLeft. |
| */ |
| LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight) |
| { |
| LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; |
| |
| return *pr - *pl; |
| } |
| |
| /************************************************************************** |
| * FtMulDw@12 (MAPI32.124) |
| * |
| * Multiply a FILETIME by a DWORD. |
| * |
| * PARAMS |
| * dwLeft [I] DWORD to multiply with ftRight |
| * ftRight [I] FILETIME to multiply with dwLeft |
| * |
| * RETURNS |
| * The product of dwLeft and ftRight |
| */ |
| LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight) |
| { |
| LONGLONG *pr = (LONGLONG*)&ftRight; |
| |
| return (LONGLONG)dwLeft * (*pr); |
| } |
| |
| /************************************************************************** |
| * FtMulDwDw@8 (MAPI32.125) |
| * |
| * Multiply two DWORD, giving the result as a FILETIME. |
| * |
| * PARAMS |
| * dwLeft [I] DWORD to multiply with dwRight |
| * dwRight [I] DWORD to multiply with dwLeft |
| * |
| * RETURNS |
| * The product of ftMultiplier and ftMultiplicand as a FILETIME. |
| */ |
| LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight) |
| { |
| return (LONGLONG)dwLeft * (LONGLONG)dwRight; |
| } |
| |
| /************************************************************************** |
| * FtNegFt@8 (MAPI32.126) |
| * |
| * Negate a FILETIME. |
| * |
| * PARAMS |
| * ft [I] FILETIME to negate |
| * |
| * RETURNS |
| * The negation of ft. |
| */ |
| LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft) |
| { |
| LONGLONG *p = (LONGLONG*)&ft; |
| |
| return - *p; |
| } |
| |
| /************************************************************************** |
| * UlAddRef@4 (MAPI32.128) |
| * |
| * Add a reference to an object. |
| * |
| * PARAMS |
| * lpUnk [I] Object to add a reference to. |
| * |
| * RETURNS |
| * The new reference count of the object, or 0 if lpUnk is NULL. |
| * |
| * NOTES |
| * See IUnknown_AddRef. |
| */ |
| ULONG WINAPI UlAddRef(void *lpUnk) |
| { |
| TRACE("(%p)\n", lpUnk); |
| |
| if (!lpUnk) |
| return 0UL; |
| return IUnknown_AddRef((LPUNKNOWN)lpUnk); |
| } |
| |
| /************************************************************************** |
| * UlRelease@4 (MAPI32.129) |
| * |
| * Remove a reference from an object. |
| * |
| * PARAMS |
| * lpUnk [I] Object to remove reference from. |
| * |
| * RETURNS |
| * The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is |
| * non-NULL and this function returns 0, the object pointed to by lpUnk has |
| * been released. |
| * |
| * NOTES |
| * See IUnknown_Release. |
| */ |
| ULONG WINAPI UlRelease(void *lpUnk) |
| { |
| TRACE("(%p)\n", lpUnk); |
| |
| if (!lpUnk) |
| return 0UL; |
| return IUnknown_Release((LPUNKNOWN)lpUnk); |
| } |
| |
| /************************************************************************* |
| * OpenStreamOnFile@24 (MAPI32.147) |
| * |
| * Create a stream on a file. |
| * |
| * PARAMS |
| * lpAlloc [I] Memory allocation function |
| * lpFree [I] Memory free function |
| * ulFlags [I] Flags controlling the opening process |
| * lpszPath [I] Path of file to create stream on |
| * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME) |
| * lppStream [O] Destination for created stream |
| * |
| * RETURNS |
| * Success: S_OK. lppStream contains the new stream object |
| * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code |
| * describing the error. |
| */ |
| HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree, |
| ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix, |
| LPSTREAM *lppStream) |
| { |
| WCHAR szBuff[MAX_PATH]; |
| DWORD dwMode = STGM_READWRITE, dwAttributes = 0; |
| HRESULT hRet; |
| |
| TRACE("(%p,%p,0x%08lx,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags, |
| debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream); |
| |
| if (lppStream) |
| *lppStream = NULL; |
| |
| if (ulFlags & SOF_UNIQUEFILENAME) |
| { |
| FIXME("Should generate a temporary name\n"); |
| return E_INVALIDARG; |
| } |
| |
| if (!lpszPath || !lppStream) |
| return E_INVALIDARG; |
| |
| /* FIXME: Should probably munge mode and attributes, and should handle |
| * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if |
| * we are being passed Unicode strings; MSDN doesn't say). |
| * This implementation is just enough for Outlook97 to start. |
| */ |
| MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH); |
| hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE, |
| NULL, lppStream); |
| return hRet; |
| } |
| |
| |
| /************************************************************************* |
| * cmc_query_configuration (MAPI32.235) |
| * |
| * Retrieves the configuration information for the installed CMC |
| * |
| * PARAMS |
| * session [I] MAPI session handle |
| * item [I] Enumerated variable that identifies which |
| * configuration information is being requested |
| * reference [O] Buffer where configuration information is written |
| * config_extensions[I/O] Path of file to create stream on |
| * |
| * RETURNS |
| * A CMD define |
| */ |
| CMC_return_code WINAPI cmc_query_configuration( |
| CMC_session_id session, |
| CMC_enum item, |
| CMC_buffer reference, |
| CMC_extension *config_extensions) |
| { |
| FIXME("stub"); |
| return CMC_E_NOT_SUPPORTED; |
| } |