mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9384 lines
252 KiB
9384 lines
252 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1994-1995
|
|
//
|
|
// File: unicwrap.cpp
|
|
//
|
|
// Contents: Wrappers for all Unicode functions used in MSHTML.
|
|
// Any Unicode parameters/structure fields/buffers are converted
|
|
// to ANSI, and then the corresponding ANSI version of the function
|
|
// is called.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// This file expects to be compiled UNICODE
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// HOW TO WRITE A WRAPPER
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Suppose you want to write a wrapper for CreateMutex.
|
|
//
|
|
// - Look up CreateMutex and see that it is a function in KERNEL32.DLL.
|
|
// If your function is in some other DLL, make the appropriate changes
|
|
// to the instructions below.
|
|
//
|
|
// - Write a wrapper for your function, wrapped inside the appropriate
|
|
// #ifdef for the DLL being wrapped.
|
|
//
|
|
// #ifdef NEED_KERNEL32_WRAPPER
|
|
// STDAPI_(HANDLE) WINAPI
|
|
// CreateMutexWrapW(...)
|
|
// {
|
|
// VALIDATE_PROTOTYPE(CreateMutex);
|
|
// blahblahblah
|
|
// }
|
|
// #endif // NEED_KERNEL32_WRAPPER
|
|
//
|
|
// - If your wrapped function is in a DLL other than KERNEL32,
|
|
// USER32, GDI32, or ADVAPI32, then you need to write a delay-load
|
|
// stub in dllload.c.
|
|
//
|
|
// Furthermore, if the delay-load stub uses DELAY_MAP instead of
|
|
// DELAY_LOAD (SHELL32, WINMM, COMDLG32), then the line
|
|
//
|
|
// VALIDATE_PROTOTYPE(WrappedFunction)
|
|
//
|
|
// needs to be changed to
|
|
//
|
|
// VALIDATE_PROTOTYPE_DELAYLOAD(WrappedFunction, _WrappedFunction)
|
|
//
|
|
// - Add a line for your function to thunk.h. In our case, we would
|
|
// look for the #ifndef NEED_KERNEL32_WRAPPER section and add the
|
|
// line
|
|
//
|
|
// #define CreateMutexWrapW CreateMutexW
|
|
//
|
|
// (This prevents shlwapi from trying to call a nonexistent wrapper.)
|
|
//
|
|
// - Add a line for your function to shlwapi.src.
|
|
//
|
|
// KERNEL32_WRAP(CreateMutexW) @nnn NONAME PRIVATE
|
|
//
|
|
// - If your wrapper is high-frequency, you may want to use
|
|
// FORWARD_AW or THUNK_AW to make it faster on NT.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// WARNING: if you add a new call to FORWARD_AW or THUNK_AW (or modify the
|
|
// macros), make sure you build this file on both x86 and non-x86 (or
|
|
// alternately, build w/ PERF_ASM=0 on x86) to make sure there are no
|
|
// syntax errors. the macros are *very* different between x86 and non-x86,
|
|
// so successful compilation on one platform in no way guarantees success
|
|
// on the other. i speak from experience, not theory...
|
|
|
|
#include "priv.h"
|
|
#define _SHELL32_
|
|
#define _SHDOCVW_
|
|
#include <shellapi.h>
|
|
#include <commctrl.h> // for treeview
|
|
#include "unicwrap.h"
|
|
#include <wininet.h> // INTERNET_MAX_URL_LENGTH
|
|
#include <winnetp.h>
|
|
#include "mlui.h"
|
|
|
|
#include <platform.h>
|
|
#include "apithk.h"
|
|
|
|
#define DM_PERF 0 // perf stats
|
|
|
|
#ifndef ANSI_SHELL32_ON_UNIX
|
|
#define UseUnicodeShell32() ( g_bRunningOnNT )
|
|
#else
|
|
#define UseUnicodeShell32() ( FALSE )
|
|
#endif
|
|
|
|
//
|
|
// Do this in every wrapper function to make sure the wrapper
|
|
// prototype matches the function it is intending to replace.
|
|
//
|
|
#define VALIDATE_PROTOTYPE(f) if (f##W == f##WrapW) 0
|
|
#define VALIDATE_PROTOTYPEA(f) if (f##A == f##WrapA) 0
|
|
#define VALIDATE_PROTOTYPEX(f) if (f == f##Wrap) 0
|
|
#define VALIDATE_PROTOTYPE_DELAYLOAD(fWrap, fDelay) if (fDelay##W == fWrap##WrapW) 0
|
|
#define VALIDATE_PROTOTYPE_DELAYLOADX(fWrap, fDelay) if (fDelay == fWrap##Wrap) 0
|
|
#define VALIDATE_PROTOTYPE_NO_W(f) if (f## == f##Wrap) 0
|
|
|
|
|
|
//
|
|
// Do this in every wrapper function that has an output parameter.
|
|
// It raises assertion failures on the main code path so that
|
|
// the same assertions are raised on NT and 95. The CStrOut class
|
|
// doesn't like it when you say that an output buffer is NULL yet
|
|
// has nonzero length. Without this macro, the bug would go undetected
|
|
// on NT and appear only on Win95.
|
|
//
|
|
// FEATURE raymondc - Turn this on after fixing all the RIPs it catches
|
|
// (otherwise we assert too much)
|
|
#if 0
|
|
#define VALIDATE_OUTBUF(s, cch) ASSERT((s) != NULL || (cch) == 0)
|
|
#else
|
|
#define VALIDATE_OUTBUF(s, cch)
|
|
#endif
|
|
|
|
// compiler should do this opt for us (call-thunk => jmp), but it doesn't
|
|
// so we do it ourselves (i raided it and they're adding it to vc6.x so
|
|
// hopefully we'll get it someday)
|
|
#if _X86_
|
|
#define PERF_ASM 1 // turn on inline-asm opts
|
|
#endif
|
|
|
|
// todo??? #ifdef SUNDOWN #undef PERF_ASM
|
|
|
|
#if PERF_ASM // {
|
|
|
|
// APPCOMPAT workaround compiler bug
|
|
// compiler should know this, but doesn't, so we make it explicit
|
|
#define IMPORT_PTR dword ptr // doesn't work for sundown
|
|
|
|
|
|
//*** FORWARD_AW, THUNK_AW -- simple forwarders and thunks
|
|
// ENTRY/EXIT
|
|
// - declare function w/ FORWARD_API
|
|
// - if you're using THUNK_AW, create the 'A' thunk helper
|
|
// - make the body FORWARD_AW or THUNK_AW.
|
|
// - make sure there's *no* other code in the func. o.w. you'll get bogus
|
|
// code.
|
|
// EXAMPLE
|
|
// int FORWARD_API WINAPI FooWrapW(int i, void *p)
|
|
// {
|
|
// VALIDATE_PROTOTYPE(Foo);
|
|
//
|
|
// FORWARD_AW(Foo, (i, p));
|
|
// }
|
|
//
|
|
// int WINAPI BarAThunk(HWND hwnd, WPARAM wParam)
|
|
// {
|
|
// ... ansi thunk helper ...
|
|
// }
|
|
//
|
|
// int FORWARD_API WINAPI BarWrapW(HWND hwnd, WPARAM wParam)
|
|
// {
|
|
// VALIDATE_PROTOTYPE(Bar);
|
|
//
|
|
// THUNK_AW(Bar, (hwnd, wParam));
|
|
// }
|
|
// NOTES
|
|
// - WARNING: can only be used for 'simple' thunks (NAKED => no non-global
|
|
// vars, etc.).
|
|
// - WARNING: calling func must be declared FORWARD_API. if not you'll
|
|
// get bogus code. happily if you forget you get the (obscure) error
|
|
// message "error C4035: 'FooW': no return value"
|
|
// - note that the macro ends up w/ an extra ";" from the caller, oh well...
|
|
// - TODO: perf: better still would be to have a g_pfnCallWndProc, init
|
|
// it 1x, and then jmp indirect w/o the test. it would cost us a ptr but
|
|
// we only do it for the top-2 funcs (CallWindowProc and SendMessage)
|
|
#define FORWARD_API _declspec(naked)
|
|
|
|
#define FORWARD_AW(_fn, _args) \
|
|
if (g_bRunningOnNT) { \
|
|
_asm { jmp IMPORT_PTR _fn##W } \
|
|
} \
|
|
_asm { jmp IMPORT_PTR _fn##A }
|
|
|
|
#define THUNK_AW(_fn, _args) \
|
|
if (g_bRunningOnNT) { \
|
|
_asm { jmp IMPORT_PTR _fn##W } \
|
|
} \
|
|
_asm { jmp _fn##AThunk } // n.b. no IMPORT_PTR
|
|
|
|
#else // }{
|
|
|
|
#define FORWARD_API /*NOTHING*/
|
|
|
|
#define FORWARD_AW(_fn, _args) \
|
|
if (g_bRunningOnNT) { \
|
|
return _fn##W _args; \
|
|
} \
|
|
return _fn##A _args;
|
|
|
|
#define THUNK_AW(_fn, _args) \
|
|
if (g_bRunningOnNT) { \
|
|
return _fn##W _args; \
|
|
} \
|
|
return _fn##AThunk _args;
|
|
|
|
#endif // }
|
|
|
|
//
|
|
// Windows 95 and NT5 do not have the hbmpItem field in their MENUITEMINFO
|
|
// structure.
|
|
//
|
|
#if (_WIN32_WINNT >= 0x0500)
|
|
#define MENUITEMINFOSIZE_WIN95 FIELD_OFFSET(MENUITEMINFOW, hbmpItem)
|
|
#else
|
|
#define MENUITEMINFOSIZE_WIN95 sizeof(MENUITEMINFOW)
|
|
#endif
|
|
|
|
|
|
//
|
|
// FEATURE - Undefine functions that are defined in thunk.h
|
|
// These are duplicates of functions defined here
|
|
// and should be deleted from thunk.c.
|
|
|
|
#undef RegSetValueExW
|
|
#undef CompareStringW
|
|
#undef GetFileAttributesW
|
|
#undef GetFullPathNameW
|
|
#undef SearchPathW
|
|
#undef GetWindowsDirectoryW
|
|
#undef GetSystemDirectoryW
|
|
#undef GetEnvironmentVariableW
|
|
|
|
// Undefine mappings
|
|
#undef CharLowerW
|
|
|
|
|
|
//
|
|
// FEATURE - There are numerous registry functions that are duplicated
|
|
// here and in reg.c
|
|
//
|
|
|
|
//
|
|
// Some W functions are implemented on Win95, so complain if anybody
|
|
// writes thunks for them.
|
|
//
|
|
// Though Win95's implementation of TextOutW is incomplete for FE languages.
|
|
// Remove this section when we implement FE-aware TextOutW for Win95.
|
|
//
|
|
#if defined(TextOutWrap)
|
|
#error Do not write thunks for TextOutW; Win95 supports it.
|
|
#endif
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CConvertStr::Free
|
|
//
|
|
// Synopsis: Frees string if alloc'd and initializes to NULL.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
CConvertStr::Free()
|
|
{
|
|
if (_pstr != _ach && HIWORD64(_pstr) != 0 && !IsAtom())
|
|
{
|
|
delete [] _pstr;
|
|
}
|
|
|
|
_pstr = NULL;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CConvertStrW::Free
|
|
//
|
|
// Synopsis: Frees string if alloc'd and initializes to NULL.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
CConvertStrW::Free()
|
|
{
|
|
if (_pwstr != _awch && HIWORD64(_pwstr) != 0)
|
|
{
|
|
delete [] _pwstr;
|
|
}
|
|
|
|
_pwstr = NULL;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrInW::Init
|
|
//
|
|
// Synopsis: Converts a LPSTR function argument to a LPWSTR.
|
|
//
|
|
// Arguments: [pstr] -- The function argument. May be NULL or an atom
|
|
// (HIWORD64(pwstr) == 0).
|
|
//
|
|
// [cch] -- The number of characters in the string to
|
|
// convert. If -1, the string is assumed to be
|
|
// NULL terminated and its length is calculated.
|
|
//
|
|
// Modifies: [this]
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
CStrInW::Init(LPCSTR pstr, int cch)
|
|
{
|
|
int cchBufReq;
|
|
|
|
_cwchLen = 0;
|
|
|
|
// Check if string is NULL or an atom.
|
|
if (HIWORD64(pstr) == 0)
|
|
{
|
|
_pwstr = (LPWSTR) pstr;
|
|
return;
|
|
}
|
|
|
|
ASSERT(cch == -1 || cch > 0);
|
|
|
|
//
|
|
// Convert string to preallocated buffer, and return if successful.
|
|
//
|
|
// Since the passed in buffer may not be null terminated, we have
|
|
// a problem if cch==ARRAYSIZE(_awch), because MultiByteToWideChar
|
|
// will succeed, and we won't be able to null terminate the string!
|
|
// Decrease our buffer by one for this case.
|
|
//
|
|
_cwchLen = MultiByteToWideChar(
|
|
CP_ACP, 0, pstr, cch, _awch, ARRAYSIZE(_awch)-1);
|
|
|
|
if (_cwchLen > 0)
|
|
{
|
|
// Some callers don't NULL terminate.
|
|
//
|
|
// We could check "if (-1 != cch)" before doing this,
|
|
// but always doing the null is less code.
|
|
//
|
|
_awch[_cwchLen] = 0;
|
|
|
|
if (0 == _awch[_cwchLen-1]) // account for terminator
|
|
_cwchLen--;
|
|
|
|
_pwstr = _awch;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Alloc space on heap for buffer.
|
|
//
|
|
|
|
cchBufReq = MultiByteToWideChar( CP_ACP, 0, pstr, cch, NULL, 0 );
|
|
|
|
// Again, leave room for null termination
|
|
cchBufReq++;
|
|
|
|
ASSERT(cchBufReq > 0);
|
|
_pwstr = new WCHAR[cchBufReq];
|
|
if (!_pwstr)
|
|
{
|
|
// On failure, the argument will point to the empty string.
|
|
_awch[0] = 0;
|
|
_pwstr = _awch;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(_pwstr));
|
|
_cwchLen = MultiByteToWideChar(
|
|
CP_ACP, 0, pstr, cch, _pwstr, cchBufReq );
|
|
|
|
#if DBG == 1 /* { */
|
|
if (0 == _cwchLen)
|
|
{
|
|
int errcode = GetLastError();
|
|
ASSERT(0 && "MultiByteToWideChar failed in unicode wrapper.");
|
|
}
|
|
#endif /* } */
|
|
|
|
// Again, make sure we're always null terminated
|
|
ASSERT(_cwchLen < cchBufReq);
|
|
_pwstr[_cwchLen] = 0;
|
|
|
|
if (0 == _pwstr[_cwchLen-1]) // account for terminator
|
|
_cwchLen--;
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrIn::CStrIn
|
|
//
|
|
// Synopsis: Inits the class.
|
|
//
|
|
// NOTE: Don't inline this function or you'll increase code size
|
|
// by pushing -1 on the stack for each call.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrIn::CStrIn(LPCWSTR pwstr) : CConvertStr(CP_ACP)
|
|
{
|
|
Init(pwstr, -1);
|
|
}
|
|
|
|
|
|
CStrIn::CStrIn(UINT uCP, LPCWSTR pwstr) : CConvertStr(uCP)
|
|
{
|
|
Init(pwstr, -1);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrIn::Init
|
|
//
|
|
// Synopsis: Converts a LPWSTR function argument to a LPSTR.
|
|
//
|
|
// Arguments: [pwstr] -- The function argument. May be NULL or an atom
|
|
// (HIWORD(pwstr) == 0).
|
|
//
|
|
// [cwch] -- The number of characters in the string to
|
|
// convert. If -1, the string is assumed to be
|
|
// NULL terminated and its length is calculated.
|
|
//
|
|
// Modifies: [this]
|
|
//
|
|
// Note: We ignore AreFileApisANSI() and always use CP_ACP.
|
|
// The reason is that nobody uses SetFileApisToOEM() except
|
|
// console apps, and once you set file APIs to OEM, you
|
|
// cannot call shell/user/gdi APIs, since they assume ANSI
|
|
// regardless of the FileApis setting. So you end up in
|
|
// this horrible messy state where the filename APIs interpret
|
|
// the strings as OEM but SHELL32 interprets the strings
|
|
// as ANSI and you end up with a big mess.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
CStrIn::Init(LPCWSTR pwstr, int cwch)
|
|
{
|
|
int cchBufReq;
|
|
|
|
#if DBG == 1 /* { */
|
|
int errcode;
|
|
#endif /* } */
|
|
|
|
_cchLen = 0;
|
|
|
|
// Check if string is NULL or an atom.
|
|
if (HIWORD64(pwstr) == 0 || IsAtom())
|
|
{
|
|
_pstr = (LPSTR) pwstr;
|
|
return;
|
|
}
|
|
|
|
if ( cwch == 0 )
|
|
{
|
|
*_ach = '\0';
|
|
_pstr = _ach;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Convert string to preallocated buffer, and return if successful.
|
|
//
|
|
|
|
_cchLen = WideCharToMultiByte(
|
|
_uCP, 0, pwstr, cwch, _ach, ARRAYSIZE(_ach)-1, NULL, NULL);
|
|
|
|
if (_cchLen > 0)
|
|
{
|
|
// This is DBCS safe since byte before _cchLen is last character
|
|
_ach[_cchLen] = 0;
|
|
// this may not be safe if the last character
|
|
// was a multibyte character...
|
|
if (_ach[_cchLen-1]==0)
|
|
_cchLen--; // account for terminator
|
|
_pstr = _ach;
|
|
return;
|
|
}
|
|
|
|
|
|
cchBufReq = WideCharToMultiByte(
|
|
CP_ACP, 0, pwstr, cwch, NULL, 0, NULL, NULL);
|
|
|
|
cchBufReq++;
|
|
|
|
ASSERT(cchBufReq > 0);
|
|
_pstr = new char[cchBufReq];
|
|
if (!_pstr)
|
|
{
|
|
// On failure, the argument will point to the empty string.
|
|
_ach[0] = 0;
|
|
_pstr = _ach;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(_pstr));
|
|
_cchLen = WideCharToMultiByte(
|
|
_uCP, 0, pwstr, cwch, _pstr, cchBufReq, NULL, NULL);
|
|
#if DBG == 1 /* { */
|
|
if (_cchLen < 0)
|
|
{
|
|
errcode = GetLastError();
|
|
ASSERT(0 && "WideCharToMultiByte failed in unicode wrapper.");
|
|
}
|
|
#endif /* } */
|
|
|
|
// Again, make sure we're always null terminated
|
|
ASSERT(_cchLen < cchBufReq);
|
|
_pstr[_cchLen] = 0;
|
|
if (0 == _pstr[_cchLen-1]) // account for terminator
|
|
_cchLen--;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrInMulti::CStrInMulti
|
|
//
|
|
// Synopsis: Converts mulitple LPWSTRs to a multiple LPSTRs.
|
|
//
|
|
// Arguments: [pwstr] -- The strings to convert.
|
|
//
|
|
// Modifies: [this]
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrInMulti::CStrInMulti(LPCWSTR pwstr)
|
|
{
|
|
LPCWSTR pwstrT;
|
|
|
|
// We don't handle atoms because we don't need to.
|
|
ASSERT(HIWORD64(pwstr));
|
|
|
|
//
|
|
// Count number of characters to convert.
|
|
//
|
|
|
|
pwstrT = pwstr;
|
|
if (pwstr)
|
|
{
|
|
do {
|
|
while (*pwstrT++)
|
|
;
|
|
|
|
} while (*pwstrT++);
|
|
}
|
|
|
|
Init(pwstr, (int)(pwstrT - pwstr));
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CPPFIn::CPPFIn
|
|
//
|
|
// Synopsis: Inits the class. Truncates the filename to MAX_PATH
|
|
// so Win9x DBCS won't fault. Win9x SBCS silently truncates
|
|
// to MAX_PATH, so we're bug-for-bug compatible.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CPPFIn::CPPFIn(LPCWSTR pwstr)
|
|
{
|
|
SHUnicodeToAnsi(pwstr, _ach, ARRAYSIZE(_ach));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOut::CStrOut
|
|
//
|
|
// Synopsis: Allocates enough space for an out buffer.
|
|
//
|
|
// Arguments: [pwstr] -- The Unicode buffer to convert to when destroyed.
|
|
// May be NULL.
|
|
//
|
|
// [cwchBuf] -- The size of the buffer in characters.
|
|
//
|
|
// Modifies: [this].
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrOut::CStrOut(LPWSTR pwstr, int cwchBuf) : CConvertStr(CP_ACP)
|
|
{
|
|
Init(pwstr, cwchBuf);
|
|
}
|
|
|
|
CStrOut::CStrOut(UINT uCP, LPWSTR pwstr, int cwchBuf) : CConvertStr(uCP)
|
|
{
|
|
Init(pwstr, cwchBuf);
|
|
}
|
|
|
|
void
|
|
CStrOut::Init(LPWSTR pwstr, int cwchBuf)
|
|
{
|
|
ASSERT(cwchBuf >= 0);
|
|
|
|
_pwstr = pwstr;
|
|
_cwchBuf = cwchBuf;
|
|
|
|
if (!pwstr)
|
|
{
|
|
// Force cwchBuf = 0 because many callers (in particular, registry
|
|
// munging functions) pass garbage as the length because they know
|
|
// it will be ignored.
|
|
_cwchBuf = 0;
|
|
_pstr = NULL;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(pwstr));
|
|
|
|
// Initialize buffer in case Windows API returns an error.
|
|
_ach[0] = 0;
|
|
|
|
// Use preallocated buffer if big enough.
|
|
if (cwchBuf * 2 <= ARRAYSIZE(_ach))
|
|
{
|
|
_pstr = _ach;
|
|
return;
|
|
}
|
|
|
|
// Allocate buffer.
|
|
_pstr = new char[cwchBuf * 2];
|
|
if (!_pstr)
|
|
{
|
|
//
|
|
// On failure, the argument will point to a zero-sized buffer initialized
|
|
// to the empty string. This should cause the Windows API to fail.
|
|
//
|
|
|
|
ASSERT(cwchBuf > 0);
|
|
_pwstr[0] = 0;
|
|
_cwchBuf = 0;
|
|
_pstr = _ach;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(_pstr));
|
|
_pstr[0] = 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOutW::CStrOutW
|
|
//
|
|
// Synopsis: Allocates enough space for an out buffer.
|
|
//
|
|
// Arguments: [pstr] -- The MBCS buffer to convert to when destroyed.
|
|
// May be NULL.
|
|
//
|
|
// [cchBuf] -- The size of the buffer in characters.
|
|
//
|
|
// Modifies: [this].
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrOutW::CStrOutW(LPSTR pstr, int cchBuf)
|
|
{
|
|
ASSERT(cchBuf >= 0);
|
|
|
|
_pstr = pstr;
|
|
_cchBuf = cchBuf;
|
|
|
|
if (!pstr)
|
|
{
|
|
// Force cchBuf = 0 because many callers (in particular, registry
|
|
// munging functions) pass garbage as the length because they know
|
|
// it will be ignored.
|
|
_cchBuf = 0;
|
|
_pwstr = NULL;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(pstr));
|
|
|
|
// Initialize buffer in case Windows API returns an error.
|
|
_awch[0] = 0;
|
|
|
|
// Use preallocated buffer if big enough.
|
|
if (cchBuf <= ARRAYSIZE(_awch))
|
|
{
|
|
_pwstr = _awch;
|
|
return;
|
|
}
|
|
|
|
// Allocate buffer.
|
|
_pwstr = new WCHAR[cchBuf];
|
|
if (!_pwstr)
|
|
{
|
|
//
|
|
// On failure, the argument will point to a zero-sized buffer initialized
|
|
// to the empty string. This should cause the Windows API to fail.
|
|
//
|
|
|
|
ASSERT(cchBuf > 0);
|
|
_pstr[0] = 0;
|
|
_cchBuf = 0;
|
|
_pwstr = _awch;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HIWORD64(_pwstr));
|
|
_pwstr[0] = 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOut::ConvertIncludingNul
|
|
//
|
|
// Synopsis: Converts the buffer from MBCS to Unicode
|
|
//
|
|
// Return: Character count INCLUDING the trailing '\0'
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
CStrOut::ConvertIncludingNul()
|
|
{
|
|
int cch;
|
|
|
|
if (!_pstr)
|
|
return 0;
|
|
|
|
cch = SHAnsiToUnicodeCP(_uCP, _pstr, _pwstr, _cwchBuf);
|
|
|
|
#if DBG == 1 /* { */
|
|
if (cch == 0 && _cwchBuf > 0)
|
|
{
|
|
int errcode = GetLastError();
|
|
ASSERT(0 && "SHAnsiToUnicode failed in unicode wrapper.");
|
|
}
|
|
#endif /* } */
|
|
|
|
Free();
|
|
return cch;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOutW::ConvertIncludingNul
|
|
//
|
|
// Synopsis: Converts the buffer from Unicode to MBCS
|
|
//
|
|
// Return: Character count INCLUDING the trailing '\0'
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
CStrOutW::ConvertIncludingNul()
|
|
{
|
|
int cch;
|
|
|
|
if (!_pwstr)
|
|
return 0;
|
|
|
|
cch = SHUnicodeToAnsi(_pwstr, _pstr, _cchBuf);
|
|
|
|
#if DBG == 1 /* { */
|
|
if (cch == 0 && _cchBuf > 0)
|
|
{
|
|
int errcode = GetLastError();
|
|
ASSERT(0 && "SHUnicodeToAnsi failed in unicode wrapper.");
|
|
}
|
|
#endif /* } */
|
|
|
|
Free();
|
|
return cch;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOut::ConvertExcludingNul
|
|
//
|
|
// Synopsis: Converts the buffer from MBCS to Unicode
|
|
//
|
|
// Return: Character count EXCLUDING the trailing '\0'
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
CStrOut::ConvertExcludingNul()
|
|
{
|
|
int ret = ConvertIncludingNul();
|
|
if (ret > 0)
|
|
{
|
|
ret -= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOut::~CStrOut
|
|
//
|
|
// Synopsis: Converts the buffer from MBCS to Unicode.
|
|
//
|
|
// Note: Don't inline this function, or you'll increase code size as
|
|
// both ConvertIncludingNul() and CConvertStr::~CConvertStr will be
|
|
// called inline.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrOut::~CStrOut()
|
|
{
|
|
ConvertIncludingNul();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStrOutW::~CStrOutW
|
|
//
|
|
// Synopsis: Converts the buffer from Unicode to MBCS.
|
|
//
|
|
// Note: Don't inline this function, or you'll increase code size as
|
|
// both ConvertIncludingNul() and CConvertStr::~CConvertStr will be
|
|
// called inline.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStrOutW::~CStrOutW()
|
|
{
|
|
ConvertIncludingNul();
|
|
}
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CWin32FindDataInOut
|
|
//
|
|
// Purpose: Converts WIN32_FIND_DATA structures from UNICODE to ANSI
|
|
// on the way in, then ANSI to UNICODE on the way out.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CWin32FindDataInOut
|
|
{
|
|
public:
|
|
operator LPWIN32_FIND_DATAA();
|
|
CWin32FindDataInOut(LPWIN32_FIND_DATAW pfdW);
|
|
~CWin32FindDataInOut();
|
|
|
|
protected:
|
|
LPWIN32_FIND_DATAW _pfdW;
|
|
WIN32_FIND_DATAA _fdA;
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWin32FindDataInOut::CWin32FindDataInOut
|
|
//
|
|
// Synopsis: Convert the non-string fields to ANSI. You'd think this
|
|
// isn't necessary, but it is, because Win95 puts secret
|
|
// goo into the dwReserved fields that must be preserved.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
CWin32FindDataInOut::CWin32FindDataInOut(LPWIN32_FIND_DATAW pfdW) :
|
|
_pfdW(pfdW)
|
|
{
|
|
memcpy(&_fdA, _pfdW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName));
|
|
|
|
_fdA.cFileName[0] = '\0';
|
|
_fdA.cAlternateFileName[0] = '\0';
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWin32FindDataInOut::~CWin32FindDataInOut
|
|
//
|
|
// Synopsis: Convert all the fields from ANSI back to UNICODE.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
CWin32FindDataInOut::~CWin32FindDataInOut()
|
|
{
|
|
memcpy(_pfdW, &_fdA, FIELD_OFFSET(WIN32_FIND_DATA, cFileName));
|
|
|
|
SHAnsiToUnicode(_fdA.cFileName, _pfdW->cFileName, ARRAYSIZE(_pfdW->cFileName));
|
|
SHAnsiToUnicode(_fdA.cAlternateFileName, _pfdW->cAlternateFileName, ARRAYSIZE(_pfdW->cAlternateFileName));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWin32FindDataInOut::operator LPWIN32_FIND_DATAA
|
|
//
|
|
// Synopsis: Returns the WIN32_FIND_DATAA.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
CWin32FindDataInOut::operator LPWIN32_FIND_DATAA()
|
|
{
|
|
return &_fdA;
|
|
}
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Implementation of the wrapped functions
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
AppendMenuWrapW(
|
|
HMENU hMenu,
|
|
UINT uFlags,
|
|
UINT_PTR uIDnewItem,
|
|
LPCWSTR lpnewItem)
|
|
{
|
|
VALIDATE_PROTOTYPE(AppendMenu);
|
|
|
|
// Make the InsertMenu wrapper do all the work
|
|
return InsertMenuWrapW(hMenu, (UINT)-1,
|
|
uFlags | MF_BYPOSITION, uIDnewItem, lpnewItem);
|
|
}
|
|
|
|
UINT GetLocaleAnsiCodePage(LCID Locale)
|
|
{
|
|
WCHAR szCodePage[7];
|
|
|
|
UINT uiRetVal;
|
|
|
|
if (0 != GetLocaleInfoWrapW(Locale, LOCALE_IDEFAULTANSICODEPAGE, szCodePage, ARRAYSIZE(szCodePage)))
|
|
{
|
|
uiRetVal = StrToInt(szCodePage);
|
|
}
|
|
else
|
|
{
|
|
uiRetVal = CP_ACP;
|
|
}
|
|
|
|
return uiRetVal;
|
|
}
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LRESULT FORWARD_API WINAPI
|
|
CallWindowProcWrapW(
|
|
WNDPROC lpPrevWndFunc,
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(CallWindowProc);
|
|
|
|
// perf: better still would be to have a g_pfnCallWndProc, init it 1x,
|
|
// and then jmp indirect w/o the test. it would cost us a ptr but we
|
|
// only do it for the top-2 funcs (CallWindowProc and SendMessage)
|
|
FORWARD_AW(CallWindowProc, (lpPrevWndFunc, hWnd, Msg, wParam, lParam));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
STDAPI_(BOOL FORWARD_API) CallMsgFilterWrapW(LPMSG lpMsg, int nCode)
|
|
{
|
|
VALIDATE_PROTOTYPE(CallMsgFilter);
|
|
|
|
FORWARD_AW(CallMsgFilter, (lpMsg, nCode));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CharLowerWrapW( LPWSTR pch )
|
|
//
|
|
// purpose: Converts character to lowercase. Takes either a pointer
|
|
// to a string, or a character masquerading as a pointer.
|
|
// In the later case, the HIWORD must be zero. This is
|
|
// as spec'd for Win32.
|
|
//
|
|
// returns: Lowercased character or string. In the string case,
|
|
// the lowercasing is done inplace.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LPWSTR WINAPI
|
|
CharLowerWrapW( LPWSTR pch )
|
|
{
|
|
VALIDATE_PROTOTYPE(CharLower);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CharLowerW( pch );
|
|
}
|
|
|
|
if (!HIWORD64(pch))
|
|
{
|
|
WCHAR ch = (WCHAR)(LONG_PTR)pch;
|
|
|
|
CharLowerBuffWrapW( &ch, 1 );
|
|
|
|
pch = (LPWSTR)MAKEINTATOM(ch);
|
|
}
|
|
else
|
|
{
|
|
CharLowerBuffWrapW( pch, lstrlenW(pch) );
|
|
}
|
|
|
|
return pch;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CharLowerBuffWrapW( LPWSTR pch, DWORD cch )
|
|
//
|
|
// purpose: Converts a string to lowercase. String must be cch
|
|
// characters in length.
|
|
//
|
|
// returns: Character count (cch). The lowercasing is done inplace.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
CharLowerBuffWrapW( LPWSTR pch, DWORD cchLength )
|
|
{
|
|
VALIDATE_PROTOTYPE(CharLowerBuff);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CharLowerBuffW( pch, cchLength );
|
|
}
|
|
|
|
DWORD cch;
|
|
|
|
for ( cch = cchLength; cch-- ; pch++ )
|
|
{
|
|
WCHAR ch = *pch;
|
|
|
|
if (IsCharUpperWrapW(ch))
|
|
{
|
|
if (ch < 0x0100)
|
|
{
|
|
*pch += 32; // Get Latin-1 out of the way first
|
|
}
|
|
else if (ch < 0x0531)
|
|
{
|
|
if (ch < 0x0391)
|
|
{
|
|
if (ch < 0x01cd)
|
|
{
|
|
if (ch <= 0x178)
|
|
{
|
|
if (ch < 0x0178)
|
|
{
|
|
*pch += (ch == 0x0130) ? 0 : 1;
|
|
}
|
|
else
|
|
{
|
|
*pch -= 121;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const BYTE abLookup[] =
|
|
{ // 0/8 1/9 2/a 3/b 4/c 5/d 6/e 7/f
|
|
/* 0x0179-0x17f */ 1, 0, 1, 0, 1, 0, 0,
|
|
/* 0x0180-0x187 */ 0, 210, 1, 0, 1, 0, 206, 1,
|
|
/* 0x0188-0x18f */ 0, 205, 205, 1, 0, 0, 79, 202,
|
|
/* 0x0190-0x197 */ 203, 1, 0, 205, 207, 0, 211, 209,
|
|
/* 0x0198-0x19f */ 1, 0, 0, 0, 211, 213, 0, 214,
|
|
/* 0x01a0-0x1a7 */ 1, 0, 1, 0, 1, 0, 0, 1,
|
|
/* 0x01a8-0x1af */ 0, 218, 0, 0, 1, 0, 218, 1,
|
|
/* 0x01b0-0x1b7 */ 0, 217, 217, 1, 0, 1, 0, 219,
|
|
/* 0x01b8-0x1bf */ 1, 0, 0, 0, 1, 0, 0, 0,
|
|
/* 0x01c0-0x1c7 */ 0, 0, 0, 0, 2, 0, 0, 2,
|
|
/* 0x01c8-0x1cb */ 0, 0, 2, 0
|
|
};
|
|
|
|
*pch += abLookup[ch-0x0179];
|
|
}
|
|
}
|
|
else if (ch < 0x0386)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case 0x01f1: *pch += 2; break;
|
|
case 0x01f2: break;
|
|
default: *pch += 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const BYTE abLookup[] =
|
|
{ 38, 0, 37, 37, 37, 0, 64, 0, 63, 63 };
|
|
|
|
*pch += abLookup[ch-0x0386];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x0410)
|
|
{
|
|
if (ch < 0x0401)
|
|
{
|
|
if (ch < 0x03e2)
|
|
{
|
|
if (!InRange(ch, 0x03d2, 0x03d4) &&
|
|
!(InRange(ch, 0x3da, 0x03e0) & !(ch & 1)))
|
|
{
|
|
*pch += 32;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pch += 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pch += 80;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x0460)
|
|
{
|
|
*pch += 32;
|
|
}
|
|
else
|
|
{
|
|
*pch += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x2160)
|
|
{
|
|
if (ch < 0x1fba)
|
|
{
|
|
if (ch < 0x1f08)
|
|
{
|
|
if (ch < 0x1e00)
|
|
{
|
|
*pch += 48;
|
|
}
|
|
else
|
|
{
|
|
*pch += 1;
|
|
}
|
|
}
|
|
else if (!(InRange(ch, 0x1f88, 0x1faf) && (ch & 15)>7))
|
|
{
|
|
*pch -= 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const BYTE abLookup[] =
|
|
{ // 8 9 a b c d e f
|
|
0, 0, 74, 74, 0, 0, 0, 0,
|
|
86, 86, 86, 86, 0, 0, 0, 0,
|
|
8, 8, 100, 100, 0, 0, 0, 0,
|
|
8, 8, 112, 112, 7, 0, 0, 0,
|
|
128, 128, 126, 126, 0, 0, 0, 0
|
|
};
|
|
int i = (ch-0x1fb0);
|
|
|
|
*pch -= (int)abLookup[((i>>1) & ~7) | (i & 7)];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0xff21)
|
|
{
|
|
if (ch < 0x24b6)
|
|
{
|
|
*pch += 16;
|
|
}
|
|
else
|
|
{
|
|
*pch += 26;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pch += 32;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// These are Unicode Number Forms. They have lowercase counter-
|
|
// parts, but are not considered uppercase. Why, I don't know.
|
|
|
|
if (InRange(ch, 0x2160, 0x216f))
|
|
{
|
|
*pch += 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
return cchLength;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
//
|
|
// REARCHITECT - Do CharNextWrap and CharPrevWrap need to call the
|
|
// CharNextW, CharPrevW on WinNT? Couldn't these be MACROS?
|
|
//
|
|
|
|
LPWSTR WINAPI
|
|
CharNextWrapW(LPCWSTR lpszCurrent)
|
|
{
|
|
VALIDATE_PROTOTYPE(CharNext);
|
|
|
|
if (*lpszCurrent)
|
|
{
|
|
return (LPWSTR) lpszCurrent + 1;
|
|
}
|
|
else
|
|
{
|
|
return (LPWSTR) lpszCurrent;
|
|
}
|
|
}
|
|
|
|
LPWSTR WINAPI
|
|
CharPrevWrapW(LPCWSTR lpszStart, LPCWSTR lpszCurrent)
|
|
{
|
|
VALIDATE_PROTOTYPE(CharPrev);
|
|
|
|
if (lpszCurrent == lpszStart)
|
|
{
|
|
return (LPWSTR) lpszStart;
|
|
}
|
|
else
|
|
{
|
|
return (LPWSTR) lpszCurrent - 1;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
CharToOemWrapW(LPCWSTR lpszSrc, LPSTR lpszDst)
|
|
{
|
|
VALIDATE_PROTOTYPE(CharToOem);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
CharToOemW(lpszSrc, lpszDst);
|
|
}
|
|
|
|
CStrIn str(lpszSrc);
|
|
|
|
return CharToOemA(str, lpszDst);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CharUpperWrapW( LPWSTR pch )
|
|
//
|
|
// purpose: Converts character to uppercase. Takes either a pointer
|
|
// to a string, or a character masquerading as a pointer.
|
|
// In the later case, the HIWORD must be zero. This is
|
|
// as spec'd for Win32.
|
|
//
|
|
// returns: Uppercased character or string. In the string case,
|
|
// the uppercasing is done inplace.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LPWSTR WINAPI
|
|
CharUpperWrapW( LPWSTR pch )
|
|
{
|
|
VALIDATE_PROTOTYPE(CharUpper);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CharUpperW( pch );
|
|
}
|
|
|
|
if (!HIWORD64(pch))
|
|
{
|
|
WCHAR ch = (WCHAR)(LONG_PTR)pch;
|
|
|
|
CharUpperBuffWrapW( &ch, 1 );
|
|
|
|
pch = (LPWSTR)MAKEINTATOM(ch);
|
|
}
|
|
else
|
|
{
|
|
CharUpperBuffWrapW( pch, lstrlenW(pch) );
|
|
}
|
|
|
|
return pch;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CharUpperBuffWrapW( LPWSTR pch, DWORD cch )
|
|
//
|
|
// purpose: Converts a string to uppercase. String must be cch
|
|
// characters in length. Note that this function is
|
|
// is messier that CharLowerBuffWrap, and the reason for
|
|
// this is many Unicode characters are considered uppercase,
|
|
// even when they don't have an uppercase counterpart.
|
|
//
|
|
// returns: Character count (cch). The uppercasing is done inplace.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
CharUpperBuffWrapW( LPWSTR pch, DWORD cchLength )
|
|
{
|
|
VALIDATE_PROTOTYPE(CharUpperBuff);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CharUpperBuffW( pch, cchLength );
|
|
}
|
|
|
|
DWORD cch;
|
|
|
|
for ( cch = cchLength; cch-- ; pch++ )
|
|
{
|
|
WCHAR ch = *pch;
|
|
|
|
if (IsCharLowerWrapW(ch))
|
|
{
|
|
if (ch < 0x00ff)
|
|
{
|
|
*pch -= ((ch != 0xdf) << 5);
|
|
}
|
|
else if (ch < 0x03b1)
|
|
{
|
|
if (ch < 0x01f5)
|
|
{
|
|
if (ch < 0x01ce)
|
|
{
|
|
if (ch < 0x017f)
|
|
{
|
|
if (ch < 0x0101)
|
|
{
|
|
*pch += 121;
|
|
}
|
|
else
|
|
{
|
|
*pch -= (ch != 0x0131 &&
|
|
ch != 0x0138 &&
|
|
ch != 0x0149);
|
|
}
|
|
}
|
|
else if (ch < 0x01c9)
|
|
{
|
|
static const BYTE abMask[] =
|
|
{ // 6543210f edcba987
|
|
0xfc, 0xbf, // 11111100 10111111
|
|
0xbf, 0x67, // 10111111 01100111
|
|
0xff, 0xef, // 11111111 11101111
|
|
0xff, 0xf7, // 11111111 11110111
|
|
0xbf, 0xfd // 10111111 11111101
|
|
};
|
|
|
|
int i = ch - 0x017f;
|
|
|
|
*pch -= ((abMask[i>>3] >> (i&7)) & 1) +
|
|
(ch == 0x01c6);
|
|
}
|
|
else
|
|
{
|
|
*pch -= ((ch != 0x01cb)<<1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x01df)
|
|
{
|
|
if (ch < 0x01dd)
|
|
{
|
|
*pch -= 1;
|
|
}
|
|
else
|
|
{
|
|
*pch -= 79;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pch -= 1 + (ch == 0x01f3) -
|
|
InRange(ch,0x01f0,0x01f2);
|
|
}
|
|
}
|
|
}
|
|
else if (ch < 0x0253)
|
|
{
|
|
*pch -= (ch < 0x0250);
|
|
}
|
|
else if (ch < 0x03ac)
|
|
{
|
|
static const BYTE abLookup[] =
|
|
{// 0/8 1/9 2/a 3/b 4/c 5/d 6/e 7/f
|
|
/* 0x0253-0x0257 */ 210, 206, 0, 205, 205,
|
|
/* 0x0258-0x025f */ 0, 202, 0, 203, 0, 0, 0, 0,
|
|
/* 0x0260-0x0267 */ 205, 0, 0, 207, 0, 0, 0, 0,
|
|
/* 0x0268-0x026f */ 209, 211, 0, 0, 0, 0, 0, 211,
|
|
/* 0x0270-0x0277 */ 0, 0, 213, 0, 0, 214, 0, 0,
|
|
/* 0x0278-0x027f */ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x0280-0x0287 */ 0, 0, 0, 218, 0, 0, 0, 0,
|
|
/* 0x0288-0x028f */ 218, 0, 217, 217, 0, 0, 0, 0,
|
|
/* 0x0290-0x0297 */ 0, 0, 219
|
|
};
|
|
|
|
if (ch <= 0x0292)
|
|
{
|
|
*pch -= abLookup[ch - 0x0253];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pch -= (ch == 0x03b0) ? 0 : (37 + (ch == 0x03ac));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x0561)
|
|
{
|
|
if (ch < 0x0451)
|
|
{
|
|
if (ch < 0x03e3)
|
|
{
|
|
if (ch < 0x03cc)
|
|
{
|
|
*pch -= 32 - (ch == 0x03c2);
|
|
}
|
|
else
|
|
{
|
|
int i = (ch < 0x03d0);
|
|
*pch -= (i<<6) - i + (ch == 0x03cc);
|
|
}
|
|
}
|
|
else if (ch < 0x0430)
|
|
{
|
|
*pch -= (ch < 0x03f0);
|
|
}
|
|
else
|
|
{
|
|
*pch -= 32;
|
|
}
|
|
}
|
|
else if (ch < 0x0461)
|
|
{
|
|
*pch -= 80;
|
|
}
|
|
else
|
|
{
|
|
*pch -= 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x1fb0)
|
|
{
|
|
if (ch < 0x1f70)
|
|
{
|
|
if (ch < 0x1e01)
|
|
{
|
|
int i = ch != 0x0587 && ch < 0x10d0;
|
|
*pch -= ((i<<5)+(i<<4)); /* 48 */
|
|
}
|
|
else if (ch < 0x1f00)
|
|
{
|
|
*pch -= !InRange(ch, 0x1e96, 0x1e9a);
|
|
}
|
|
else
|
|
{
|
|
int i = !InRange(ch, 0x1f50, 0x1f56)||(ch & 1);
|
|
*pch += (i<<3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const BYTE abLookup[] =
|
|
{ 74, 86, 86, 100, 128, 112, 126 };
|
|
|
|
if ( ch <= 0x1f7d )
|
|
{
|
|
*pch += abLookup[(ch-0x1f70)>>1];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ch < 0x24d0)
|
|
{
|
|
if (ch < 0x1fe5)
|
|
{
|
|
*pch += (0x0023 & (1<<(ch&15))) ? 8 : 0;
|
|
}
|
|
else if (ch < 0x2170)
|
|
{
|
|
*pch += (0x0023 & (1<<(ch&15))) ? 7 : 0;
|
|
}
|
|
else
|
|
{
|
|
*pch -= ((ch > 0x24b5)<<4);
|
|
}
|
|
}
|
|
else if (ch < 0xff41)
|
|
{
|
|
int i = !InRange(ch, 0xfb00, 0xfb17);
|
|
*pch -= (i<<4)+(i<<3)+(i<<1); /* 26 */
|
|
}
|
|
else
|
|
{
|
|
*pch -= 32;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i = InRange(ch, 0x2170, 0x217f);
|
|
*pch -= (i<<4);
|
|
}
|
|
}
|
|
|
|
return cchLength;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int FORWARD_API WINAPI
|
|
CopyAcceleratorTableWrapW(
|
|
HACCEL hAccelSrc,
|
|
LPACCEL lpAccelDst,
|
|
int cAccelEntries)
|
|
{
|
|
VALIDATE_PROTOTYPE(CopyAcceleratorTable);
|
|
|
|
FORWARD_AW(CopyAcceleratorTable, (hAccelSrc, lpAccelDst, cAccelEntries));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HACCEL FORWARD_API WINAPI
|
|
CreateAcceleratorTableWrapW(LPACCEL lpAccel, int cEntries)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateAcceleratorTable);
|
|
|
|
FORWARD_AW(CreateAcceleratorTable, (lpAccel, cEntries));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
typedef HDC (*FnCreateHDCA)(LPCSTR, LPCSTR, LPCSTR, CONST DEVMODEA *);
|
|
|
|
HDC WINAPI
|
|
CreateHDCWrapW(
|
|
LPCWSTR lpszDriver,
|
|
LPCWSTR lpszDevice,
|
|
LPCWSTR lpszOutput,
|
|
CONST DEVMODEW * lpInitData,
|
|
FnCreateHDCA pfn)
|
|
{
|
|
DEVMODEA * pdevmode = NULL;
|
|
CStrIn strDriver(lpszDriver);
|
|
CStrIn strDevice(lpszDevice);
|
|
CStrIn strOutput(lpszOutput);
|
|
HDC hdcReturn = 0;
|
|
|
|
if (lpInitData)
|
|
{
|
|
pdevmode = (DEVMODEA *) LocalAlloc( LPTR, lpInitData->dmSize + lpInitData->dmDriverExtra );
|
|
|
|
if (pdevmode)
|
|
{
|
|
// LPBYTE->LPSTR casts below
|
|
SHUnicodeToAnsi(lpInitData->dmDeviceName, (LPSTR)pdevmode->dmDeviceName, ARRAYSIZE(pdevmode->dmDeviceName));
|
|
memcpy(&pdevmode->dmSpecVersion,
|
|
&lpInitData->dmSpecVersion,
|
|
FIELD_OFFSET(DEVMODEW,dmFormName) - FIELD_OFFSET(DEVMODEW,dmSpecVersion));
|
|
SHUnicodeToAnsi(lpInitData->dmFormName, (LPSTR)pdevmode->dmFormName, ARRAYSIZE(pdevmode->dmFormName));
|
|
memcpy(&pdevmode->dmLogPixels,
|
|
&lpInitData->dmLogPixels,
|
|
lpInitData->dmDriverExtra + lpInitData->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
|
|
|
|
pdevmode->dmSize -= (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME);
|
|
}
|
|
}
|
|
|
|
hdcReturn = (*pfn)(strDriver, strDevice, strOutput, pdevmode);
|
|
|
|
if (pdevmode)
|
|
{
|
|
LocalFree(pdevmode);
|
|
}
|
|
|
|
return hdcReturn;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
HDC WINAPI
|
|
CreateDCWrapW(
|
|
LPCWSTR lpszDriver,
|
|
LPCWSTR lpszDevice,
|
|
LPCWSTR lpszOutput,
|
|
CONST DEVMODEW * lpInitData)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateDC);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateDCW(lpszDriver, lpszDevice, lpszOutput, lpInitData);
|
|
}
|
|
return CreateHDCWrapW(lpszDriver, lpszDevice, lpszOutput, lpInitData, CreateDCA);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
HDC WINAPI
|
|
CreateICWrapW(
|
|
LPCWSTR lpszDriver,
|
|
LPCWSTR lpszDevice,
|
|
LPCWSTR lpszOutput,
|
|
CONST DEVMODEW * lpInitData)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateIC);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateICW(lpszDriver, lpszDevice, lpszOutput, lpInitData);
|
|
}
|
|
|
|
return CreateHDCWrapW(lpszDriver, lpszDevice, lpszOutput, lpInitData, CreateICA);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
|
|
#undef CreateDialogIndirectParamW
|
|
|
|
HWND WINAPI
|
|
CreateDialogIndirectParamWrapW(
|
|
HINSTANCE hInstance,
|
|
LPCDLGTEMPLATEW hDialogTemplate,
|
|
HWND hWndParent,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateDialogIndirectParam);
|
|
|
|
if (fDoMungeUI(hInstance))
|
|
{
|
|
return MLCreateDialogIndirectParamI(
|
|
hInstance,
|
|
hDialogTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateDialogIndirectParamW(
|
|
hInstance,
|
|
hDialogTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
return CreateDialogIndirectParamA(
|
|
hInstance,
|
|
hDialogTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
|
|
#undef CreateDialogParamW
|
|
|
|
HWND WINAPI
|
|
CreateDialogParamWrapW(
|
|
HINSTANCE hInstance,
|
|
LPCWSTR lpTemplateName,
|
|
HWND hWndParent,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateDialogParam);
|
|
ASSERT(HIWORD64(lpTemplateName) == 0);
|
|
|
|
if (fDoMungeUI(hInstance))
|
|
return MLCreateDialogParamI(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateDialogParamW(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);
|
|
}
|
|
|
|
return CreateDialogParamA(hInstance, (LPSTR) lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);
|
|
}
|
|
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
CreateDirectoryWrapW(
|
|
LPCWSTR lpPathName,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateDirectory);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateDirectoryW(lpPathName, lpSecurityAttributes);
|
|
}
|
|
|
|
CStrIn str(lpPathName);
|
|
|
|
ASSERT(!lpSecurityAttributes);
|
|
return CreateDirectoryA(str, lpSecurityAttributes);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
CreateEventWrapW(
|
|
LPSECURITY_ATTRIBUTES lpEventAttributes,
|
|
BOOL bManualReset,
|
|
BOOL bInitialState,
|
|
LPCWSTR lpName)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateEvent);
|
|
|
|
//Totally bogus assert.
|
|
//ASSERT(!lpName);
|
|
|
|
// cast means we can't use FORWARD_AW
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName);
|
|
}
|
|
|
|
return CreateEventA(lpEventAttributes, bManualReset, bInitialState, (LPCSTR)lpName);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
CreateFileWrapW(
|
|
LPCWSTR lpFileName,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes,
|
|
HANDLE hTemplateFile)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateFileW(
|
|
lpFileName,
|
|
dwDesiredAccess,
|
|
dwShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
hTemplateFile);
|
|
}
|
|
|
|
CStrIn str(lpFileName);
|
|
|
|
return CreateFileA(
|
|
str,
|
|
dwDesiredAccess,
|
|
dwShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
hTemplateFile);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
HFONT WINAPI
|
|
CreateFontIndirectWrapW(CONST LOGFONTW * plfw)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateFontIndirect);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateFontIndirectW(plfw);
|
|
}
|
|
|
|
LOGFONTA lfa;
|
|
HFONT hFont;
|
|
|
|
memcpy(&lfa, plfw, FIELD_OFFSET(LOGFONTA, lfFaceName));
|
|
SHUnicodeToAnsi(plfw->lfFaceName, lfa.lfFaceName, ARRAYSIZE(lfa.lfFaceName));
|
|
hFont = CreateFontIndirectA(&lfa);
|
|
|
|
return hFont;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HWND WINAPI
|
|
CreateWindowExWrapW(
|
|
DWORD dwExStyle,
|
|
LPCWSTR lpClassName,
|
|
LPCWSTR lpWindowName,
|
|
DWORD dwStyle,
|
|
int X,
|
|
int Y,
|
|
int nWidth,
|
|
int nHeight,
|
|
HWND hWndParent,
|
|
HMENU hMenu,
|
|
HINSTANCE hInstance,
|
|
LPVOID lpParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateWindowEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateWindowExW(
|
|
dwExStyle,
|
|
lpClassName,
|
|
lpWindowName,
|
|
dwStyle,
|
|
X,
|
|
Y,
|
|
nWidth,
|
|
nHeight,
|
|
hWndParent,
|
|
hMenu,
|
|
hInstance,
|
|
lpParam);
|
|
}
|
|
|
|
CStrIn strClass(lpClassName);
|
|
CStrIn strWindow(lpWindowName);
|
|
|
|
return CreateWindowExA(
|
|
dwExStyle,
|
|
strClass,
|
|
strWindow,
|
|
dwStyle,
|
|
X,
|
|
Y,
|
|
nWidth,
|
|
nHeight,
|
|
hWndParent,
|
|
hMenu,
|
|
hInstance,
|
|
lpParam);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LRESULT FORWARD_API WINAPI DefWindowProcWrapW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(DefWindowProc);
|
|
|
|
FORWARD_AW(DefWindowProc, (hWnd, msg, wParam, lParam));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI DeleteFileWrapW(LPCWSTR pwsz)
|
|
{
|
|
VALIDATE_PROTOTYPE(DeleteFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return DeleteFileW(pwsz);
|
|
}
|
|
|
|
CStrIn str(pwsz);
|
|
|
|
return DeleteFileA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#undef DialogBoxIndirectParamW
|
|
|
|
INT_PTR WINAPI
|
|
DialogBoxIndirectParamWrapW(
|
|
HINSTANCE hInstance,
|
|
LPCDLGTEMPLATEW hDialogTemplate,
|
|
HWND hWndParent,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(DialogBoxIndirectParam);
|
|
|
|
if (fDoMungeUI(hInstance))
|
|
return MLDialogBoxIndirectParamI(hInstance, hDialogTemplate, hWndParent, lpDialogFunc, dwInitParam);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return DialogBoxIndirectParamW(
|
|
hInstance,
|
|
hDialogTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
return DialogBoxIndirectParamA(
|
|
hInstance,
|
|
hDialogTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
|
|
#undef DialogBoxParamW
|
|
|
|
INT_PTR WINAPI
|
|
DialogBoxParamWrapW(
|
|
HINSTANCE hInstance,
|
|
LPCWSTR lpszTemplate,
|
|
HWND hWndParent,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(DialogBoxParam);
|
|
ASSERT(HIWORD64(lpszTemplate) == 0);
|
|
|
|
if (fDoMungeUI(hInstance))
|
|
return MLDialogBoxParamI(hInstance, lpszTemplate, hWndParent, lpDialogFunc, dwInitParam);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return DialogBoxParamW(
|
|
hInstance,
|
|
lpszTemplate,
|
|
hWndParent,
|
|
lpDialogFunc,
|
|
dwInitParam);
|
|
}
|
|
|
|
return DialogBoxParamA(hInstance, (LPCSTR) lpszTemplate, hWndParent, lpDialogFunc, dwInitParam);
|
|
}
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LRESULT FORWARD_API WINAPI
|
|
DispatchMessageWrapW(CONST MSG * lpMsg)
|
|
{
|
|
VALIDATE_PROTOTYPE(DispatchMessage);
|
|
|
|
FORWARD_AW(DispatchMessage, (lpMsg));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
BOOL _MayNeedFontLinking(LPCWSTR lpStr, UINT cch)
|
|
{
|
|
#ifndef UNIX
|
|
//
|
|
// Scan the string to see if we might need to use font linking to draw it.
|
|
// If you've got a better way of doing this, I'd love to hear it.
|
|
//
|
|
BOOL fRet = FALSE;
|
|
|
|
int cChars = ((cch == -1) ? lstrlenW(lpStr) : cch);
|
|
|
|
for (int i=0; i < cChars; i++)
|
|
{
|
|
if (lpStr[i] > 127)
|
|
{
|
|
fRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return fRet;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
DrawTextWrapW(
|
|
HDC hDC,
|
|
LPCWSTR lpString,
|
|
int nCount,
|
|
LPRECT lpRect,
|
|
UINT uFormat)
|
|
{
|
|
VALIDATE_PROTOTYPE(DrawText);
|
|
|
|
if (_MayNeedFontLinking(lpString, nCount))
|
|
{
|
|
return DrawTextFLW(hDC, lpString, nCount, lpRect, uFormat);
|
|
}
|
|
else if (g_bRunningOnNT)
|
|
{
|
|
return DrawTextW(hDC, lpString, nCount, lpRect, uFormat);
|
|
}
|
|
CStrIn str(lpString, nCount);
|
|
return DrawTextA(hDC, str, str.strlen(), lpRect, uFormat);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
struct EFFSTAT
|
|
{
|
|
LPARAM lParam;
|
|
FONTENUMPROC lpEnumFontProc;
|
|
BOOL fFamilySpecified;
|
|
};
|
|
|
|
int CALLBACK
|
|
EnumFontFamiliesCallbackWrap(
|
|
ENUMLOGFONTA * lpelf,
|
|
NEWTEXTMETRIC * lpntm,
|
|
DWORD FontType,
|
|
LPARAM lParam)
|
|
{
|
|
ENUMLOGFONTW elf;
|
|
|
|
// Convert strings from ANSI to Unicode
|
|
if (((EFFSTAT *)lParam)->fFamilySpecified && (FontType & TRUETYPE_FONTTYPE) )
|
|
{
|
|
// LPBYTE->LPCSTR cast below
|
|
SHAnsiToUnicode((LPCSTR)lpelf->elfFullName, elf.elfFullName, ARRAYSIZE(elf.elfFullName));
|
|
SHAnsiToUnicode((LPCSTR)lpelf->elfStyle, elf.elfStyle, ARRAYSIZE(elf.elfStyle));
|
|
}
|
|
else
|
|
{
|
|
elf.elfStyle[0] = L'\0';
|
|
elf.elfFullName[0] = L'\0';
|
|
}
|
|
|
|
SHAnsiToUnicode(lpelf->elfLogFont.lfFaceName, elf.elfLogFont.lfFaceName, ARRAYSIZE(elf.elfLogFont.lfFaceName));
|
|
|
|
// Copy the non-string data
|
|
memcpy(
|
|
&elf.elfLogFont,
|
|
&lpelf->elfLogFont,
|
|
FIELD_OFFSET(LOGFONTA, lfFaceName));
|
|
|
|
// Chain to the original callback function
|
|
return (*((EFFSTAT *) lParam)->lpEnumFontProc)(
|
|
(const LOGFONTW *)&elf,
|
|
(const TEXTMETRICW *) lpntm,
|
|
FontType,
|
|
((EFFSTAT *) lParam)->lParam);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
int WINAPI
|
|
EnumFontFamiliesWrapW(
|
|
HDC hdc,
|
|
LPCWSTR lpszFamily,
|
|
FONTENUMPROC lpEnumFontProc,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(EnumFontFamilies);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return EnumFontFamiliesW(
|
|
hdc,
|
|
lpszFamily,
|
|
lpEnumFontProc,
|
|
lParam);
|
|
}
|
|
|
|
CStrIn str(lpszFamily);
|
|
EFFSTAT effstat;
|
|
|
|
effstat.lParam = lParam;
|
|
effstat.lpEnumFontProc = lpEnumFontProc;
|
|
effstat.fFamilySpecified = lpszFamily != NULL;
|
|
|
|
return EnumFontFamiliesA(
|
|
hdc,
|
|
str,
|
|
(FONTENUMPROCA) EnumFontFamiliesCallbackWrap,
|
|
(LPARAM) &effstat);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
int WINAPI
|
|
EnumFontFamiliesExWrapW(
|
|
HDC hdc,
|
|
LPLOGFONTW lplfw,
|
|
FONTENUMPROC lpEnumFontProc,
|
|
LPARAM lParam,
|
|
DWORD dwFlags )
|
|
{
|
|
VALIDATE_PROTOTYPE(EnumFontFamiliesEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return EnumFontFamiliesExW(
|
|
hdc,
|
|
lplfw,
|
|
lpEnumFontProc,
|
|
lParam,
|
|
dwFlags);
|
|
}
|
|
|
|
LOGFONTA lfa;
|
|
CStrIn str(lplfw->lfFaceName);
|
|
EFFSTAT effstat;
|
|
|
|
ASSERT( FIELD_OFFSET(LOGFONTW, lfFaceName) == FIELD_OFFSET(LOGFONTA, lfFaceName) );
|
|
|
|
memcpy( &lfa, lplfw, sizeof(LOGFONTA) - FIELD_OFFSET(LOGFONTA, lfFaceName) );
|
|
memcpy( lfa.lfFaceName, str, LF_FACESIZE );
|
|
lfa.lfFaceName[LF_FACESIZE - 1] = 0x00;
|
|
|
|
effstat.lParam = lParam;
|
|
effstat.lpEnumFontProc = lpEnumFontProc;
|
|
effstat.fFamilySpecified = lplfw->lfFaceName != NULL;
|
|
|
|
return EnumFontFamiliesExA(
|
|
hdc,
|
|
&lfa,
|
|
(FONTENUMPROCA) EnumFontFamiliesCallbackWrap,
|
|
(LPARAM) &effstat,
|
|
dwFlags );
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
EnumResourceNamesWrapW(
|
|
HINSTANCE hModule,
|
|
LPCWSTR lpType,
|
|
ENUMRESNAMEPROCW lpEnumFunc,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(EnumResourceNames);
|
|
ASSERT(HIWORD64(lpType) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return EnumResourceNamesW(hModule, lpType, lpEnumFunc, lParam);
|
|
}
|
|
|
|
return EnumResourceNamesA(hModule, (LPCSTR) lpType, (ENUMRESNAMEPROCA)lpEnumFunc, lParam);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
FindFirstFileWrapW(
|
|
LPCWSTR lpFileName,
|
|
LPWIN32_FIND_DATAW pwszFd)
|
|
{
|
|
VALIDATE_PROTOTYPE(FindFirstFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return FindFirstFileW(lpFileName, pwszFd);
|
|
}
|
|
|
|
CStrIn str(lpFileName);
|
|
CWin32FindDataInOut fd(pwszFd);
|
|
|
|
return FindFirstFileA(str, fd);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HRSRC WINAPI
|
|
FindResourceWrapW(HINSTANCE hModule, LPCWSTR lpName, LPCWSTR lpType)
|
|
{
|
|
VALIDATE_PROTOTYPE(FindResource);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return FindResourceW(hModule, lpName, lpType);
|
|
}
|
|
|
|
// NOTE: The FindResourceW exists on Win9x, but Win95 and Win98
|
|
// have a bug where they make two bogus call to LocalFree to try
|
|
// to free up the passed-in buffers that they did not allocate.
|
|
//
|
|
// We work around by always wrapping. Another solution that Godot uses:
|
|
//
|
|
// For win95/98 only:
|
|
// 1) Copy the two params to stack-alloc'ed variables
|
|
// 2) Call the "W" function with the variables from step #1
|
|
// 3) Clear out last error when it is ERROR_INVALID_HANDLE (the error that the
|
|
// bogus LocalFree call in the OS will cause
|
|
// This gives proper Unicode behavior to both functions on all Win9x platforms.
|
|
|
|
CStrIn strName(lpName);
|
|
CStrIn strType(lpType);
|
|
|
|
return FindResourceA(hModule, strName, strType);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HWND WINAPI
|
|
FindWindowWrapW(LPCWSTR lpClassName, LPCWSTR lpWindowName)
|
|
{
|
|
VALIDATE_PROTOTYPE(FindWindow);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return FindWindowW(lpClassName, lpWindowName);
|
|
}
|
|
|
|
// Let FindWindowExWrapW do the thunking
|
|
return FindWindowExWrapW(NULL, NULL, lpClassName, lpWindowName);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HWND WINAPI
|
|
FindWindowExWrapW(HWND hwndParent, HWND hwndChildAfter, LPCWSTR pwzClassName, LPCWSTR pwzWindowName)
|
|
{
|
|
VALIDATE_PROTOTYPE(FindWindowEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
return FindWindowExW(hwndParent, hwndChildAfter, pwzClassName, pwzWindowName);
|
|
|
|
|
|
CStrIn strClass(pwzClassName);
|
|
CStrIn strWindow(pwzWindowName);
|
|
|
|
return FindWindowExA(hwndParent, hwndChildAfter, strClass, strWindow);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
//
|
|
// FindNextArgInfo - Finds the argument format and argument number from a FormatMessage like template
|
|
//
|
|
// Returns - True if arg is wide string, False if other
|
|
//
|
|
BOOL FindNextArgInfo(LPCWSTR *pszTemplate, UINT *puiNum, LPWSTR pszFormat, UINT cchFormat)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
if(*pszTemplate == NULL)
|
|
return(FALSE);
|
|
|
|
LPCWSTR psz = *pszTemplate;
|
|
LPCWSTR pszT1 = NULL;
|
|
LPCWSTR pszT2 = NULL;
|
|
LPWSTR pszFmt = pszFormat;
|
|
BOOL fHaveStart = FALSE;
|
|
UINT cchFmt;
|
|
|
|
*puiNum = 0;
|
|
|
|
if(cchFormat > 0)
|
|
{
|
|
*pszFmt = TEXT('%');
|
|
pszFmt++;
|
|
cchFormat--;
|
|
}
|
|
|
|
if(*psz >= TEXT('1') && *psz <= TEXT('9'))
|
|
{
|
|
for(; *psz; psz++)
|
|
{
|
|
if(*psz == TEXT('!'))
|
|
{
|
|
if(fHaveStart) // Done
|
|
{
|
|
pszT2 = ++psz; // Mark end of type
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
fHaveStart = TRUE;
|
|
psz++;
|
|
if(pszT1 == NULL)
|
|
pszT1 = psz; // Mark start of arg format string
|
|
}
|
|
}
|
|
|
|
if(!fHaveStart) // Get arg number
|
|
{
|
|
if(*psz >= TEXT('0') && *psz <= TEXT('9'))
|
|
*puiNum = (*puiNum * 10) + (*psz - TEXT('0'));
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(*puiNum == 0)
|
|
return(FALSE);
|
|
}
|
|
else // Special format specifier
|
|
{
|
|
pszT1 = psz;
|
|
pszT2 = psz+1;
|
|
}
|
|
|
|
if(pszT1 != NULL) // We have an arg format string
|
|
{
|
|
cchFmt = cchFormat;
|
|
if(cchFmt > (UINT)(pszT2 - pszT1))
|
|
cchFmt = (pszT2 - pszT1);
|
|
StrCpyN(pszFmt, pszT1, cchFmt);
|
|
|
|
// Is argument type a string
|
|
if(StrChrI(pszFormat, TEXT('s')))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
cchFmt = cchFormat;
|
|
if(cchFmt > (UINT)(pszT2 - *pszTemplate)+1)
|
|
cchFmt = (pszT2 - *pszTemplate)+1;
|
|
StrCpyN(pszFmt, *pszTemplate, cchFmt);
|
|
}
|
|
}
|
|
else // No arg format string, FormatMessage default is !s!
|
|
{
|
|
pszT2 = psz;
|
|
fRet = TRUE;
|
|
cchFmt = cchFormat;
|
|
if(cchFmt > 3)
|
|
cchFmt = 3;
|
|
StrCpyN(pszFmt, TEXT("ws"), cchFmt);
|
|
}
|
|
|
|
*pszTemplate = pszT2; // Move template string beyond this format specifier
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
//
|
|
// The following is used to work around Win9x FormatMessage problems related to converting
|
|
// DBCS strings to Unicode.
|
|
//
|
|
#define FML_BUFFER_SIZE 1024
|
|
#define FML_BUFFER_INC 256
|
|
|
|
DWORD
|
|
FormatMessageLiteW(
|
|
DWORD dwFlags,
|
|
LPCWSTR lpSource,
|
|
PVOID * pDest,
|
|
DWORD nSize,
|
|
va_list * Arguments)
|
|
{
|
|
BOOL fIsStr;
|
|
UINT uiNum;
|
|
UINT uiDataCnt = 0;
|
|
va_list pArgList = *Arguments;
|
|
va_list pArgList2;
|
|
WCHAR *pszBuf2;
|
|
WCHAR szFmt[256];
|
|
VOID *pData[10];
|
|
LPCWSTR psz = lpSource;
|
|
LPCWSTR psz1 = NULL;
|
|
LPWSTR lpBuffer;
|
|
INT cchBufUsed = 0;
|
|
INT cchBuf2;
|
|
INT cch;
|
|
|
|
if(lpSource == NULL || pDest == NULL || Arguments == NULL)
|
|
return(0);
|
|
|
|
if(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
nSize = max(nSize, FML_BUFFER_SIZE);
|
|
if((lpBuffer = (WCHAR *)LocalAlloc(LPTR, nSize * sizeof(WCHAR))) == NULL)
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
if(nSize == 0)
|
|
return(0);
|
|
lpBuffer = (LPWSTR)pDest;
|
|
}
|
|
|
|
cchBuf2 = nSize + lstrlen(lpSource);
|
|
if((pszBuf2 = (WCHAR *)LocalAlloc(LPTR, cchBuf2 * sizeof(WCHAR))) != NULL)
|
|
{
|
|
*lpBuffer = TEXT('\0');
|
|
while(*psz)
|
|
{
|
|
if(*psz == TEXT('%'))
|
|
{
|
|
psz++;
|
|
if(psz1 != NULL) // Copy any previous text to the buffer
|
|
{
|
|
if((cch = psz - psz1) > (INT)(nSize - cchBufUsed))
|
|
{
|
|
if(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
LPWSTR lpRealloc;
|
|
nSize = max(FML_BUFFER_INC, cch);
|
|
if((lpRealloc = (WCHAR *)LocalReAlloc(lpBuffer, nSize * sizeof(WCHAR), LMEM_ZEROINIT | LMEM_MOVEABLE)) == NULL)
|
|
{
|
|
LocalFree(lpBuffer);
|
|
LocalFree(pszBuf2);
|
|
return(0);
|
|
}
|
|
lpBuffer = lpRealloc;
|
|
}
|
|
else
|
|
{
|
|
RIPMSG(FALSE, "Output buffer not large enough. Truncating.");
|
|
cch = nSize - cchBufUsed;
|
|
}
|
|
}
|
|
StrCpyNW(lpBuffer+cchBufUsed, psz1, cch);
|
|
cchBufUsed += cch-1;
|
|
psz1 = NULL;
|
|
}
|
|
|
|
fIsStr = FindNextArgInfo(&psz, &uiNum, szFmt, ARRAYSIZE(szFmt));
|
|
|
|
if(fIsStr)
|
|
{
|
|
if(uiNum > uiDataCnt)
|
|
{
|
|
for(UINT i = uiDataCnt; i < uiNum; i++) // Find the iTH argument
|
|
{
|
|
pData[i] = va_arg(pArgList, VOID *);
|
|
uiDataCnt++;
|
|
}
|
|
}
|
|
|
|
cch = wnsprintfW(pszBuf2, cchBuf2, szFmt, pData[uiNum-1]);
|
|
if(cch == cchBuf2)
|
|
{
|
|
RIPMSG(FALSE, "Param buffer may be too small. Output string may be truncated.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Call FormatMessage on non-string arguments
|
|
pArgList2 = *Arguments;
|
|
CStrIn strSource(CP_ACP, (LPCWSTR)szFmt, -1);
|
|
CStrOut str(pszBuf2, cchBuf2);
|
|
FormatMessageA(FORMAT_MESSAGE_FROM_STRING, strSource, 0, 0, str, str.BufSize(), &pArgList2);
|
|
cch = str.ConvertExcludingNul();
|
|
}
|
|
|
|
if(cch > 0)
|
|
{
|
|
if(cch > (INT)(nSize - cchBufUsed))
|
|
{
|
|
if(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
LPWSTR lpRealloc;
|
|
nSize += max(FML_BUFFER_INC, cch);
|
|
if((lpRealloc = (WCHAR *)LocalReAlloc(lpBuffer, nSize * sizeof(WCHAR), LMEM_ZEROINIT | LMEM_MOVEABLE)) == NULL)
|
|
{
|
|
LocalFree(lpBuffer);
|
|
LocalFree(pszBuf2);
|
|
return(0);
|
|
}
|
|
lpBuffer = lpRealloc;
|
|
}
|
|
else
|
|
{
|
|
RIPMSG(FALSE, "Output buffer not large enough. Truncating.");
|
|
cch = nSize - cchBufUsed;
|
|
}
|
|
}
|
|
StrCpyW(lpBuffer+cchBufUsed, pszBuf2);
|
|
cchBufUsed += cch;
|
|
}
|
|
else
|
|
{
|
|
RIPMSG(FALSE, "Argument string conversion failed. Argument not copied to output buffer");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(psz1 == NULL)
|
|
psz1 = psz; // Start of text block
|
|
|
|
psz++;
|
|
}
|
|
|
|
if(psz1) // Copy any remaining text to the output buffer
|
|
{
|
|
if((cch = (psz - psz1)+1) > (INT)(nSize - cchBufUsed))
|
|
{
|
|
if(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
LPWSTR lpRealloc;
|
|
nSize = max(FML_BUFFER_INC, cch);
|
|
if((lpRealloc = (WCHAR *)LocalReAlloc(lpBuffer, nSize * sizeof(WCHAR), LMEM_ZEROINIT | LMEM_MOVEABLE)) == NULL)
|
|
{
|
|
LocalFree(lpBuffer);
|
|
LocalFree(pszBuf2);
|
|
return(0);
|
|
}
|
|
lpBuffer = lpRealloc;
|
|
}
|
|
else
|
|
{
|
|
RIPMSG(FALSE, "Output buffer not large enough. Truncating.");
|
|
cch = nSize - cchBufUsed;
|
|
}
|
|
}
|
|
StrCpyNW(lpBuffer+cchBufUsed, psz1, cch);
|
|
cchBufUsed += cch - 1; // substract the null from the count
|
|
}
|
|
|
|
LocalFree(pszBuf2);
|
|
pszBuf2 = NULL;
|
|
}
|
|
|
|
if(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
*pDest = (PVOID *)lpBuffer;
|
|
}
|
|
|
|
return((DWORD)cchBufUsed);
|
|
}
|
|
|
|
DWORD WINAPI
|
|
FormatMessageWrapW(
|
|
DWORD dwFlags,
|
|
LPCVOID lpSource,
|
|
DWORD dwMessageId,
|
|
DWORD dwLanguageId,
|
|
LPWSTR lpBuffer,
|
|
DWORD nSize,
|
|
va_list * Arguments)
|
|
{
|
|
VALIDATE_PROTOTYPE(FormatMessage);
|
|
if (!(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER))
|
|
{
|
|
VALIDATE_OUTBUF(lpBuffer, nSize);
|
|
}
|
|
|
|
DWORD dwResult;
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
dwResult = FormatMessageW(
|
|
dwFlags,
|
|
lpSource,
|
|
dwMessageId,
|
|
dwLanguageId,
|
|
lpBuffer,
|
|
nSize,
|
|
Arguments);
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
// If a source string is passed, make sure that all string insertions
|
|
// have explicit character set markers. Otherwise, you get random
|
|
// behavior depending on whether we need to thunk to ANSI or not.
|
|
// (We are not clever enough to thunk the inserts; that's the caller's
|
|
// responsibility.)
|
|
//
|
|
if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
|
|
{
|
|
LPCWSTR pwsz;
|
|
for (pwsz = (LPCWSTR)lpSource; *pwsz; pwsz++)
|
|
{
|
|
if (*pwsz == L'%')
|
|
{
|
|
pwsz++;
|
|
// Found an insertion. Get the digit or two.
|
|
if (*pwsz == L'0')
|
|
continue; // "%0" is special
|
|
if (*pwsz < L'0' || *pwsz > L'9')
|
|
continue; // skip % followed by nondigit
|
|
pwsz++; // Skip the digit
|
|
if (*pwsz >= L'0' && *pwsz <= L'9')
|
|
pwsz++; // Skip the optional second digit
|
|
// The next character MUST be an exclamation point!
|
|
ASSERT(*pwsz == L'!' &&
|
|
"FormatMessageWrapW: All string insertions must have explicit character sets.");
|
|
// I'm not going to validate that the insertion contains
|
|
// an explicit character set override because if you went
|
|
// so far as to do a %n!...!, you'll get the last bit right too.
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// FORMAT_MESSAGE_FROM_STRING means that the source is a string.
|
|
// Otherwise, it's an opaque LPVOID (aka, an atom).
|
|
//
|
|
if(((dwFlags == FORMAT_MESSAGE_FROM_STRING) ||
|
|
(dwFlags == (FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER))) &&
|
|
(dwMessageId == 0) && (dwLanguageId == 0))
|
|
{
|
|
TraceMsg(TF_WARNING, "This is a lite version of FormatMessage. It may not act as you expect.");
|
|
dwResult = FormatMessageLiteW(dwFlags, (LPCWSTR)lpSource, (PVOID *)lpBuffer, nSize, Arguments);
|
|
}
|
|
else
|
|
{
|
|
CStrIn strSource((dwFlags & FORMAT_MESSAGE_FROM_STRING) ? CP_ACP : CP_ATOM,
|
|
(LPCWSTR)lpSource, -1);
|
|
|
|
if (!(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER))
|
|
{
|
|
CStrOut str(lpBuffer, nSize);
|
|
FormatMessageA(
|
|
dwFlags,
|
|
strSource,
|
|
dwMessageId,
|
|
dwLanguageId,
|
|
str,
|
|
str.BufSize(),
|
|
Arguments); // We don't handle Arguments != NULL
|
|
|
|
dwResult = str.ConvertExcludingNul();
|
|
}
|
|
else
|
|
{
|
|
LPSTR pszBuffer = NULL;
|
|
LPWSTR * ppwzOut = (LPWSTR *)lpBuffer;
|
|
|
|
*ppwzOut = NULL;
|
|
FormatMessageA(
|
|
dwFlags,
|
|
strSource,
|
|
dwMessageId,
|
|
dwLanguageId,
|
|
(LPSTR)&pszBuffer,
|
|
0,
|
|
Arguments);
|
|
|
|
if (pszBuffer)
|
|
{
|
|
DWORD cchSize = (lstrlenA(pszBuffer) + 1);
|
|
LPWSTR pszThunkedBuffer;
|
|
|
|
if (cchSize < nSize)
|
|
cchSize = nSize;
|
|
|
|
pszThunkedBuffer = (LPWSTR) LocalAlloc(LPTR, cchSize * sizeof(WCHAR));
|
|
if (pszThunkedBuffer)
|
|
{
|
|
*ppwzOut = pszThunkedBuffer;
|
|
SHAnsiToUnicode(pszBuffer, pszThunkedBuffer, cchSize);
|
|
}
|
|
|
|
LocalFree(pszBuffer);
|
|
}
|
|
dwResult = (*ppwzOut ? lstrlenW(*ppwzOut) : 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
GetClassInfoWrapW(HINSTANCE hModule, LPCWSTR lpClassName, LPWNDCLASSW lpWndClassW)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetClassInfo);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetClassInfoW(hModule, lpClassName, lpWndClassW);
|
|
}
|
|
|
|
BOOL ret;
|
|
|
|
CStrIn strClassName(lpClassName);
|
|
|
|
ASSERT(sizeof(WNDCLASSA) == sizeof(WNDCLASSW));
|
|
|
|
ret = GetClassInfoA(hModule, strClassName, (LPWNDCLASSA) lpWndClassW);
|
|
|
|
lpWndClassW->lpszMenuName = NULL;
|
|
lpWndClassW->lpszClassName = NULL;
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
DWORD FORWARD_API WINAPI
|
|
GetClassLongWrapW(HWND hWnd, int nIndex)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetClassLong);
|
|
|
|
FORWARD_AW(GetClassLong, (hWnd, nIndex));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetClassNameWrapW(HWND hWnd, LPWSTR lpClassName, int nMaxCount)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetClassName);
|
|
VALIDATE_OUTBUF(lpClassName, nMaxCount);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetClassNameW(hWnd, lpClassName, nMaxCount);
|
|
}
|
|
|
|
CStrOut strClassName(lpClassName, nMaxCount);
|
|
|
|
GetClassNameA(hWnd, strClassName, strClassName.BufSize());
|
|
return strClassName.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetClipboardFormatNameWrapW(UINT format, LPWSTR lpFormatName, int cchFormatName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetClipboardFormatName);
|
|
VALIDATE_OUTBUF(lpFormatName, cchFormatName);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetClipboardFormatNameW(format, lpFormatName, cchFormatName);
|
|
}
|
|
|
|
CStrOut strFormatName(lpFormatName, cchFormatName);
|
|
|
|
GetClipboardFormatNameA(format, strFormatName, strFormatName.BufSize());
|
|
return strFormatName.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetCurrentDirectoryWrapW(DWORD nBufferLength, LPWSTR lpBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetCurrentDirectory);
|
|
VALIDATE_OUTBUF(lpBuffer, nBufferLength);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetCurrentDirectoryW(nBufferLength, lpBuffer);
|
|
}
|
|
|
|
CStrOut str(lpBuffer, nBufferLength);
|
|
|
|
GetCurrentDirectoryA(str.BufSize(), str);
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
GetDlgItemTextWrapW(
|
|
HWND hWndDlg,
|
|
int idControl,
|
|
LPWSTR lpsz,
|
|
int cchMax)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetDlgItemText);
|
|
VALIDATE_OUTBUF(lpsz, cchMax);
|
|
|
|
HWND hWnd = GetDlgItem(hWndDlg, idControl);
|
|
|
|
if (hWnd)
|
|
return GetWindowTextWrapW(hWnd, lpsz, cchMax);
|
|
|
|
/*
|
|
* If we couldn't find the window, just null terminate lpch so that the
|
|
* app doesn't gp fault if it tries to run through the text.
|
|
*/
|
|
if (cchMax)
|
|
*lpsz = (WCHAR)0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetFileAttributesWrapW(LPCWSTR lpFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetFileAttributes);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetFileAttributesW(lpFileName);
|
|
}
|
|
|
|
CStrIn str(lpFileName);
|
|
|
|
return GetFileAttributesA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetLocaleInfoWrapW(LCID Locale, LCTYPE LCType, LPWSTR lpsz, int cchData)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetLocaleInfo);
|
|
VALIDATE_OUTBUF(lpsz, cchData);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetLocaleInfoW(Locale, LCType, lpsz, cchData);
|
|
}
|
|
|
|
CStrOut str(lpsz, cchData);
|
|
|
|
GetLocaleInfoA(Locale, LCType, str, str.BufSize());
|
|
return str.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL FORWARD_API WINAPI
|
|
GetMessageWrapW(
|
|
LPMSG lpMsg,
|
|
HWND hWnd,
|
|
UINT wMsgFilterMin,
|
|
UINT wMsgFilterMax)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetMessage);
|
|
|
|
FORWARD_AW(GetMessage, (lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetModuleFileNameWrapW(HINSTANCE hModule, LPWSTR pwszFilename, DWORD nSize)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetModuleFileName);
|
|
VALIDATE_OUTBUF(pwszFilename, nSize);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetModuleFileNameW(hModule, pwszFilename, nSize);
|
|
}
|
|
|
|
CStrOut str(pwszFilename, nSize);
|
|
|
|
GetModuleFileNameA(hModule, str, str.BufSize());
|
|
return str.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
GetSystemDirectoryWrapW(LPWSTR lpBuffer, UINT uSize)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetSystemDirectory);
|
|
VALIDATE_OUTBUF(lpBuffer, uSize);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetSystemDirectoryW(lpBuffer, uSize);
|
|
}
|
|
|
|
CStrOut str(lpBuffer, uSize);
|
|
|
|
GetSystemDirectoryA(str, str.BufSize());
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
SearchPathWrapW(
|
|
LPCWSTR lpPathName,
|
|
LPCWSTR lpFileName,
|
|
LPCWSTR lpExtension,
|
|
DWORD cchReturnBuffer,
|
|
LPWSTR lpReturnBuffer,
|
|
LPWSTR * plpfilePart)
|
|
{
|
|
VALIDATE_PROTOTYPE(SearchPath);
|
|
VALIDATE_OUTBUF(lpReturnBuffer, cchReturnBuffer);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SearchPathW(
|
|
lpPathName,
|
|
lpFileName,
|
|
lpExtension,
|
|
cchReturnBuffer,
|
|
lpReturnBuffer,
|
|
plpfilePart);
|
|
}
|
|
|
|
CStrIn strPath(lpPathName);
|
|
CStrIn strFile(lpFileName);
|
|
CStrIn strExtension(lpExtension);
|
|
CStrOut strReturnBuffer(lpReturnBuffer, cchReturnBuffer);
|
|
|
|
DWORD dwLen = SearchPathA(
|
|
strPath,
|
|
strFile,
|
|
strExtension,
|
|
strReturnBuffer.BufSize(),
|
|
strReturnBuffer,
|
|
(LPSTR *)plpfilePart);
|
|
|
|
//
|
|
// Getting the correct value for plpfilePart requires
|
|
// a strrchr on the converted string. If this value
|
|
// is needed, just add the code to do it here.
|
|
//
|
|
|
|
*plpfilePart = NULL;
|
|
|
|
if (cchReturnBuffer == 0)
|
|
dwLen = 2*dwLen;
|
|
else
|
|
dwLen = strReturnBuffer.ConvertExcludingNul();
|
|
|
|
return dwLen;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HMODULE WINAPI
|
|
GetModuleHandleWrapW(LPCWSTR lpModuleName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetModuleHandle);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetModuleHandleW(lpModuleName);
|
|
}
|
|
|
|
CStrIn str(lpModuleName);
|
|
return GetModuleHandleA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetObjectWrapW(HGDIOBJ hgdiObj, int cbBuffer, LPVOID lpvObj)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetObject);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetObjectW(hgdiObj, cbBuffer, lpvObj);
|
|
}
|
|
|
|
int nRet;
|
|
|
|
if(cbBuffer != sizeof(LOGFONTW))
|
|
{
|
|
nRet = GetObjectA(hgdiObj, cbBuffer, lpvObj);
|
|
}
|
|
else
|
|
{
|
|
LOGFONTA lfa;
|
|
|
|
nRet = GetObjectA(hgdiObj, sizeof(lfa), &lfa);
|
|
if (nRet > 0)
|
|
{
|
|
memcpy(lpvObj, &lfa, FIELD_OFFSET(LOGFONTW, lfFaceName));
|
|
SHAnsiToUnicode(lfa.lfFaceName, ((LOGFONTW*)lpvObj)->lfFaceName, ARRAYSIZE(((LOGFONTW*)lpvObj)->lfFaceName));
|
|
nRet = sizeof(LOGFONTW);
|
|
}
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW pbiW)
|
|
{
|
|
if (UseUnicodeShell32())
|
|
{
|
|
return SHBrowseForFolderW(pbiW);
|
|
}
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
ASSERT(pbiW);
|
|
if (pbiW)
|
|
{
|
|
CStrIn strTitle(pbiW->lpszTitle);
|
|
CStrOut strDisplayName(pbiW->pszDisplayName, MAX_PATH);
|
|
BROWSEINFOA biA;
|
|
|
|
biA = * (LPBROWSEINFOA) pbiW;
|
|
biA.lpszTitle = strTitle;
|
|
biA.pszDisplayName = strDisplayName;
|
|
|
|
pidl = SHBrowseForFolderA(&biA);
|
|
if (pidl)
|
|
{
|
|
strDisplayName.ConvertIncludingNul();
|
|
}
|
|
}
|
|
|
|
return pidl;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl, LPWSTR pwzPath)
|
|
{
|
|
if (UseUnicodeShell32())
|
|
{
|
|
return SHGetPathFromIDListW(pidl, pwzPath);
|
|
}
|
|
|
|
CStrOut strPathOut(pwzPath, MAX_PATH);
|
|
BOOL fResult = SHGetPathFromIDListA(pidl, strPathOut);
|
|
if (fResult)
|
|
{
|
|
strPathOut.ConvertIncludingNul();
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW pExecInfoW)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return ShellExecuteExW(pExecInfoW);
|
|
}
|
|
|
|
BOOL fResult = FALSE;
|
|
ASSERT(pExecInfoW);
|
|
if (pExecInfoW)
|
|
{
|
|
SHELLEXECUTEINFOA ExecInfoA;
|
|
|
|
CStrIn strVerb(pExecInfoW->lpVerb);
|
|
CStrIn strParameters(pExecInfoW->lpParameters);
|
|
CStrIn strDirectory(pExecInfoW->lpDirectory);
|
|
CStrIn strClass(pExecInfoW->lpClass);
|
|
CHAR szFile[MAX_PATH + INTERNET_MAX_URL_LENGTH + 2];
|
|
|
|
|
|
ExecInfoA = *(LPSHELLEXECUTEINFOA) pExecInfoW;
|
|
ExecInfoA.lpVerb = strVerb;
|
|
ExecInfoA.lpParameters = strParameters;
|
|
ExecInfoA.lpDirectory = strDirectory;
|
|
ExecInfoA.lpClass = strClass;
|
|
|
|
if (pExecInfoW->lpFile)
|
|
{
|
|
ExecInfoA.lpFile = szFile;
|
|
SHUnicodeToAnsi(pExecInfoW->lpFile, szFile, ARRAYSIZE(szFile));
|
|
|
|
// SEE_MASK_FILEANDURL passes "file\0url". What a hack!
|
|
if (pExecInfoW->fMask & SEE_MASK_FILEANDURL)
|
|
{
|
|
// We are so lucky that Win9x implements lstrlenW
|
|
int cch = lstrlenW(pExecInfoW->lpFile) + 1;
|
|
cch += lstrlenW(pExecInfoW->lpFile + cch) + 1;
|
|
if (!WideCharToMultiByte(CP_ACP, 0, pExecInfoW->lpFile, cch, szFile, ARRAYSIZE(szFile), NULL, NULL))
|
|
{
|
|
// Return a completely random error code
|
|
pExecInfoW->hInstApp = (HINSTANCE)SE_ERR_OOM;
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
fResult = ShellExecuteExA(&ExecInfoA);
|
|
|
|
// Out parameters
|
|
pExecInfoW->hInstApp = ExecInfoA.hInstApp;
|
|
pExecInfoW->hProcess = ExecInfoA.hProcess;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
int WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW pFileOpW)
|
|
{
|
|
// We don't thunk multiple files.
|
|
ASSERT(pFileOpW);
|
|
ASSERT(!(pFileOpW->fFlags & FOF_MULTIDESTFILES));
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
return SHFileOperationW(pFileOpW);
|
|
}
|
|
|
|
int nResult = 1; // non-Zero is failure.
|
|
if (pFileOpW)
|
|
{
|
|
SHFILEOPSTRUCTA FileOpA;
|
|
CStrIn strTo(pFileOpW->pTo);
|
|
CStrIn strFrom(pFileOpW->pFrom);
|
|
CStrIn strProgressTitle(pFileOpW->lpszProgressTitle);
|
|
|
|
FileOpA = *(LPSHFILEOPSTRUCTA) pFileOpW;
|
|
FileOpA.pFrom = strFrom;
|
|
FileOpA.pTo = strTo;
|
|
FileOpA.lpszProgressTitle = strProgressTitle;
|
|
|
|
|
|
nResult = SHFileOperationA(&FileOpA);
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
UINT WINAPI ExtractIconExWrapW(LPCWSTR pwzFile, int nIconIndex, HICON FAR *phiconLarge, HICON FAR *phiconSmall, UINT nIcons)
|
|
{
|
|
if (UseUnicodeShell32())
|
|
{
|
|
return ExtractIconExW(pwzFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
|
|
}
|
|
|
|
CStrIn str(pwzFile);
|
|
return ExtractIconExA(str, nIconIndex, phiconLarge, phiconSmall, nIcons);
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
//
|
|
// Shell_GetCachedImageIndexWrapA/W are exported from shlwapi.
|
|
// Only the W version should be in NEED_SHELL32_WRAPPER
|
|
int WINAPI Shell_GetCachedImageIndexWrapW(LPCWSTR pszIconPath, int iIconIndex, UINT uIconFlags)
|
|
{
|
|
if (UseUnicodeShell32())
|
|
{
|
|
return Shell_GetCachedImageIndex(pszIconPath, iIconIndex, uIconFlags);
|
|
}
|
|
|
|
CStrIn strIconPath(pszIconPath);
|
|
return Shell_GetCachedImageIndex((LPCWSTR)((void*)(strIconPath)), iIconIndex, uIconFlags);
|
|
}
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
int WINAPI Shell_GetCachedImageIndexWrapA(LPCSTR pszIconPath, int iIconIndex, UINT uIconFlags)
|
|
{
|
|
if (UseUnicodeShell32())
|
|
{
|
|
WCHAR szIconPath[MAX_PATH];
|
|
SHAnsiToUnicode(pszIconPath, szIconPath, ARRAYSIZE(szIconPath));
|
|
return Shell_GetCachedImageIndex(szIconPath, iIconIndex, uIconFlags);
|
|
}
|
|
|
|
return Shell_GetCachedImageIndex((LPCWSTR)((void*)(pszIconPath)), iIconIndex, uIconFlags);
|
|
}
|
|
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI SetFileAttributesWrapW(LPCWSTR pwzFile, DWORD dwFileAttributes)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetFileAttributes);
|
|
|
|
if (g_bRunningOnNT)
|
|
return SetFileAttributesW(pwzFile, dwFileAttributes);
|
|
|
|
CStrIn str(pwzFile);
|
|
return SetFileAttributesA(str, dwFileAttributes);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
int WINAPI GetNumberFormatWrapW(LCID Locale, DWORD dwFlags, LPCWSTR pwzValue, CONST NUMBERFMTW * pFormatW, LPWSTR pwzNumberStr, int cchNumber)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetNumberFormat);
|
|
|
|
if (g_bRunningOnNT)
|
|
return GetNumberFormatW(Locale, dwFlags, pwzValue, pFormatW, pwzNumberStr, cchNumber);
|
|
|
|
int nResult;
|
|
NUMBERFMTA FormatA;
|
|
CStrIn strValue(pwzValue);
|
|
CStrIn strDecimalSep(pFormatW ? pFormatW->lpDecimalSep : NULL);
|
|
CStrIn strThousandSep(pFormatW ? pFormatW->lpThousandSep : NULL);
|
|
CStrOut strNumberStr(pwzNumberStr, cchNumber);
|
|
|
|
if (pFormatW)
|
|
{
|
|
FormatA = *(NUMBERFMTA *) pFormatW;
|
|
FormatA.lpDecimalSep = strDecimalSep;
|
|
FormatA.lpThousandSep = strThousandSep;
|
|
}
|
|
|
|
nResult = GetNumberFormatA(Locale, dwFlags, strValue, (pFormatW ? &FormatA : NULL), strNumberStr, strNumberStr.BufSize());
|
|
if (ERROR_SUCCESS == nResult)
|
|
strNumberStr.ConvertIncludingNul();
|
|
|
|
return nResult;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI MessageBoxWrapW(HWND hwnd, LPCWSTR pwzText, LPCWSTR pwzCaption, UINT uType)
|
|
{
|
|
VALIDATE_PROTOTYPE(MessageBox);
|
|
|
|
if (g_bRunningOnNT)
|
|
return MessageBoxW(hwnd, pwzText, pwzCaption, uType);
|
|
|
|
CStrIn strCaption(pwzCaption);
|
|
CStrIn strText(pwzText);
|
|
return MessageBoxA(hwnd, strText, strCaption, uType);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI FindNextFileWrapW(HANDLE hSearchHandle, LPWIN32_FIND_DATAW pFindFileDataW)
|
|
{
|
|
VALIDATE_PROTOTYPE(FindNextFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
return FindNextFileW(hSearchHandle, pFindFileDataW);
|
|
|
|
CWin32FindDataInOut fd(pFindFileDataW);
|
|
return FindNextFileA(hSearchHandle, fd);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
//--------------------------------------------------------------
|
|
// GetFullPathNameWrap
|
|
//--------------------------------------------------------------
|
|
|
|
DWORD
|
|
WINAPI
|
|
GetFullPathNameWrapW( LPCWSTR lpFileName,
|
|
DWORD nBufferLength,
|
|
LPWSTR lpBuffer,
|
|
LPWSTR *lpFilePart)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetFullPathName);
|
|
VALIDATE_OUTBUF(lpBuffer, nBufferLength);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
|
|
}
|
|
|
|
CStrIn strIn(lpFileName);
|
|
CStrOut strOut(lpBuffer,nBufferLength);
|
|
LPSTR pFile;
|
|
DWORD dwRet;
|
|
|
|
dwRet = GetFullPathNameA(strIn, nBufferLength, strOut, &pFile);
|
|
strOut.ConvertIncludingNul();
|
|
// REARCHITECT raymondc - This is wrong if we had to do DBCS or related goo
|
|
*lpFilePart = lpBuffer + (pFile - strOut);
|
|
return dwRet;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetShortPathNameWrapW(
|
|
LPCWSTR lpszLongPath,
|
|
LPWSTR lpszShortPath,
|
|
DWORD cchBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetShortPathName);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetShortPathNameW(lpszLongPath, lpszShortPath, cchBuffer);
|
|
|
|
}
|
|
|
|
CStrIn strLongPath(lpszLongPath);
|
|
CStrOut strShortPath(lpszShortPath, cchBuffer);
|
|
|
|
return GetShortPathNameA(strLongPath, strShortPath, strShortPath.BufSize());
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
GetStringTypeExWrapW(LCID lcid, DWORD dwInfoType, LPCTSTR lpSrcStr, int cchSrc, LPWORD lpCharType)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetStringTypeEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetStringTypeExW(lcid, dwInfoType, lpSrcStr, cchSrc, lpCharType);
|
|
}
|
|
|
|
CStrIn str(lpSrcStr, cchSrc);
|
|
return GetStringTypeExA(lcid, dwInfoType, str, str.strlen(), lpCharType);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
GetPrivateProfileIntWrapW(
|
|
LPCWSTR lpAppName,
|
|
LPCWSTR lpKeyName,
|
|
INT nDefault,
|
|
LPCWSTR lpFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetPrivateProfileInt);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, lpFileName);
|
|
}
|
|
|
|
CStrIn strApp(lpAppName);
|
|
CStrIn strKey(lpKeyName);
|
|
CPPFIn strFile(lpFileName); // PrivateProfile filename needs special class
|
|
|
|
return GetPrivateProfileIntA(strApp, strKey, nDefault, strFile);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetProfileStringWrapW(
|
|
LPCWSTR lpAppName,
|
|
LPCWSTR lpKeyName,
|
|
LPCWSTR lpDefault,
|
|
LPWSTR lpBuffer,
|
|
DWORD dwBuffersize)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetProfileString);
|
|
VALIDATE_OUTBUF(lpBuffer, dwBuffersize);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetProfileStringW(lpAppName, lpKeyName, lpDefault, lpBuffer, dwBuffersize);
|
|
}
|
|
|
|
CStrIn strApp(lpAppName);
|
|
CStrIn strKey(lpKeyName);
|
|
CStrIn strDefault(lpDefault);
|
|
CStrOut strBuffer(lpBuffer, dwBuffersize);
|
|
|
|
GetProfileStringA(strApp, strKey, strDefault, strBuffer, dwBuffersize);
|
|
return strBuffer.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
GetPropWrapW(HWND hWnd, LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetProp);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetPropW(hWnd, lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return GetPropA(hWnd, str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
GetTempFileNameWrapW(
|
|
LPCWSTR lpPathName,
|
|
LPCWSTR lpPrefixString,
|
|
UINT uUnique,
|
|
LPWSTR lpTempFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTempFileName);
|
|
VALIDATE_OUTBUF(lpTempFileName, MAX_PATH);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetTempFileNameW(lpPathName, lpPrefixString, uUnique, lpTempFileName);
|
|
}
|
|
|
|
|
|
CStrIn strPath(lpPathName);
|
|
CStrIn strPrefix(lpPrefixString);
|
|
CStrOut strFileName(lpTempFileName, MAX_PATH);
|
|
|
|
return GetTempFileNameA(strPath, strPrefix, uUnique, strFileName);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI
|
|
GetTempPathWrapW(DWORD nBufferLength, LPWSTR lpBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTempPath);
|
|
VALIDATE_OUTBUF(lpBuffer, nBufferLength);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetTempPathW(nBufferLength, lpBuffer);
|
|
}
|
|
|
|
|
|
CStrOut str(lpBuffer, nBufferLength);
|
|
|
|
GetTempPathA(str.BufSize(), str);
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
BOOL APIENTRY
|
|
GetTextExtentPoint32WrapW(
|
|
HDC hdc,
|
|
LPCWSTR pwsz,
|
|
int cb,
|
|
LPSIZE pSize)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTextExtentPoint32);
|
|
|
|
if (_MayNeedFontLinking(pwsz, cb))
|
|
{
|
|
return GetTextExtentPointFLW(hdc, pwsz, cb, pSize);
|
|
}
|
|
else if (g_bRunningOnNT)
|
|
{
|
|
return GetTextExtentPoint32W(hdc, pwsz, cb, pSize);
|
|
}
|
|
|
|
CStrIn str(pwsz,cb);
|
|
|
|
return GetTextExtentPoint32A(hdc, str, str.strlen(), pSize);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetTextFaceWrapW(
|
|
HDC hdc,
|
|
int cch,
|
|
LPWSTR lpFaceName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTextFace);
|
|
VALIDATE_OUTBUF(lpFaceName, cch);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetTextFaceW(hdc, cch, lpFaceName);
|
|
}
|
|
|
|
|
|
CStrOut str(lpFaceName, cch);
|
|
|
|
GetTextFaceA(hdc, str.BufSize(), str);
|
|
return str.ConvertIncludingNul();
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
GetTextMetricsWrapW(HDC hdc, LPTEXTMETRICW lptm)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTextMetrics);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetTextMetricsW(hdc, lptm);
|
|
}
|
|
|
|
|
|
BOOL ret;
|
|
TEXTMETRICA tm;
|
|
|
|
ret = GetTextMetricsA(hdc, &tm);
|
|
|
|
if (ret)
|
|
{
|
|
lptm->tmHeight = tm.tmHeight;
|
|
lptm->tmAscent = tm.tmAscent;
|
|
lptm->tmDescent = tm.tmDescent;
|
|
lptm->tmInternalLeading = tm.tmInternalLeading;
|
|
lptm->tmExternalLeading = tm.tmExternalLeading;
|
|
lptm->tmAveCharWidth = tm.tmAveCharWidth;
|
|
lptm->tmMaxCharWidth = tm.tmMaxCharWidth;
|
|
lptm->tmWeight = tm.tmWeight;
|
|
lptm->tmOverhang = tm.tmOverhang;
|
|
lptm->tmDigitizedAspectX = tm.tmDigitizedAspectX;
|
|
lptm->tmDigitizedAspectY = tm.tmDigitizedAspectY;
|
|
lptm->tmItalic = tm.tmItalic;
|
|
lptm->tmUnderlined = tm.tmUnderlined;
|
|
lptm->tmStruckOut = tm.tmStruckOut;
|
|
lptm->tmPitchAndFamily = tm.tmPitchAndFamily;
|
|
lptm->tmCharSet = tm.tmCharSet;
|
|
|
|
// LPBYTE -> LPCSTR casts below
|
|
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&tm.tmFirstChar, 1, &lptm->tmFirstChar, 1);
|
|
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&tm.tmLastChar, 1, &lptm->tmLastChar, 1);
|
|
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&tm.tmDefaultChar, 1, &lptm->tmDefaultChar, 1);
|
|
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&tm.tmBreakChar, 1, &lptm->tmBreakChar, 1);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
BOOL WINAPI GetUserNameWrapW(LPWSTR pszBuffer, LPDWORD pcch)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetUserName);
|
|
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = GetUserNameW(pszBuffer, pcch);
|
|
}
|
|
else
|
|
{
|
|
CStrOut stroBuffer(pszBuffer, *pcch);
|
|
|
|
fRet = GetUserNameA(stroBuffer, pcch);
|
|
|
|
if (fRet)
|
|
*pcch = stroBuffer.ConvertIncludingNul();
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LONG FORWARD_API WINAPI
|
|
GetWindowLongWrapW(HWND hWnd, int nIndex)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetWindowLong);
|
|
|
|
FORWARD_AW(GetWindowLong, (hWnd, nIndex));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetWindowTextWrapW(HWND hWnd, LPWSTR lpString, int nMaxCount)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetWindowText);
|
|
VALIDATE_OUTBUF(lpString, nMaxCount);
|
|
|
|
if (MLIsEnabled(hWnd))
|
|
return MLGetControlTextI(hWnd, lpString, nMaxCount);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetWindowTextW(hWnd, lpString, nMaxCount);
|
|
}
|
|
|
|
|
|
CStrOut str(lpString, nMaxCount);
|
|
|
|
GetWindowTextA(hWnd, str, str.BufSize());
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetWindowTextLengthWrapW(HWND hWnd)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetWindowTextLength);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetWindowTextLengthW(hWnd);
|
|
}
|
|
|
|
return GetWindowTextLengthA(hWnd);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
GetWindowsDirectoryWrapW(LPWSTR lpWinPath, UINT cch)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetWindowsDirectory);
|
|
VALIDATE_OUTBUF(lpWinPath, cch);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetWindowsDirectoryW(lpWinPath, cch);
|
|
}
|
|
|
|
CStrOut str(lpWinPath, cch);
|
|
|
|
GetWindowsDirectoryA(str, str.BufSize());
|
|
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
STDAPI_(DWORD) WINAPI
|
|
GetEnvironmentVariableWrapW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetEnvironmentVariable);
|
|
VALIDATE_OUTBUF(lpBuffer, nSize);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetEnvironmentVariableW(lpName,lpBuffer, nSize);
|
|
}
|
|
|
|
CStrOut str(lpBuffer, nSize);
|
|
CStrIn strName(lpName);
|
|
|
|
GetEnvironmentVariableA(strName, str, str.BufSize());
|
|
return str.ConvertExcludingNul();
|
|
|
|
}
|
|
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL FORWARD_API WINAPI
|
|
IsDialogMessageWrapW(HWND hWndDlg, LPMSG lpMsg)
|
|
{
|
|
VALIDATE_PROTOTYPE(IsDialogMessage);
|
|
|
|
FORWARD_AW(IsDialogMessage, (hWndDlg, lpMsg));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HACCEL WINAPI
|
|
LoadAcceleratorsWrapW(HINSTANCE hInstance, LPCWSTR lpTableName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadAccelerators);
|
|
ASSERT(HIWORD64(lpTableName) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadAcceleratorsW(hInstance, lpTableName);
|
|
}
|
|
|
|
return LoadAcceleratorsA(hInstance, (LPCSTR) lpTableName);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HBITMAP WINAPI
|
|
LoadBitmapWrapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadBitmap);
|
|
ASSERT(HIWORD64(lpBitmapName) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadBitmapW(hInstance, lpBitmapName);
|
|
}
|
|
|
|
return LoadBitmapA(hInstance, (LPCSTR) lpBitmapName);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HCURSOR WINAPI
|
|
LoadCursorWrapW(HINSTANCE hInstance, LPCWSTR lpCursorName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadCursor);
|
|
ASSERT(HIWORD64(lpCursorName) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadCursorW(hInstance, lpCursorName);
|
|
}
|
|
|
|
return LoadCursorA(hInstance, (LPCSTR) lpCursorName);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HICON WINAPI
|
|
LoadIconWrapW(HINSTANCE hInstance, LPCWSTR lpIconName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadIcon);
|
|
ASSERT(HIWORD64(lpIconName) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadIconW(hInstance, lpIconName);
|
|
}
|
|
|
|
return LoadIconA(hInstance, (LPCSTR) lpIconName);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Returns an icon from a dll/exe loaded as a datafile. Note that this is
|
|
// very similar to the standard LoadImage API. However, LoadImage does
|
|
// not work properly (returns bogus icons) on win95/98 when the dll is
|
|
// loaded as a datafile. (Stevepro 18-Sept-98)
|
|
//--------------------------------------------------------------------------
|
|
HICON _LoadIconFromInstanceA
|
|
(
|
|
HINSTANCE hInstance, // instance containing the icon
|
|
LPCSTR pszName, // name or id of icon
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT fuLoad // load flags, LR_DEFAULTCOLOR | LR_MONOCHROME
|
|
)
|
|
{
|
|
HICON hIcon;
|
|
|
|
UINT fUnsupportedFlags = ~(LR_DEFAULTCOLOR | LR_MONOCHROME);
|
|
if (fuLoad & fUnsupportedFlags)
|
|
{
|
|
// We saw a flag that we don't support, so default to the standard API
|
|
hIcon = (HICON)LoadImageA(hInstance, pszName, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
|
|
}
|
|
else
|
|
{
|
|
// Find the group icon
|
|
HRSRC hRsrc;
|
|
HGLOBAL hGlobal;
|
|
PBYTE pIconDir;
|
|
|
|
if ((hRsrc = FindResourceA(hInstance, pszName, (LPCSTR)RT_GROUP_ICON)) == NULL ||
|
|
(hGlobal = LoadResource(hInstance, hRsrc)) == NULL ||
|
|
(pIconDir = (PBYTE)LockResource(hGlobal)) == NULL)
|
|
{
|
|
// Note that FreeResource and UnlockResource are obsolete APIs, so we just exit.
|
|
return NULL;
|
|
}
|
|
|
|
// Find the icon that best matches the desired size
|
|
int nID = LookupIconIdFromDirectoryEx(pIconDir, TRUE, cxDesired, cyDesired, fuLoad);
|
|
|
|
PBYTE pbRes;
|
|
if (0 == nID ||
|
|
(hRsrc = FindResourceA(hInstance, MAKEINTRESOURCEA(nID), (LPCSTR)RT_ICON)) == NULL ||
|
|
(hGlobal = LoadResource(hInstance, hRsrc)) == NULL ||
|
|
(pbRes = (PBYTE)LockResource(hGlobal)) == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Let the OS make us an icon
|
|
LPBITMAPINFOHEADER pbmh = (LPBITMAPINFOHEADER)pbRes;
|
|
hIcon = CreateIconFromResourceEx(pbRes, SizeofResource(hInstance, hRsrc), TRUE, 0x00030000,
|
|
pbmh->biWidth, pbmh->biHeight/2, fuLoad);
|
|
|
|
// It failed, odds are good we're on NT so try the non-Ex way
|
|
if (hIcon == NULL)
|
|
{
|
|
// We would break on NT if we try with a 16bpp image
|
|
if(pbmh->biBitCount != 16)
|
|
{
|
|
hIcon = CreateIconFromResource(pbRes, SizeofResource(hInstance, hRsrc), TRUE, 0x00030000);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hIcon;
|
|
}
|
|
|
|
HANDLE WINAPI
|
|
LoadImageWrapA(
|
|
HINSTANCE hInstance,
|
|
LPCSTR lpName,
|
|
UINT uType,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT fuLoad)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadImage);
|
|
|
|
//
|
|
// If the hInstance is loaded as a datafile, LoadImage returns the
|
|
// wrong icons on win95/98. (Kernel can't find the datafile and uses
|
|
// null instead)
|
|
//
|
|
// APPCOMPAT: Should also fix loading other resource types from datafiles
|
|
//
|
|
if (!g_bRunningOnNT && uType == IMAGE_ICON)
|
|
{
|
|
return _LoadIconFromInstanceA(
|
|
hInstance,
|
|
lpName,
|
|
cxDesired,
|
|
cyDesired,
|
|
fuLoad);
|
|
}
|
|
|
|
return LoadImageA(
|
|
hInstance,
|
|
lpName,
|
|
uType,
|
|
cxDesired,
|
|
cyDesired,
|
|
fuLoad);
|
|
}
|
|
|
|
|
|
HANDLE WINAPI
|
|
LoadImageWrapW(
|
|
HINSTANCE hInstance,
|
|
LPCWSTR lpName,
|
|
UINT uType,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT fuLoad)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadImage);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadImageW(
|
|
hInstance,
|
|
lpName,
|
|
uType,
|
|
cxDesired,
|
|
cyDesired,
|
|
fuLoad);
|
|
}
|
|
|
|
CStrIn str(lpName);
|
|
|
|
return LoadImageWrapA(
|
|
hInstance,
|
|
str,
|
|
uType,
|
|
cxDesired,
|
|
cyDesired,
|
|
fuLoad);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HINSTANCE WINAPI
|
|
LoadLibraryExWrapW(
|
|
LPCWSTR lpLibFileName,
|
|
HANDLE hFile,
|
|
DWORD dwFlags)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadLibraryEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
return LoadLibraryExW(lpLibFileName, hFile, dwFlags);
|
|
|
|
CStrIn str(lpLibFileName);
|
|
|
|
// Win9X will crash if the pathname is longer than MAX_PATH bytes.
|
|
|
|
if (str.strlen() >= MAX_PATH)
|
|
{
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return LoadLibraryExA(str, hFile, dwFlags);
|
|
}
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL fDoMungeLangId(LANGID lidUI);
|
|
|
|
BOOL NeedMenuOwnerDraw(void)
|
|
{
|
|
// FEATURE: need to be improved
|
|
// It checks whether current UI language is cross codepage or not
|
|
if (g_bRunningOnNT5OrHigher)
|
|
return FALSE;
|
|
|
|
return fDoMungeLangId(MLGetUILanguage());
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
#define PUI_OWNERDRAW_SIG 0xFFFF0000
|
|
|
|
// NOTE: This structure is only visible from subclassed OwnerDrawSubclassProc
|
|
// with WM_DRAWITEM and WM_MEASUREITEM. All other places won't see this
|
|
// structure. We restore original format MENUITEMINFO structure without
|
|
// MFT_OWNERDRAW flag unless it's a real owner draw item.
|
|
// For this, we do/undo munge in Get/SetMenuItemInfo and InsertMenuItem.
|
|
|
|
typedef struct tagPUIMENUITEM
|
|
{
|
|
DWORD dwSig; // signature for this structure
|
|
HMENU hmenu; // menu handle
|
|
UINT fMask; // original MENUITEMINFO fMask value
|
|
UINT fType; // original MENUITEMINFO fType value
|
|
DWORD_PTR dwItemData; // original MENUITEMINFO dwItemData value
|
|
LPWSTR lpwz; // unicode menu string
|
|
UINT cch; // number of character for menu string
|
|
UINT iTabLength;
|
|
} PUIMENUITEM, *LPPUIMENUITEM;
|
|
|
|
void MungeMenuItem(HMENU hMenu, LPCMENUITEMINFOW lpmiiW, LPMENUITEMINFOW lpmiiNewW)
|
|
{
|
|
if (lpmiiW && lpmiiNewW)
|
|
{
|
|
*lpmiiNewW = *lpmiiW;
|
|
|
|
if ((MIIM_TYPE & lpmiiW->fMask) && !(MFT_NONSTRING & lpmiiW->fType))
|
|
{
|
|
LPWSTR lpmenuText = (LPWSTR)lpmiiW->dwTypeData;
|
|
|
|
if (lpmenuText)
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)LocalAlloc(LPTR, sizeof(PUIMENUITEM));
|
|
|
|
if (lpItem)
|
|
{
|
|
lpItem->dwSig = PUI_OWNERDRAW_SIG;
|
|
lpItem->hmenu = hMenu;
|
|
lpItem->fMask = lpmiiW->fMask;
|
|
lpItem->fType = lpmiiW->fType;
|
|
lpItem->dwItemData = lpmiiW->dwItemData;
|
|
lpItem->cch = lstrlenW(lpmenuText);
|
|
lpItem->lpwz = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (lpItem->cch + 1));
|
|
if (lpItem->lpwz)
|
|
StrCpyNW(lpItem->lpwz, lpmenuText, lpItem->cch + 1);
|
|
else
|
|
lpItem->cch = 0;
|
|
|
|
lpmiiNewW->fType |= MFT_OWNERDRAW;
|
|
lpmiiNewW->fMask |= MIIM_DATA;
|
|
lpmiiNewW->dwItemData = (ULONG_PTR)lpItem;
|
|
lpmiiNewW->dwTypeData = 0;
|
|
lpmiiNewW->cch = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
void DeleteOwnerDrawMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition);
|
|
|
|
void DeleteOwnerDrawMenu(HMENU hMenu)
|
|
{
|
|
int i, nItem = GetMenuItemCount(hMenu);
|
|
|
|
for (i = 0; i < nItem; i++)
|
|
DeleteOwnerDrawMenuItem(hMenu, i, TRUE);
|
|
}
|
|
|
|
void DeleteOwnerDrawMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition)
|
|
{
|
|
MENUITEMINFOA miiA;
|
|
|
|
miiA.cbSize = sizeof(miiA);
|
|
miiA.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA;
|
|
miiA.cch = 0;
|
|
if (GetMenuItemInfoA(hMenu, uItem, fByPosition, &miiA))
|
|
{
|
|
if (miiA.hSubMenu)
|
|
DeleteOwnerDrawMenu(miiA.hSubMenu);
|
|
else
|
|
{
|
|
if ((MIIM_TYPE & miiA.fMask) && (MFT_OWNERDRAW & miiA.fType))
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)miiA.dwItemData;
|
|
|
|
if (!IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig && !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
if (lpItem->lpwz && lpItem->cch)
|
|
LocalFree(lpItem->lpwz);
|
|
LocalFree(lpItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
DeleteMenuWrap(HMENU hMenu, UINT uPosition, UINT uFlags)
|
|
{
|
|
VALIDATE_PROTOTYPEX(DeleteMenu);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
|
|
if (bOwnerDraw)
|
|
DeleteOwnerDrawMenuItem(hMenu, uPosition, (MF_BYPOSITION & uFlags)? TRUE: FALSE);
|
|
|
|
return DeleteMenu(hMenu, uPosition, uFlags);
|
|
}
|
|
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
DestroyMenuWrap(HMENU hMenu)
|
|
{
|
|
VALIDATE_PROTOTYPEX(DestroyMenu);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
|
|
if (bOwnerDraw)
|
|
DeleteOwnerDrawMenu(hMenu);
|
|
|
|
return DestroyMenu(hMenu);
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
LPBYTE MenuLoadMENUTemplates(LPBYTE lpMenuTemplate, HMENU *phMenu)
|
|
{
|
|
HMENU hMenu;
|
|
UINT menuFlags = 0;
|
|
ULONG_PTR menuId = 0;
|
|
LPWSTR lpmenuText;
|
|
MENUITEMINFO mii;
|
|
|
|
if (!(hMenu = CreateMenu()))
|
|
goto memoryerror;
|
|
|
|
do
|
|
{
|
|
// Get the menu flags.
|
|
menuFlags = (UINT)(*(WORD *)lpMenuTemplate);
|
|
lpMenuTemplate += 2;
|
|
if (menuFlags & ~MF_VALID) {
|
|
goto memoryerror;
|
|
}
|
|
|
|
if (!(menuFlags & MF_POPUP))
|
|
{
|
|
menuId = *(WORD *)lpMenuTemplate;
|
|
lpMenuTemplate += 2;
|
|
}
|
|
|
|
lpmenuText = (LPWSTR)lpMenuTemplate;
|
|
|
|
if (*lpmenuText) // If a string exists, then skip to the end of it.
|
|
lpMenuTemplate += lstrlenW(lpmenuText) * sizeof(WCHAR);
|
|
else
|
|
lpmenuText = NULL;
|
|
|
|
// Skip over terminating NULL of the string (or the single NULL if empty string).
|
|
lpMenuTemplate += sizeof(WCHAR);
|
|
lpMenuTemplate = (BYTE *)(((ULONG_PTR)lpMenuTemplate + 1) & ~1); // word align
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(MENUITEMINFO);
|
|
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
|
|
|
|
if (menuFlags & MF_POPUP)
|
|
{
|
|
mii.fMask |= MIIM_SUBMENU;
|
|
lpMenuTemplate = MenuLoadMENUTemplates(lpMenuTemplate, (HMENU *)&menuId);
|
|
if (!lpMenuTemplate)
|
|
goto memoryerror;
|
|
mii.hSubMenu = (HMENU)menuId;
|
|
}
|
|
|
|
// Don't allow bitmaps from the resource file.
|
|
if (menuFlags & MF_BITMAP)
|
|
menuFlags = (UINT)((menuFlags | MFT_RIGHTJUSTIFY) & ~MF_BITMAP);
|
|
|
|
// We have to take out MFS_HILITE since that bit marks the end of a menu in
|
|
// a resource file. Since we shouldn't have any pre hilited items in the
|
|
// menu anyway, this is no big deal.
|
|
mii.fState = (menuFlags & MFS_OLDAPI_MASK) & ~MFS_HILITE;
|
|
mii.fType = (menuFlags & MFT_OLDAPI_MASK);
|
|
if (menuFlags & MFT_OWNERDRAW)
|
|
{
|
|
mii.fMask |= MIIM_DATA;
|
|
mii.dwItemData = (ULONG_PTR) lpmenuText;
|
|
lpmenuText = 0;
|
|
}
|
|
|
|
mii.dwTypeData = (LPTSTR)lpmenuText;
|
|
mii.cch = (UINT)-1;
|
|
mii.wID = (UINT)menuId;
|
|
|
|
if (!InsertMenuItemWrapW(hMenu, 0xFFFFFFFF, TRUE, &mii))
|
|
{
|
|
if (menuFlags & MF_POPUP)
|
|
DestroyMenuWrap(mii.hSubMenu);
|
|
goto memoryerror;
|
|
}
|
|
} while (!(menuFlags & MF_END));
|
|
|
|
*phMenu = hMenu;
|
|
return lpMenuTemplate;
|
|
|
|
memoryerror:
|
|
if (hMenu != NULL)
|
|
DestroyMenuWrap(hMenu);
|
|
*phMenu = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
PMENUITEMTEMPLATE2 MenuLoadMENUEXTemplates(PMENUITEMTEMPLATE2 lpMenuTemplate, HMENU *phMenu, WORD wResInfo)
|
|
{
|
|
HMENU hMenu;
|
|
HMENU hSubMenu;
|
|
long menuId = 0;
|
|
LPWSTR lpmenuText;
|
|
MENUITEMINFO mii;
|
|
UINT cch = 0;
|
|
DWORD dwHelpID;
|
|
|
|
if (!(hMenu = CreateMenu()))
|
|
goto memoryerror;
|
|
|
|
do
|
|
{
|
|
if (!(wResInfo & MFR_POPUP))
|
|
{
|
|
// If the PREVIOUS wResInfo field was not a POPUP, the
|
|
// dwHelpID field is not there. Back up so things fit.
|
|
lpMenuTemplate = (PMENUITEMTEMPLATE2)(((LPBYTE)lpMenuTemplate) - sizeof(lpMenuTemplate->dwHelpID));
|
|
dwHelpID = 0;
|
|
}
|
|
else
|
|
dwHelpID = lpMenuTemplate->dwHelpID;
|
|
|
|
menuId = lpMenuTemplate->menuId;
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(MENUITEMINFO);
|
|
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
|
|
|
|
mii.fType = lpMenuTemplate->fType;
|
|
if (mii.fType & ~MFT_MASK)
|
|
goto memoryerror;
|
|
|
|
mii.fState = lpMenuTemplate->fState;
|
|
if (mii.fState & ~MFS_MASK)
|
|
goto memoryerror;
|
|
|
|
wResInfo = lpMenuTemplate->wResInfo;
|
|
if (wResInfo & ~(MF_END | MFR_POPUP))
|
|
goto memoryerror;
|
|
|
|
if (dwHelpID)
|
|
SetMenuContextHelpId(hMenu,dwHelpID);
|
|
|
|
if (lpMenuTemplate->mtString[0])
|
|
lpmenuText = lpMenuTemplate->mtString;
|
|
else
|
|
lpmenuText = NULL;
|
|
|
|
cch = lstrlenW(lpmenuText);
|
|
mii.dwTypeData = (LPTSTR) lpmenuText;
|
|
|
|
// skip to next menu item template (DWORD boundary)
|
|
lpMenuTemplate = (PMENUITEMTEMPLATE2)
|
|
(((LPBYTE)lpMenuTemplate) +
|
|
sizeof(MENUITEMTEMPLATE2) +
|
|
((cch * sizeof(WCHAR) + 3) & ~3));
|
|
|
|
if (mii.fType & MFT_OWNERDRAW)
|
|
{
|
|
mii.fMask |= MIIM_DATA;
|
|
mii.dwItemData = (ULONG_PTR) mii.dwTypeData;
|
|
mii.dwTypeData = 0;
|
|
}
|
|
|
|
if (wResInfo & MFR_POPUP)
|
|
{
|
|
mii.fMask |= MIIM_SUBMENU;
|
|
lpMenuTemplate = MenuLoadMENUEXTemplates(lpMenuTemplate, &hSubMenu, MFR_POPUP);
|
|
if (lpMenuTemplate == NULL)
|
|
goto memoryerror;
|
|
mii.hSubMenu = hSubMenu;
|
|
}
|
|
|
|
// Don't allow bitmaps from the resource file.
|
|
if (mii.fType & MFT_BITMAP)
|
|
mii.fType = (mii.fType | MFT_RIGHTJUSTIFY) & ~MFT_BITMAP;
|
|
|
|
mii.cch = (UINT)-1;
|
|
mii.wID = menuId;
|
|
if (!InsertMenuItemWrapW(hMenu, 0xFFFFFFFF, TRUE, &mii))
|
|
{
|
|
if (wResInfo & MFR_POPUP)
|
|
DestroyMenuWrap(mii.hSubMenu);
|
|
goto memoryerror;
|
|
}
|
|
wResInfo &= ~MFR_POPUP;
|
|
} while (!(wResInfo & MFR_END));
|
|
|
|
*phMenu = hMenu;
|
|
return lpMenuTemplate;
|
|
|
|
memoryerror:
|
|
if (hMenu != NULL)
|
|
DestroyMenuWrap(hMenu);
|
|
*phMenu = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
HMENU CreateMenuFromResource(LPBYTE lpMenuTemplate)
|
|
{
|
|
HMENU hMenu = NULL;
|
|
UINT menuTemplateVersion;
|
|
UINT menuTemplateHeaderSize;
|
|
|
|
// menu resource: First, strip version number word out of the menu
|
|
// template. This value should be 0 for MENU, 1 for MENUEX.
|
|
menuTemplateVersion = *(WORD *)lpMenuTemplate;
|
|
lpMenuTemplate += 2;
|
|
if (menuTemplateVersion > 1)
|
|
return NULL;
|
|
|
|
menuTemplateHeaderSize = *(WORD *)lpMenuTemplate;
|
|
lpMenuTemplate += 2;
|
|
lpMenuTemplate += menuTemplateHeaderSize;
|
|
switch (menuTemplateVersion)
|
|
{
|
|
case 0:
|
|
MenuLoadMENUTemplates(lpMenuTemplate, &hMenu);
|
|
break;
|
|
|
|
case 1:
|
|
MenuLoadMENUEXTemplates((PMENUITEMTEMPLATE2)lpMenuTemplate, &hMenu, 0);
|
|
break;
|
|
}
|
|
return hMenu;
|
|
}
|
|
|
|
HMENU WINAPI
|
|
LoadMenuWrapW(HINSTANCE hInstance, LPCWSTR lpMenuName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadMenu);
|
|
ASSERT(HIWORD64(lpMenuName) == 0);
|
|
|
|
if (NeedMenuOwnerDraw() && MLIsMLHInstance(hInstance))
|
|
{
|
|
HRSRC hRes;
|
|
|
|
if (hRes = FindResourceWrapW(hInstance, lpMenuName, RT_MENU))
|
|
{
|
|
LPBYTE lpMenuTemplate = (LPBYTE)LoadResource(hInstance, hRes);
|
|
|
|
if (lpMenuTemplate)
|
|
{
|
|
HMENU hmenu = CreateMenuFromResource(lpMenuTemplate);
|
|
|
|
if (hmenu)
|
|
return hmenu;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadMenuW(hInstance, lpMenuName);
|
|
}
|
|
|
|
return LoadMenuA(hInstance, (LPCSTR) lpMenuName);
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
#define CX_MENUCHECK 8
|
|
#define CY_MENUCHECK 8
|
|
|
|
#define CHK_RADIO 0x006C
|
|
#define CHK_NORMAL 0x00FC
|
|
|
|
int FindCharPosition(LPCWSTR lpwStr, WCHAR wch)
|
|
{
|
|
int iPos;
|
|
int iLength = lstrlenW(lpwStr);
|
|
|
|
for (iPos = 0; iPos < iLength; iPos++)
|
|
{
|
|
if (lpwStr[iPos] == wch)
|
|
break;
|
|
}
|
|
|
|
return (iPos < iLength) ? iPos : -1;
|
|
}
|
|
|
|
int CalculateMenuTabString(HWND hWnd, HMENU hMenu)
|
|
{
|
|
int i;
|
|
int iMenuCount = GetMenuItemCount(hMenu);
|
|
int iLength;
|
|
int iTabPos = 0;
|
|
int iMaxTabLength = 0;
|
|
RECT rc;
|
|
HDC hdc;
|
|
HFONT hfont, hfontSav;
|
|
NONCLIENTMETRICSA ncm;
|
|
MENUITEMINFOA miiA;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
if (!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
|
|
return 0;
|
|
|
|
hfont = CreateFontIndirectA(&ncm.lfMenuFont);
|
|
if (NULL == hfont)
|
|
return 0;
|
|
|
|
hdc = GetDC(hWnd);
|
|
hfontSav = (HFONT)SelectObject(hdc, hfont);
|
|
|
|
for (i = 0; i < iMenuCount; i++)
|
|
{
|
|
miiA.cbSize = sizeof(miiA);
|
|
miiA.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA;
|
|
miiA.cch = 0;
|
|
|
|
if (GetMenuItemInfoA(hMenu, i, MF_BYPOSITION, &miiA))
|
|
{
|
|
if (miiA.hSubMenu)
|
|
CalculateMenuTabString(hWnd, miiA.hSubMenu);
|
|
|
|
if ((MIIM_TYPE & miiA.fMask) && (MFT_OWNERDRAW & miiA.fType))
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)miiA.dwItemData;
|
|
|
|
if (!IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig && !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
if (lpItem->lpwz && lpItem->cch)
|
|
{
|
|
iTabPos = FindCharPosition(lpItem->lpwz, L'\t');
|
|
|
|
if (iTabPos >= 0)
|
|
{
|
|
DrawTextFLW(hdc, lpItem->lpwz + iTabPos + 1,
|
|
lstrlenW(lpItem->lpwz) - iTabPos - 1, &rc, DT_SINGLELINE | DT_CALCRECT);
|
|
|
|
iLength = rc.right - rc.left;
|
|
if (iLength > iMaxTabLength)
|
|
iMaxTabLength = iLength;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < iMenuCount; i++)
|
|
{
|
|
miiA.cbSize = sizeof(miiA);
|
|
miiA.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA;
|
|
miiA.cch = 0;
|
|
|
|
if (GetMenuItemInfoA(hMenu, i, MF_BYPOSITION, &miiA))
|
|
{
|
|
if ((MIIM_TYPE & miiA.fMask) && (MFT_OWNERDRAW & miiA.fType))
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)miiA.dwItemData;
|
|
|
|
if (!IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig && !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
if (lpItem->lpwz && lpItem->cch)
|
|
{
|
|
lpItem->iTabLength = iMaxTabLength;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SelectObject(hdc, hfontSav);
|
|
DeleteObject(hfont);
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
return iMaxTabLength;
|
|
}
|
|
|
|
void DrawMenuItemCheckMark(HDC hdc, LPCSTR lpChkSym, LPRECT lprc, UINT uFormat)
|
|
{
|
|
HFONT hFont, hFontSave;
|
|
NONCLIENTMETRICSA ncm;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
if (SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
|
|
{
|
|
StrCpyNA(ncm.lfMenuFont.lfFaceName, "Wingdings", LF_FACESIZE);
|
|
ncm.lfMenuFont.lfCharSet = SYMBOL_CHARSET;
|
|
hFont = CreateFontIndirectA(&ncm.lfMenuFont);
|
|
if ( hFont == NULL )
|
|
return;
|
|
|
|
hFontSave = (HFONT)SelectObject(hdc, hFont);
|
|
|
|
DrawTextA(hdc, lpChkSym, 1, lprc, uFormat);
|
|
hFont = (HFONT)SelectObject(hdc, hFontSave);
|
|
DeleteObject(hFont);
|
|
}
|
|
}
|
|
|
|
void DrawMenuItemText(HDC hdc, LPCWSTR lpwMenuStr, LPRECT lprc, UINT uiRefData)
|
|
{
|
|
UINT uFormat = DT_VCENTER | DT_SINGLELINE | DT_LEFT | DT_EXPANDTABS;
|
|
int iTabPos;
|
|
|
|
iTabPos = FindCharPosition(lpwMenuStr, L'\t');
|
|
if(iTabPos < 0)
|
|
{
|
|
// No TAB string is in the menu string
|
|
DrawTextFLW(hdc, lpwMenuStr, lstrlenW(lpwMenuStr), lprc, uFormat);
|
|
}
|
|
else
|
|
{
|
|
RECT rc;
|
|
|
|
// Draw Text before TAB
|
|
DrawTextFLW(hdc, lpwMenuStr, iTabPos, lprc, uFormat);
|
|
|
|
// Adjust RC for after TAB string.
|
|
CopyRect(&rc, lprc);
|
|
rc.left = rc.right - uiRefData - GetSystemMetrics(SM_CXMENUCHECK);
|
|
DrawTextFLW(hdc, lpwMenuStr + iTabPos + 1, lstrlenW(lpwMenuStr) - iTabPos - 1, &rc, uFormat);
|
|
}
|
|
|
|
}
|
|
|
|
void DrawMenuItem(LPDRAWITEMSTRUCT lpdis, LPRECT lprc)
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)lpdis->itemData;
|
|
|
|
if (lpItem && lpItem->lpwz)
|
|
{
|
|
HDC hdc = lpdis->hDC;
|
|
UINT uFormat = DT_VCENTER | DT_SINGLELINE | DT_LEFT | DT_EXPANDTABS;
|
|
CHAR ChkSym[2] = {(CHAR)CHK_NORMAL, 0x00};
|
|
COLORREF clrTxt;
|
|
int iBkMode;
|
|
RECT rc;
|
|
|
|
if (ODS_CHECKED & lpdis->itemState)
|
|
{
|
|
MENUITEMINFOA miiA;
|
|
|
|
miiA.cbSize = sizeof(miiA);
|
|
miiA.fMask = MIIM_TYPE;
|
|
miiA.cch = 0;
|
|
if (GetMenuItemInfoA(lpItem->hmenu, lpdis->itemID, FALSE, &miiA))
|
|
{
|
|
if (MFT_RADIOCHECK & miiA.fType)
|
|
ChkSym[0] = CHK_RADIO;
|
|
}
|
|
}
|
|
|
|
iBkMode = SetBkMode(hdc, TRANSPARENT);
|
|
|
|
if (ODS_GRAYED & lpdis->itemState)
|
|
{
|
|
clrTxt = SetTextColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
|
|
|
|
if (ODS_CHECKED & lpdis->itemState)
|
|
{
|
|
CopyRect(&rc, &(lpdis->rcItem));
|
|
OffsetRect(&rc, 1, 1);
|
|
DrawMenuItemCheckMark(hdc, ChkSym, &rc, uFormat);
|
|
}
|
|
|
|
CopyRect(&rc, lprc);
|
|
OffsetRect(&rc, 1, 1);
|
|
DrawMenuItemText(hdc, lpItem->lpwz, &rc, lpItem->iTabLength);
|
|
|
|
SetTextColor(hdc, GetSysColor(COLOR_BTNSHADOW));
|
|
}
|
|
|
|
if (ODS_CHECKED & lpdis->itemState)
|
|
DrawMenuItemCheckMark(hdc, ChkSym, &(lpdis->rcItem), uFormat);
|
|
DrawMenuItemText(hdc, lpItem->lpwz, lprc, lpItem->iTabLength);
|
|
|
|
if (ODS_GRAYED & lpdis->itemState)
|
|
SetTextColor(hdc, clrTxt);
|
|
SetBkMode(hdc, iBkMode);
|
|
}
|
|
}
|
|
|
|
LRESULT OwnerDrawSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_DRAWITEM:
|
|
if (0 == wParam) // This is a menu
|
|
{
|
|
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)lpdis->itemData;
|
|
|
|
if (lpdis->CtlType == ODT_MENU
|
|
&& !IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig
|
|
&& !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
int cyTemp;
|
|
RECT rc;
|
|
HDC hdc = lpdis->hDC;
|
|
HFONT hfont, hfontSav;
|
|
TEXTMETRICA tm;
|
|
NONCLIENTMETRICSA ncm;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
if (!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
|
|
break;
|
|
|
|
hfont = CreateFontIndirectA(&ncm.lfMenuFont);
|
|
if (NULL == hfont)
|
|
break;
|
|
|
|
hfontSav = (HFONT)SelectObject(hdc, hfont);
|
|
|
|
GetTextMetricsA(hdc, &tm);
|
|
CopyRect(&rc, &lpdis->rcItem);
|
|
rc.left += GetSystemMetrics(SM_CXMENUCHECK);
|
|
rc.top += tm.tmExternalLeading;
|
|
|
|
cyTemp = (lpdis->rcItem.bottom - lpdis->rcItem.top) - (tm.tmHeight + tm.tmExternalLeading + GetSystemMetrics(SM_CYBORDER));
|
|
if (cyTemp > 0)
|
|
rc.top += (cyTemp / 2);
|
|
|
|
switch (lpdis->itemAction)
|
|
{
|
|
case ODA_DRAWENTIRE:
|
|
DrawMenuItem(lpdis, &rc);
|
|
break;
|
|
|
|
case ODA_FOCUS:
|
|
break;
|
|
|
|
case ODA_SELECT:
|
|
{
|
|
COLORREF clrTxt, clrBk, clrTxtSav, clrBkSav;
|
|
|
|
if (ODS_SELECTED & lpdis->itemState)
|
|
{
|
|
clrTxt = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
clrBk = GetSysColor(COLOR_HIGHLIGHT);
|
|
}
|
|
else
|
|
{
|
|
clrTxt = GetSysColor(COLOR_MENUTEXT);
|
|
clrBk = GetSysColor(COLOR_MENU);
|
|
}
|
|
clrTxtSav = SetTextColor(hdc, clrTxt);
|
|
clrBkSav = SetBkColor(hdc, clrBk);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &lpdis->rcItem, TEXT(""), 0, NULL);
|
|
DrawMenuItem(lpdis, &rc);
|
|
SetTextColor(hdc, clrTxtSav);
|
|
SetBkColor(hdc, clrBkSav);
|
|
break;
|
|
}
|
|
}
|
|
SelectObject(hdc, hfontSav);
|
|
DeleteObject(hfont);
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_MEASUREITEM:
|
|
if (0 == wParam) // This is a menu
|
|
{
|
|
LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam;
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)lpmis->itemData;
|
|
|
|
if (lpmis->CtlType == ODT_MENU
|
|
&& !IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig
|
|
&& !(MFT_OWNERDRAW & lpItem->fType) && lpItem->lpwz)
|
|
{
|
|
RECT rc;
|
|
HDC hdc;
|
|
HFONT hfont, hfontSav;
|
|
NONCLIENTMETRICSA ncm;
|
|
int iTabPos;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
if (!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
|
|
break;
|
|
|
|
hfont = CreateFontIndirectA(&ncm.lfMenuFont);
|
|
if (NULL == hfont)
|
|
break;
|
|
|
|
hdc = GetDC(hWnd);
|
|
hfontSav = (HFONT)SelectObject(hdc, hfont);
|
|
|
|
iTabPos = FindCharPosition(lpItem->lpwz, L'\t');
|
|
if (iTabPos < 0)
|
|
iTabPos = lstrlenW(lpItem->lpwz);
|
|
|
|
DrawTextFLW(hdc, lpItem->lpwz, iTabPos, &rc, DT_SINGLELINE | DT_CALCRECT | DT_EXPANDTABS);
|
|
SelectObject(hdc, hfontSav);
|
|
DeleteObject(hfont);
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
lpmis->itemWidth = rc.right - rc.left + GetSystemMetrics(SM_CXMENUCHECK) +
|
|
GetSystemMetrics(SM_CXEDGE) * 2 + lpItem->iTabLength;
|
|
lpmis->itemHeight = rc.bottom - rc.top + GetSystemMetrics(SM_CYEDGE) * 2;
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_MENUCHAR:
|
|
// FEATURE: need to be implemented
|
|
break;
|
|
}
|
|
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
GetMenuStringWrapW(
|
|
HMENU hMenu,
|
|
UINT uIDItem,
|
|
LPWSTR lpString,
|
|
int nMaxCount,
|
|
UINT uFlag)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetMenuString);
|
|
VALIDATE_OUTBUF(lpString, nMaxCount);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
MENUITEMINFOA miiA;
|
|
|
|
miiA.cbSize = sizeof(miiA);
|
|
miiA.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA;
|
|
miiA.cch = 0;
|
|
if (GetMenuItemInfoA(hMenu, uIDItem, (uFlag & MF_BYPOSITION)? TRUE: FALSE, &miiA))
|
|
{
|
|
if ((MIIM_TYPE & miiA.fMask) && (MFT_OWNERDRAW & miiA.fType))
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)miiA.dwItemData;
|
|
|
|
if (!IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig && !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
if (lpItem->lpwz && lpItem->cch)
|
|
{
|
|
StrCpyNW(lpString, lpItem->lpwz, nMaxCount);
|
|
return min((UINT)(nMaxCount - 1), lpItem->cch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetMenuStringW(hMenu, uIDItem, lpString, nMaxCount, uFlag);
|
|
}
|
|
|
|
CStrOut str(lpString, nMaxCount);
|
|
|
|
GetMenuStringA(hMenu, uIDItem, str, str.BufSize(), uFlag);
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
InsertMenuWrapW(
|
|
HMENU hMenu,
|
|
UINT uPosition,
|
|
UINT uFlags,
|
|
UINT_PTR uIDNewItem,
|
|
LPCWSTR lpNewItem)
|
|
{
|
|
VALIDATE_PROTOTYPE(InsertMenu);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
if (!((MF_BITMAP | MF_OWNERDRAW) & uFlags)) // if MF_STRING is set. MF_STRING is 0
|
|
{
|
|
MENUITEMINFOW miiW;
|
|
|
|
miiW.cbSize = sizeof(miiW);
|
|
miiW.fMask = MIIM_TYPE | MIIM_STATE;
|
|
miiW.fType = MFT_STRING;
|
|
miiW.fState = uFlags & (MF_DEFAULT | MF_CHECKED | MF_UNCHECKED | MF_HILITE | MF_UNHILITE| MF_ENABLED | MF_DISABLED | MF_GRAYED);
|
|
if (uFlags & (MF_GRAYED | MF_DISABLED))
|
|
miiW.fState |= MFS_GRAYED;
|
|
if (MF_POPUP & uFlags)
|
|
{
|
|
miiW.fMask |= MIIM_SUBMENU;
|
|
miiW.hSubMenu = (HMENU)uIDNewItem;
|
|
}
|
|
else
|
|
{
|
|
miiW.fMask |= MIIM_ID;
|
|
miiW.wID = (UINT)uIDNewItem;
|
|
}
|
|
miiW.dwTypeData = (LPWSTR)lpNewItem;
|
|
miiW.cch = lstrlenW(lpNewItem);
|
|
return InsertMenuItemWrapW(hMenu, uPosition, (MF_BYPOSITION & uFlags)? TRUE: FALSE, &miiW);
|
|
}
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, lpNewItem);
|
|
}
|
|
|
|
//
|
|
// You can't test for MFT_STRING because MFT_STRING is zero!
|
|
// So instead you have to check for everything *other* than
|
|
// a string.
|
|
//
|
|
// The presence of any non-string menu type turns lpnewItem into
|
|
// an atom.
|
|
//
|
|
CStrIn str((uFlags & MFT_NONSTRING) ? CP_ATOM : CP_ACP, lpNewItem);
|
|
|
|
return InsertMenuA(hMenu, uPosition, uFlags, uIDNewItem, str);
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL IsWindowOnCurrentThread(HWND hWnd)
|
|
{
|
|
DWORD foo;
|
|
|
|
if (!IsWindow(hWnd))
|
|
// bail if the window is dead so we dont bogusly rip
|
|
return TRUE;
|
|
|
|
if (GetCurrentThreadId() != GetWindowThreadProcessId(hWnd, &foo))
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
TrackPopupMenuWrap(HMENU hMenu, UINT uFlags, int x, int y, int nReserved, HWND hWnd, CONST RECT *prcRect)
|
|
{
|
|
VALIDATE_PROTOTYPEX(TrackPopupMenu);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
BOOL bIsWindowOnCurrentThread, bRet;
|
|
|
|
if (bOwnerDraw && (bIsWindowOnCurrentThread = IsWindowOnCurrentThread(hWnd)))
|
|
{
|
|
CalculateMenuTabString(hWnd, hMenu);
|
|
SetWindowSubclass(hWnd, OwnerDrawSubclassProc, 0, (DWORD_PTR)NULL);
|
|
}
|
|
|
|
bRet = TrackPopupMenu(hMenu, uFlags, x, y, nReserved, hWnd, prcRect);
|
|
|
|
if (bOwnerDraw && bIsWindowOnCurrentThread)
|
|
RemoveWindowSubclass(hWnd, OwnerDrawSubclassProc, 0);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
TrackPopupMenuExWrap(HMENU hMenu, UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm)
|
|
{
|
|
VALIDATE_PROTOTYPEX(TrackPopupMenuEx);
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
BOOL bIsWindowOnCurrentThread, bRet;
|
|
|
|
if (bOwnerDraw && (bIsWindowOnCurrentThread = IsWindowOnCurrentThread(hWnd)))
|
|
{
|
|
CalculateMenuTabString(hWnd, hMenu);
|
|
SetWindowSubclass(hWnd, OwnerDrawSubclassProc, 0, (DWORD_PTR)NULL);
|
|
}
|
|
|
|
bRet = TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm);
|
|
|
|
if (bOwnerDraw && bIsWindowOnCurrentThread)
|
|
RemoveWindowSubclass(hWnd, OwnerDrawSubclassProc, 0);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI
|
|
LoadStringWrapW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadString);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return LoadStringW(hInstance, uID, lpBuffer, nBufferMax);
|
|
}
|
|
|
|
//
|
|
// Do it manually. The old code used to call LoadStringA and then
|
|
// convert it up to unicode, which is bad, since resources are
|
|
// physically already Unicode! Just copy it out directly.
|
|
//
|
|
// The old code was also buggy in the case where the loaded string
|
|
// contains embedded NULLs.
|
|
//
|
|
|
|
if (nBufferMax <= 0) return 0; // sanity check
|
|
|
|
PWCHAR pwch;
|
|
|
|
/*
|
|
* String tables are broken up into "bundles" of 16 strings each.
|
|
*/
|
|
HRSRC hrsrc;
|
|
int cwch = 0;
|
|
|
|
hrsrc = FindResourceA(hInstance, (LPSTR)(LONG_PTR)(1 + uID / 16), (LPSTR)RT_STRING);
|
|
if (hrsrc) {
|
|
pwch = (PWCHAR)LoadResource(hInstance, hrsrc);
|
|
if (pwch) {
|
|
/*
|
|
* Now skip over the strings in the resource until we
|
|
* hit the one we want. Each entry is a counted string,
|
|
* just like Pascal.
|
|
*/
|
|
for (uID %= 16; uID; uID--) {
|
|
pwch += *pwch + 1;
|
|
}
|
|
cwch = min(*pwch, nBufferMax - 1);
|
|
memcpy(lpBuffer, pwch+1, cwch * sizeof(WCHAR)); /* Copy the goo */
|
|
}
|
|
}
|
|
lpBuffer[cwch] = L'\0'; /* Terminate the string */
|
|
return cwch;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformCharNoOp1( WCHAR **ppch )
|
|
//
|
|
// purpose: Stand-in for TransformCharWidth. Used by the function
|
|
// CompareStringString.
|
|
//
|
|
// returns: Character at *ppch. The value *ppch is incremented.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static WCHAR
|
|
TransformCharNoOp1( LPCWSTR *ppch, int )
|
|
{
|
|
WCHAR ch = **ppch;
|
|
|
|
(*ppch)++;
|
|
|
|
return ch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformCharWidth( WCHAR **ppch, cchRemaining )
|
|
//
|
|
// purpose: Converts halfwidth characters to fullwidth characters.
|
|
// Also combines voiced (dakuon) and semi-voiced (handakuon)
|
|
// characters. *pch is advanced by one, unless there is a
|
|
// (semi)voiced character, in which case it is advanced by
|
|
// two characters.
|
|
//
|
|
// Note that unlike the full widechar version, we do not
|
|
// combine other characters, notably the combining Hiragana
|
|
// characters (U+3099 and U+309A.) This is to keep the
|
|
// tables from getting unnecessarily large.
|
|
//
|
|
// cchRemaining is passed so as to not include the voiced
|
|
// marks if it's passed the end of the specified buffer.
|
|
//
|
|
// returns: Full width character. *pch is incremented.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static WCHAR
|
|
TransformCharWidth( LPCWSTR *ppch, int cchRemaining )
|
|
{
|
|
WCHAR ch = **ppch;
|
|
|
|
(*ppch)++;
|
|
|
|
if (ch == 0x0020)
|
|
{
|
|
ch = 0x3000;
|
|
}
|
|
else if (ch == 0x005c)
|
|
{
|
|
// REVERSE SOLIDUS (aka BACKSLASH) maps to itself
|
|
}
|
|
else if (InRange(ch, 0x0021, 0x07e))
|
|
{
|
|
ch += 65248;
|
|
}
|
|
else if (InRange(ch, 0x00a2, 0x00af))
|
|
{
|
|
static const WCHAR achFull[] =
|
|
{
|
|
0xffe0, 0xffe1, 0x00a4, 0xffe5, 0xffe4, 0x00a7, 0x00a8, // 0xa2-0xa8
|
|
0x00a9, 0x00aa, 0x00ab, 0xffe2, 0x00ad, 0x00ae, 0xffe3 // 0xa9-0xaf
|
|
};
|
|
|
|
ch = achFull[ch - 0x00a2];
|
|
}
|
|
else if (ch == 0x20a9) // WON SIGN
|
|
{
|
|
ch = 0xffe6;
|
|
}
|
|
else if (InRange(ch, 0xff61, 0xffdc))
|
|
{
|
|
WCHAR chNext = (cchRemaining > 1) ? **ppch : 0;
|
|
|
|
if (chNext == 0xff9e && InRange(ch, 0xff73, 0xff8e))
|
|
{
|
|
if (cchRemaining != 1)
|
|
{
|
|
static const WCHAR achFull[] =
|
|
{
|
|
/* 0xff73-0xff79 */ 0xb0f4, 0x30a8, 0x30aa, 0xb0ac, 0xb0ae, 0xb0b0, 0xb0b2,
|
|
/* 0xff7a-0xff80 */ 0xb0b4, 0xb0b6, 0xb0b8, 0xb0ba, 0xb0bc, 0xb0be, 0xb0c0,
|
|
/* 0xff81-0xff87 */ 0xb0c2, 0xb0c5, 0xb0c7, 0xb0c9, 0x30ca, 0x30cb, 0x30cc,
|
|
/* 0xff88-0xff8e */ 0x30cd, 0x30ce, 0xb0d0, 0xb0d3, 0xb0d6, 0xb0d9, 0xb0dc
|
|
};
|
|
|
|
// HALFWIDTH KATAKANA VOICED SOUND MARK
|
|
|
|
WCHAR chTemp = achFull[ch - 0xff73];
|
|
|
|
// Some in the range absorb the sound mark.
|
|
// These are indicated by the set high-bit.
|
|
|
|
ch = chTemp & 0x7fff;
|
|
|
|
if (chTemp & 0x8000)
|
|
{
|
|
(*ppch)++;
|
|
}
|
|
}
|
|
}
|
|
else if (chNext == 0xff9f && InRange(ch, 0xff8a, 0xff8e))
|
|
{
|
|
// HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
|
|
|
|
ch = 0x30d1 + (ch - 0xff8a) * 3;
|
|
(*ppch)++;
|
|
}
|
|
else
|
|
{
|
|
static const WCHAR achMapFullFFxx[] =
|
|
{
|
|
0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1, // 0xff61-0xff67
|
|
0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, // 0xff68-0xff6e
|
|
0x30c3, 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, // 0xff6f-0xff75
|
|
0x30ab, 0x30ad, 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, // 0xff76-0xff7c
|
|
0x30b9, 0x30bb, 0x30bd, 0x30bf, 0x30c1, 0x30c4, 0x30c6, // 0xff7d-0xff83
|
|
0x30c8, 0x30ca, 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, // 0xff84-0xff8a
|
|
0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, 0x30df, 0x30e0, // 0xff8b-0xff91
|
|
0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, 0x30ea, // 0xff92-0xff98
|
|
0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c, // 0xff99-0xff9f
|
|
0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, // 0xffa0-0xffa6
|
|
0x3137, 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, // 0xffa7-0xffad
|
|
0x313e, 0x313f, 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, // 0xffae-0xffb4
|
|
0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314a, 0x314b, // 0xffb5-0xffbb
|
|
0x314c, 0x314d, 0x314e, 0xffbf, 0xffc0, 0xffc1, 0x314f, // 0xffbc-0xffc2
|
|
0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0xffc8, 0xffc9, // 0xffc3-0xffc9
|
|
0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a, 0xffd0, // 0xffca-0xffd0
|
|
0xffd1, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160, // 0xffd1-0xffd7
|
|
0xffd8, 0xffd9, 0x3161, 0x3162, 0x3163 // 0xffd8-0xffac
|
|
};
|
|
|
|
ch = achMapFullFFxx[ch - 0xff61];
|
|
}
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformaCharNoOp2( WCHAR ch )
|
|
//
|
|
// purpose: Stand-in for CharLowerBuffWrap. Used by the function
|
|
// CompareStringString.
|
|
//
|
|
// returns: Original character
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static WCHAR
|
|
TransformCharNoOp2( WCHAR ch )
|
|
{
|
|
return ch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformaCharKana( WCHAR ch )
|
|
//
|
|
// purpose: Converts Hiragana characters to Katakana characters
|
|
//
|
|
// returns: Original character if not Hiragana,
|
|
// Katanaka character if Hiragana
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static WCHAR
|
|
TransformCharKana( WCHAR ch )
|
|
{
|
|
if (((ch & 0xff00) == 0x3000) &&
|
|
(InRange(ch, 0x3041, 0x3094) || InRange(ch, 0x309d, 0x309e)))
|
|
{
|
|
ch += 0x060;
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformCharNoOp3( LPWSTR pch, DWORD cch )
|
|
//
|
|
// purpose: Stand-in for CharLowerBuffWrap. Used by the function
|
|
// CompareStringString.
|
|
//
|
|
// returns: Character count (cch).
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static DWORD
|
|
TransformCharNoOp3( LPWSTR, DWORD cch )
|
|
{
|
|
return cch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: TransformaCharFinal( WCHAR ch )
|
|
//
|
|
// purpose: Converts "final" forms to regular forms
|
|
//
|
|
// returns: Original character if not Hiragana,
|
|
// Katanaka character if Hiragana
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
// REARCHITECT (cthrash) We do not fold Presentation Forms (Alphabetic or Arabic)
|
|
|
|
static WCHAR
|
|
TransformCharFinal( WCHAR ch )
|
|
{
|
|
WCHAR chRet = ch;
|
|
|
|
if (ch >= 0x3c2) // short-circuit ASCII +
|
|
{
|
|
switch (ch)
|
|
{
|
|
case 0x03c2: // GREEK SMALL LETTER FINAL SIGMA
|
|
case 0x05da: // HEBREW LETTER FINAL KAF
|
|
case 0x05dd: // HEBREW LETTER FINAL MEM
|
|
case 0x05df: // HEBREW LETTER FINAL NUN
|
|
case 0x05e3: // HEBREW LETTER FINAL PE
|
|
case 0x05e5: // HEBREW LETTER FINAL TSADI
|
|
case 0xfb26: // HEBREW LETTER WIDE FINAL MEM
|
|
case 0xfb3a: // HEBREW LETTER FINAL KAF WITH DAGESH
|
|
case 0xfb43: // HEBREW LETTER FINAL PE WITH DAGESH
|
|
chRet++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CompareStringString( ... )
|
|
//
|
|
// purpose: Helper for CompareStringWrap.
|
|
//
|
|
// We handle the string comparsion for CompareStringWrap.
|
|
// We can convert each character to (1) fullwidth,
|
|
// (2) Katakana, and (3) lowercase, as necessary.
|
|
//
|
|
// returns: 1 - string A is less in lexical value as string B
|
|
// 2 - string B is equal in lexical value as string B
|
|
// 3 - string B is greater in lexical value as string B
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static int
|
|
CompareStringString(
|
|
DWORD dwFlags,
|
|
LPCWSTR lpA,
|
|
int cchA,
|
|
LPCWSTR lpB,
|
|
int cchB )
|
|
{
|
|
int nRet = 0;
|
|
WCHAR wchIgnoreNulA = cchA == -1 ? 0 : -1;
|
|
WCHAR wchIgnoreNulB = cchB == -1 ? 0 : -1;
|
|
WCHAR (*pfnTransformWidth)(LPCWSTR *, int);
|
|
WCHAR (*pfnTransformKana)(WCHAR);
|
|
DWORD (*pfnTransformLower)(LPWSTR, DWORD);
|
|
WCHAR (*pfnTransformFinal)(WCHAR);
|
|
|
|
|
|
pfnTransformWidth = (dwFlags & NORM_IGNOREWIDTH)
|
|
? TransformCharWidth : TransformCharNoOp1;
|
|
pfnTransformKana = (dwFlags & NORM_IGNOREKANATYPE)
|
|
? TransformCharKana : TransformCharNoOp2;
|
|
pfnTransformLower = (dwFlags & NORM_IGNORECASE)
|
|
? CharLowerBuffWrap : TransformCharNoOp3;
|
|
pfnTransformFinal = (dwFlags & NORM_IGNORECASE)
|
|
? TransformCharFinal : TransformCharNoOp2;
|
|
|
|
while ( !nRet
|
|
&& cchA
|
|
&& cchB
|
|
&& (*lpA | wchIgnoreNulA)
|
|
&& (*lpB | wchIgnoreNulB) )
|
|
{
|
|
WCHAR chA, chB;
|
|
LPCWSTR lpAOld = lpA;
|
|
LPCWSTR lpBOld = lpB;
|
|
|
|
chA = (*pfnTransformWidth)(&lpA, cchA);
|
|
chA = (*pfnTransformKana)(chA);
|
|
(*pfnTransformLower)(&chA, 1);
|
|
chA = (*pfnTransformFinal)(chA);
|
|
|
|
chB = (*pfnTransformWidth)(&lpB, cchB);
|
|
chB = (*pfnTransformKana)(chB);
|
|
(*pfnTransformLower)(&chB, 1);
|
|
chB = (*pfnTransformFinal)(chB);
|
|
|
|
nRet = (int)chA - (int)chB;
|
|
cchA -= (int) (lpA - lpAOld);
|
|
cchB -= (int) (lpB - lpBOld);
|
|
}
|
|
|
|
if (!nRet)
|
|
{
|
|
nRet = cchA - cchB;
|
|
}
|
|
|
|
if (nRet)
|
|
{
|
|
nRet = nRet > 0 ? 1 : -1;
|
|
}
|
|
|
|
return nRet + 2;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CompareStringWord( ... )
|
|
//
|
|
// purpose: Helper for CompareStringWrap.
|
|
//
|
|
// We handle the word comparsion for CompareStringWrap.
|
|
//
|
|
// returns: 1 - string A is less in lexical value as string B
|
|
// 2 - string B is equal in lexical value as string B
|
|
// 3 - string B is greater in lexical value as string B
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
static int
|
|
CompareStringWord(
|
|
LCID lcid,
|
|
DWORD dwFlags,
|
|
LPCWSTR lpA,
|
|
int cchA,
|
|
LPCWSTR lpB,
|
|
int cchB )
|
|
{
|
|
// FEATURE (cthrash) We won't properly support word compare for the
|
|
// time being. Do the same old CP_ACP trick, which should cover
|
|
// enough cases.
|
|
|
|
// fail if either string is NULL, as it causes assert on debug windows
|
|
if (!lpA || !lpB)
|
|
return 0;
|
|
|
|
CStrIn strA(lpA, cchA);
|
|
CStrIn strB(lpB, cchB);
|
|
|
|
cchA = strA.strlen();
|
|
cchB = strB.strlen();
|
|
|
|
return CompareStringA(lcid, dwFlags, strA, cchA, strB, cchB);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// function: CompareStringWrapW( ... )
|
|
//
|
|
// purpose: Unicode wrapper of CompareString for Win95.
|
|
//
|
|
// Note not all bits in dwFlags are honored; specifically,
|
|
// since we don't do a true widechar word compare, we
|
|
// won't properly handle NORM_IGNORENONSPACE or
|
|
// NORM_IGNORESYMBOLS for arbitrary widechar strings.
|
|
//
|
|
// returns: 1 - string A is less in lexical value as string B
|
|
// 2 - string B is equal in lexical value as string B
|
|
// 3 - string B is greater in lexical value as string B
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
LWSTDAPI_(int)
|
|
CompareStringAltW(
|
|
LCID lcid,
|
|
DWORD dwFlags,
|
|
LPCWSTR lpA,
|
|
int cchA,
|
|
LPCWSTR lpB,
|
|
int cchB )
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CompareStringW(lcid, dwFlags, lpA, cchA, lpB, cchB);
|
|
}
|
|
|
|
int nRet;
|
|
|
|
if (dwFlags & SORT_STRINGSORT)
|
|
{
|
|
nRet = CompareStringString(dwFlags, lpA, cchA, lpB, cchB);
|
|
}
|
|
else
|
|
{
|
|
nRet = CompareStringWord(lcid, dwFlags, lpA, cchA, lpB, cchB);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
int StrLenN(LPCWSTR psz, int cchMin)
|
|
{
|
|
LPCWSTR pszEnd = psz;
|
|
|
|
while (((pszEnd - psz) < cchMin) && *pszEnd)
|
|
{
|
|
pszEnd++;
|
|
}
|
|
return pszEnd - psz;
|
|
}
|
|
|
|
int WINAPI CompareStringWrapW(LCID Locale, DWORD dwFlags,
|
|
LPCWSTR psz1, int cch1,
|
|
LPCWSTR psz2, int cch2)
|
|
{
|
|
VALIDATE_PROTOTYPE(CompareString);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CompareStringW(Locale, dwFlags, psz1, cch1, psz2, cch2);
|
|
}
|
|
else if (psz1 && psz2)
|
|
{
|
|
if (dwFlags & NORM_STOP_ON_NULL)
|
|
{
|
|
cch1 = StrLenN(psz1, cch1);
|
|
cch2 = StrLenN(psz2, cch2);
|
|
dwFlags &= ~NORM_STOP_ON_NULL;
|
|
}
|
|
|
|
CStrIn strString1(psz1, cch1);
|
|
CStrIn strString2(psz2, cch2);
|
|
|
|
cch1 = strString1.strlen();
|
|
cch2 = strString2.strlen();
|
|
|
|
return CompareStringA(Locale, dwFlags, strString1, cch1, strString2, cch2);
|
|
}
|
|
else
|
|
return 0; // fail if either string is NULL, as it causes assert on debug windows
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
#ifndef UNIX
|
|
BOOL WINAPI
|
|
MessageBoxIndirectWrapW(CONST MSGBOXPARAMS *pmbp)
|
|
#else
|
|
int WINAPI
|
|
MessageBoxIndirectWrapW(LPMSGBOXPARAMS pmbp)
|
|
#endif /* UNIX */
|
|
{
|
|
VALIDATE_PROTOTYPE(MessageBoxIndirect);
|
|
ASSERT(HIWORD64(pmbp->lpszIcon) == 0);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return MessageBoxIndirectW(pmbp);
|
|
}
|
|
|
|
CStrIn strText(pmbp->lpszText);
|
|
CStrIn strCaption(pmbp->lpszCaption);
|
|
MSGBOXPARAMSA mbp;
|
|
|
|
memcpy(&mbp, pmbp, sizeof(mbp));
|
|
mbp.lpszText = strText;
|
|
mbp.lpszCaption = strCaption;
|
|
|
|
return MessageBoxIndirectA(&mbp);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
DWORD GetCharacterPlacementWrapW(
|
|
HDC hdc, // handle to device context
|
|
LPCTSTR lpString, // pointer to string
|
|
int nCount, // number of characters in string
|
|
int nMaxExtent, // maximum extent for displayed string
|
|
LPGCP_RESULTS lpResults, // pointer to buffer for placement result
|
|
DWORD dwFlags // placement flags
|
|
)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetCharacterPlacement);
|
|
// Leave for someone else.
|
|
ASSERT (lpResults->lpOutString == NULL);
|
|
ASSERT (lpResults->lpClass == NULL);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetCharacterPlacementW (hdc,
|
|
lpString,
|
|
nCount,
|
|
nMaxExtent,
|
|
lpResults,
|
|
dwFlags);
|
|
}
|
|
|
|
CStrIn strText(lpString);
|
|
DWORD dwRet;
|
|
|
|
dwRet = GetCharacterPlacementA (hdc, strText, nCount, nMaxExtent,
|
|
(LPGCP_RESULTSA)lpResults,
|
|
dwFlags);
|
|
return dwRet;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
//
|
|
// Note that we're calling get GetCharWidthA instead of GetCharWidth32A
|
|
// because the 32 version doesn't exist under Win95.
|
|
BOOL WINAPI GetCharWidth32WrapW(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPINT lpBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetCharWidth32);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetCharWidth32W (hdc, iFirstChar, iLastChar, lpBuffer);
|
|
}
|
|
|
|
// Note that we expect to do only one character at a time for anything but
|
|
// ISO Latin 1.
|
|
if (iFirstChar > 255)
|
|
{
|
|
UINT mbChar=0;
|
|
WCHAR ch;
|
|
|
|
// Convert string
|
|
ch = (WCHAR)iFirstChar;
|
|
WideCharToMultiByte(CP_ACP, 0, &ch, 1,
|
|
(char *)&mbChar, 2, NULL, NULL);
|
|
}
|
|
|
|
return (GetCharWidthA (hdc, iFirstChar, iLastChar, lpBuffer));
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
//
|
|
// Note: Win95 does support ExtTextOutW. This thunk is not for
|
|
// ANSI/UNICODE wrapping. It's to work around an ISV app bug.
|
|
//
|
|
// Y'see, there's an app that patches Win95 GDI and their ExtTextOutW handler
|
|
// is broken. It always dereferences the lpStr parameter, even if
|
|
// cch is zero. Consequently, any time we are about to pass NULL as
|
|
// the lpStr, we have to change our mind and pass a null UNICODE string
|
|
// instead.
|
|
//
|
|
// The name of this app: Lotus SmartSuite ScreenCam 97.
|
|
//
|
|
LWSTDAPI_(BOOL)
|
|
ExtTextOutWrapW(HDC hdc, int x, int y, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpStr, UINT cch, CONST INT *lpDx)
|
|
{
|
|
VALIDATE_PROTOTYPE(ExtTextOut);
|
|
if (lpStr == NULL) // workaround
|
|
lpStr = L""; // for ScreenCam 97
|
|
|
|
if (_MayNeedFontLinking(lpStr, cch))
|
|
{
|
|
return ExtTextOutFLW(hdc, x, y, fuOptions, lprc, lpStr, cch, lpDx);
|
|
}
|
|
|
|
return ExtTextOutW(hdc, x, y, fuOptions, lprc, lpStr, cch, lpDx);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
ModifyMenuWrapW(
|
|
HMENU hMenu,
|
|
UINT uPosition,
|
|
UINT uFlags,
|
|
UINT_PTR uIDNewItem,
|
|
LPCWSTR lpNewItem)
|
|
{
|
|
VALIDATE_PROTOTYPE(ModifyMenu);
|
|
ASSERT(!(uFlags & MF_BITMAP) && !(uFlags & MF_OWNERDRAW));
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return ModifyMenuW(hMenu, uPosition, uFlags, uIDNewItem, lpNewItem);
|
|
}
|
|
|
|
CStrIn str(lpNewItem);
|
|
|
|
return ModifyMenuA(hMenu, uPosition, uFlags, uIDNewItem, str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
CopyFileWrapW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)
|
|
{
|
|
VALIDATE_PROTOTYPE(CopyFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists);
|
|
}
|
|
|
|
CStrIn strOld(lpExistingFileName);
|
|
CStrIn strNew(lpNewFileName);
|
|
|
|
return CopyFileA(strOld, strNew, bFailIfExists);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
MoveFileWrapW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(MoveFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return MoveFileW(lpExistingFileName, lpNewFileName);
|
|
}
|
|
|
|
CStrIn strOld(lpExistingFileName);
|
|
CStrIn strNew(lpNewFileName);
|
|
|
|
return MoveFileA(strOld, strNew);
|
|
}
|
|
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
OemToCharWrapW(LPCSTR lpszSrc, LPWSTR lpszDst)
|
|
{
|
|
VALIDATE_PROTOTYPE(OemToChar);
|
|
VALIDATE_OUTBUF(lpszDst, lstrlenA(lpszSrc));
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return OemToCharW(lpszSrc, lpszDst);
|
|
}
|
|
|
|
CStrOut strDst(lpszDst, lstrlenA(lpszSrc));
|
|
|
|
return OemToCharA(lpszSrc, strDst);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
OpenEventWrapW(
|
|
DWORD fdwAccess,
|
|
BOOL fInherit,
|
|
LPCWSTR lpszEventName)
|
|
{
|
|
VALIDATE_PROTOTYPE(OpenEvent);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return OpenEventW(fdwAccess, fInherit, lpszEventName);
|
|
}
|
|
|
|
CStrIn strEventName(lpszEventName);
|
|
|
|
return OpenEventA(fdwAccess, fInherit, strEventName);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
VOID WINAPI
|
|
OutputDebugStringWrapW(LPCWSTR lpOutputString)
|
|
{
|
|
VALIDATE_PROTOTYPE(OutputDebugString);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
OutputDebugStringW(lpOutputString);
|
|
return;
|
|
}
|
|
|
|
CStrIn str(lpOutputString);
|
|
|
|
OutputDebugStringA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL FORWARD_API WINAPI
|
|
PeekMessageWrapW(
|
|
LPMSG lpMsg,
|
|
HWND hWnd,
|
|
UINT wMsgFilterMin,
|
|
UINT wMsgFilterMax,
|
|
UINT wRemoveMsg)
|
|
{
|
|
VALIDATE_PROTOTYPE(PeekMessage);
|
|
|
|
FORWARD_AW(PeekMessage, (lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_WINMM_WRAPPER
|
|
|
|
LWSTDAPI_(BOOL)
|
|
PlaySoundWrapW(
|
|
LPCWSTR pszSound,
|
|
HMODULE hmod,
|
|
DWORD fdwSound)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return PlaySoundW(pszSound, hmod, fdwSound);
|
|
}
|
|
|
|
CStrIn strSound(pszSound);
|
|
|
|
return PlaySoundA(strSound, hmod, fdwSound);
|
|
}
|
|
|
|
#endif // NEED_WINMM_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL FORWARD_API WINAPI
|
|
PostMessageWrapW(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(PostMessage);
|
|
|
|
FORWARD_AW(PostMessage, (hWnd, Msg, wParam, lParam));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL FORWARD_API WINAPI
|
|
PostThreadMessageWrapW(
|
|
DWORD idThread,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(PostThreadMessage);
|
|
|
|
FORWARD_AW(PostThreadMessage, (idThread, Msg, wParam, lParam));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegCreateKeyWrapW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegCreateKey);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegCreateKeyW(hKey, lpSubKey, phkResult);
|
|
}
|
|
|
|
CStrIn str(lpSubKey);
|
|
|
|
return RegCreateKeyA(hKey, str, phkResult);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegCreateKeyExWrapW(HKEY hKey, LPCTSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegCreateKeyEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
|
|
}
|
|
|
|
CStrIn strSubKey(lpSubKey);
|
|
CStrIn strClass(lpClass);
|
|
|
|
return RegCreateKeyExA(hKey, strSubKey, Reserved, strClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
//
|
|
// Subtle difference: RegDeleteKey on Win9x will recursively delete subkeys.
|
|
// On NT, it fails if the key being deleted has subkeys. If you need to
|
|
// force NT-style behavior, use SHDeleteEmptyKey. To force 95-style
|
|
// behavior, use SHDeleteKey.
|
|
//
|
|
LONG APIENTRY
|
|
RegDeleteKeyWrapW(HKEY hKey, LPCWSTR pwszSubKey)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegDeleteKey);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegDeleteKeyW(hKey, pwszSubKey);
|
|
}
|
|
|
|
CStrIn str(pwszSubKey);
|
|
|
|
return RegDeleteKeyA(hKey, str);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegDeleteValueWrapW(HKEY hKey, LPCWSTR pwszSubKey)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegDeleteValue);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegDeleteValueW(hKey, pwszSubKey);
|
|
}
|
|
|
|
CStrIn str(pwszSubKey);
|
|
|
|
return RegDeleteValueA(hKey, str);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegEnumKeyWrapW(
|
|
HKEY hKey,
|
|
DWORD dwIndex,
|
|
LPWSTR lpName,
|
|
DWORD cbName)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegEnumKey);
|
|
VALIDATE_OUTBUF(lpName, cbName);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegEnumKeyW(hKey, dwIndex, lpName, cbName);
|
|
}
|
|
|
|
CStrOut str(lpName, cbName);
|
|
|
|
return RegEnumKeyA(hKey, dwIndex, str, str.BufSize());
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegEnumKeyExWrapW(
|
|
HKEY hKey,
|
|
DWORD dwIndex,
|
|
LPWSTR lpName,
|
|
LPDWORD lpcbName,
|
|
LPDWORD lpReserved,
|
|
LPWSTR lpClass,
|
|
LPDWORD lpcbClass,
|
|
PFILETIME lpftLastWriteTime)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegEnumKeyEx);
|
|
if (lpcbName) {VALIDATE_OUTBUF(lpName, *lpcbName);}
|
|
if (lpcbClass) {VALIDATE_OUTBUF(lpClass, *lpcbClass);}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegEnumKeyExW(
|
|
hKey,
|
|
dwIndex,
|
|
lpName,
|
|
lpcbName,
|
|
lpReserved,
|
|
lpClass,
|
|
lpcbClass,
|
|
lpftLastWriteTime);
|
|
}
|
|
|
|
long ret;
|
|
DWORD dwClass = 0;
|
|
|
|
if (!lpcbClass)
|
|
{
|
|
lpcbClass = &dwClass;
|
|
}
|
|
|
|
CStrOut strName(lpName, *lpcbName);
|
|
CStrOut strClass(lpClass, *lpcbClass);
|
|
|
|
ret = RegEnumKeyExA(
|
|
hKey,
|
|
dwIndex,
|
|
strName,
|
|
lpcbName,
|
|
lpReserved,
|
|
strClass,
|
|
lpcbClass,
|
|
lpftLastWriteTime);
|
|
|
|
*lpcbName = strName.ConvertExcludingNul();
|
|
*lpcbClass = strClass.ConvertExcludingNul();
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegOpenKeyWrapW(HKEY hKey, LPCWSTR pwszSubKey, PHKEY phkResult)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegOpenKey);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegOpenKeyW(hKey, pwszSubKey, phkResult);
|
|
}
|
|
|
|
CStrIn str(pwszSubKey);
|
|
|
|
return RegOpenKeyA(hKey, str, phkResult);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegOpenKeyExWrapW(
|
|
HKEY hKey,
|
|
LPCWSTR lpSubKey,
|
|
DWORD ulOptions,
|
|
REGSAM samDesired,
|
|
PHKEY phkResult)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegOpenKeyEx);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
|
}
|
|
|
|
CStrIn str(lpSubKey);
|
|
|
|
return RegOpenKeyExA(hKey, str, ulOptions, samDesired, phkResult);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegQueryInfoKeyWrapW(
|
|
HKEY hKey,
|
|
LPWSTR lpClass,
|
|
LPDWORD lpcbClass,
|
|
LPDWORD lpReserved,
|
|
LPDWORD lpcSubKeys,
|
|
LPDWORD lpcbMaxSubKeyLen,
|
|
LPDWORD lpcbMaxClassLen,
|
|
LPDWORD lpcValues,
|
|
LPDWORD lpcbMaxValueNameLen,
|
|
LPDWORD lpcbMaxValueLen,
|
|
LPDWORD lpcbSecurityDescriptor,
|
|
PFILETIME lpftLastWriteTime)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegQueryInfoKey);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegQueryInfoKeyW(
|
|
hKey,
|
|
lpClass,
|
|
lpcbClass,
|
|
lpReserved,
|
|
lpcSubKeys,
|
|
lpcbMaxSubKeyLen,
|
|
lpcbMaxClassLen,
|
|
lpcValues,
|
|
lpcbMaxValueNameLen,
|
|
lpcbMaxValueLen,
|
|
lpcbSecurityDescriptor,
|
|
lpftLastWriteTime);
|
|
|
|
}
|
|
|
|
CStrIn str(lpClass);
|
|
|
|
return RegQueryInfoKeyA(
|
|
hKey,
|
|
str,
|
|
lpcbClass,
|
|
lpReserved,
|
|
lpcSubKeys,
|
|
lpcbMaxSubKeyLen,
|
|
lpcbMaxClassLen,
|
|
lpcValues,
|
|
lpcbMaxValueNameLen,
|
|
lpcbMaxValueLen,
|
|
lpcbSecurityDescriptor,
|
|
lpftLastWriteTime);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegQueryValueWrapW(
|
|
HKEY hKey,
|
|
LPCWSTR pwszSubKey,
|
|
LPWSTR pwszValue,
|
|
PLONG lpcbValue)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegQueryValue);
|
|
if (lpcbValue) {VALIDATE_OUTBUF(pwszValue, *lpcbValue);}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegQueryValueW(hKey, pwszSubKey, pwszValue, lpcbValue);
|
|
}
|
|
|
|
long ret;
|
|
long cb;
|
|
CStrIn strKey(pwszSubKey);
|
|
CStrOut strValue(pwszValue, (lpcbValue ? ((*lpcbValue) / sizeof(WCHAR)) : 0));
|
|
|
|
cb = strValue.BufSize();
|
|
ret = RegQueryValueA(hKey, strKey, strValue, (lpcbValue ? &cb : NULL));
|
|
if (ret != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
if (strValue)
|
|
{
|
|
cb = strValue.ConvertIncludingNul();
|
|
}
|
|
|
|
if (lpcbValue)
|
|
*lpcbValue = cb * sizeof(WCHAR);
|
|
|
|
Cleanup:
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegQueryValueExWrapW(
|
|
HKEY hKey,
|
|
LPCWSTR lpValueName,
|
|
LPDWORD lpReserved,
|
|
LPDWORD lpType,
|
|
LPBYTE lpData,
|
|
LPDWORD lpcbData)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegQueryValueEx);
|
|
if (lpcbData) {VALIDATE_OUTBUF(lpData, *lpcbData);}
|
|
|
|
LONG ret;
|
|
DWORD dwTempType;
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
#ifdef DEBUG
|
|
if (lpType == NULL)
|
|
lpType = &dwTempType;
|
|
#endif
|
|
ret = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
|
|
|
return ret;
|
|
}
|
|
|
|
CStrIn strValueName(lpValueName);
|
|
DWORD cb;
|
|
|
|
//
|
|
// Determine the type of buffer needed
|
|
//
|
|
|
|
ret = RegQueryValueExA(hKey, strValueName, lpReserved, &dwTempType, NULL, (lpcbData ? &cb : NULL));
|
|
if (ret != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
ASSERT(dwTempType != REG_MULTI_SZ);
|
|
|
|
switch (dwTempType)
|
|
{
|
|
case REG_EXPAND_SZ:
|
|
case REG_SZ:
|
|
{
|
|
CStrOut strData((LPWSTR) lpData, (lpcbData ? ((*lpcbData) / sizeof(WCHAR)) : 0));
|
|
|
|
cb = strData.BufSize();
|
|
ret = RegQueryValueExA(hKey, strValueName, lpReserved, lpType, (LPBYTE)(LPSTR)strData, (lpcbData ? &cb : NULL));
|
|
if (ret != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if (strData)
|
|
{
|
|
cb = strData.ConvertIncludingNul();
|
|
}
|
|
|
|
if (lpcbData)
|
|
*lpcbData = cb * sizeof(WCHAR);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ret = RegQueryValueExA(
|
|
hKey,
|
|
strValueName,
|
|
lpReserved,
|
|
lpType,
|
|
lpData,
|
|
lpcbData);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegSetValueWrapW(
|
|
HKEY hKey,
|
|
LPCWSTR lpSubKey,
|
|
DWORD dwType,
|
|
LPCWSTR lpData,
|
|
DWORD cbData)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegSetValue);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegSetValueW(hKey, lpSubKey, dwType, lpData, cbData);
|
|
}
|
|
|
|
CStrIn strKey(lpSubKey);
|
|
CStrIn strValue(lpData);
|
|
|
|
return RegSetValueA(hKey, strKey, dwType, strValue, cbData);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG APIENTRY
|
|
RegSetValueExWrapW(
|
|
HKEY hKey,
|
|
LPCWSTR lpValueName,
|
|
DWORD Reserved,
|
|
DWORD dwType,
|
|
CONST BYTE* lpData,
|
|
DWORD cbData)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegSetValueEx);
|
|
ASSERT(dwType != REG_MULTI_SZ);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegSetValueExW(
|
|
hKey,
|
|
lpValueName,
|
|
Reserved,
|
|
dwType,
|
|
lpData,
|
|
cbData);
|
|
}
|
|
|
|
|
|
CStrIn strKey(lpValueName);
|
|
CStrIn strSZ((dwType == REG_SZ || dwType == REG_EXPAND_SZ) ? (LPCWSTR) lpData : NULL);
|
|
|
|
if (strSZ)
|
|
{
|
|
lpData = (LPBYTE) (LPSTR) strSZ;
|
|
cbData = strSZ.strlen() + 1;
|
|
}
|
|
|
|
return RegSetValueExA(
|
|
hKey,
|
|
strKey,
|
|
Reserved,
|
|
dwType,
|
|
lpData,
|
|
cbData);
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
ATOM WINAPI
|
|
RegisterClassWrapW(CONST WNDCLASSW * lpWndClass)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegisterClass);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegisterClassW(lpWndClass);
|
|
}
|
|
|
|
WNDCLASSA wc;
|
|
CStrIn strMenuName(lpWndClass->lpszMenuName);
|
|
CStrIn strClassName(lpWndClass->lpszClassName);
|
|
|
|
ASSERT(sizeof(wc) == sizeof(*lpWndClass));
|
|
memcpy(&wc, lpWndClass, sizeof(wc));
|
|
|
|
wc.lpszMenuName = strMenuName;
|
|
wc.lpszClassName = strClassName;
|
|
|
|
return RegisterClassA(&wc);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
RegisterClipboardFormatWrapW(LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegisterClipboardFormat);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegisterClipboardFormatW(lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return RegisterClipboardFormatA(str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
UINT WINAPI
|
|
RegisterWindowMessageWrapW(LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegisterWindowMessage);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RegisterWindowMessageW(lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return RegisterWindowMessageA(str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
RemoveDirectoryWrapW(LPCWSTR lpszDir)
|
|
{
|
|
VALIDATE_PROTOTYPE(RemoveDirectory);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RemoveDirectoryW(lpszDir);
|
|
}
|
|
|
|
CStrIn strDir(lpszDir);
|
|
|
|
return RemoveDirectoryA(strDir);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HANDLE WINAPI
|
|
RemovePropWrapW(
|
|
HWND hWnd,
|
|
LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(RemoveProp);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return RemovePropW(hWnd, lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return RemovePropA(hWnd, str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LRESULT WINAPI SendMessageWrapW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
|
// NOTE (SumitC) Instead of calling SendDlgItemMessageA below, I'm forwarding to
|
|
// SendMessageWrap so as not to have to re-do the special-case processing.
|
|
LRESULT WINAPI
|
|
SendDlgItemMessageWrapW(
|
|
HWND hDlg,
|
|
int nIDDlgItem,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(SendDlgItemMessage);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SendDlgItemMessageW(hDlg, nIDDlgItem, Msg, wParam, lParam);
|
|
}
|
|
|
|
HWND hWnd;
|
|
|
|
hWnd = GetDlgItem(hDlg, nIDDlgItem);
|
|
|
|
return SendMessageWrapW(hWnd, Msg, wParam, lParam);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int CharIndexToByteIndex(LPCSTR psz, int cch)
|
|
{
|
|
if (cch <= 0)
|
|
return cch;
|
|
|
|
LPCSTR pszTemp = psz;
|
|
while (*pszTemp && cch-- > 0)
|
|
{
|
|
pszTemp = CharNextA(pszTemp);
|
|
}
|
|
|
|
return (int)(pszTemp - psz);
|
|
}
|
|
|
|
int ByteIndexToCharIndex(LPCSTR psz, int cb)
|
|
{
|
|
if (cb <=0)
|
|
return cb;
|
|
|
|
LPCSTR pszTemp = psz;
|
|
LPCSTR pszEnd = &psz[cb];
|
|
int cch = 0;
|
|
|
|
while (*pszTemp && pszTemp < pszEnd)
|
|
{
|
|
pszTemp = CharNextA(pszTemp);
|
|
++cch;
|
|
}
|
|
|
|
return cch;
|
|
}
|
|
|
|
//
|
|
// Translate between byte positions and "character" positions
|
|
//
|
|
void TranslateCharPos(HWND hwnd, BOOL fByteIndexToCharIndex, DWORD* pdwPos, int cPos)
|
|
{
|
|
int cch = GetWindowTextLengthA(hwnd);
|
|
if (cch > 0)
|
|
{
|
|
char szBuf[MAX_PATH];
|
|
LPSTR pszBuf = szBuf;
|
|
|
|
if (cch >= ARRAYSIZE(szBuf))
|
|
{
|
|
pszBuf = new char[cch + 1];
|
|
}
|
|
|
|
if (pszBuf)
|
|
{
|
|
GetWindowTextA(hwnd, (LPSTR)pszBuf, cch+1);
|
|
|
|
// Translate Each value passed in
|
|
while (cPos--)
|
|
{
|
|
if (fByteIndexToCharIndex)
|
|
{
|
|
*pdwPos = (DWORD)ByteIndexToCharIndex(pszBuf, (int)*pdwPos);
|
|
}
|
|
else
|
|
{
|
|
*pdwPos = (DWORD)CharIndexToByteIndex(pszBuf, (int)*pdwPos);
|
|
}
|
|
++pdwPos;
|
|
}
|
|
|
|
if (pszBuf != szBuf)
|
|
{
|
|
delete [] pszBuf;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// There is no WM_GETOBJECT/OBJID_QUERYCLASSNAMEIDX code for comboex,
|
|
// so we will just send CCM_GETUNICODEFORMAT and hope for the best.
|
|
// We are relying on the fact that Win95's combo box returns 0 in response
|
|
// to messages it doesn't understand (like CCM_GETUNICODEFORMAT).
|
|
//
|
|
#define IsUnicodeComboEx(hWnd) SendMessageA(hWnd, CCM_GETUNICODEFORMAT, 0, 0)
|
|
|
|
#ifdef DEBUG
|
|
int g_cSMTot, g_cSMHit;
|
|
int g_cSMMod = 100;
|
|
#endif
|
|
|
|
LRESULT WINAPI
|
|
SendMessageAThunk(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
#ifdef DEBUG
|
|
if ((g_cSMTot % g_cSMMod) == 0)
|
|
TraceMsg(DM_PERF, "sm: tot=%d hit=%d", g_cSMTot, g_cSMHit);
|
|
#endif
|
|
DBEXEC(TRUE, g_cSMTot++);
|
|
// todo: perf? seems to be pretty common case, at least for now...
|
|
DBEXEC(Msg > WM_USER, g_cSMHit++);
|
|
#if 0
|
|
if (Msg > WM_USER)
|
|
goto Ldef;
|
|
#endif
|
|
|
|
switch (Msg)
|
|
{
|
|
case EM_GETLINE:
|
|
{
|
|
LRESULT nLen;
|
|
|
|
CStrOut str((LPWSTR) lParam, (* (SHORT *) lParam) + 1);
|
|
* (SHORT *) (LPSTR) str = * (SHORT *) lParam;
|
|
nLen = SendMessageA(hWnd, Msg, (WPARAM) wParam, (LPARAM) (LPSTR) str);
|
|
|
|
if(nLen > 0)
|
|
((LPSTR) str)[nLen] = '\0';
|
|
|
|
return nLen;
|
|
}
|
|
|
|
case EM_SETPASSWORDCHAR:
|
|
{
|
|
WPARAM wp = 0;
|
|
|
|
ASSERT(HIWORD64(wParam) == 0);
|
|
SHUnicodeToAnsi((LPWSTR) &wParam, (LPSTR) &wp, sizeof(wp));
|
|
ASSERT(HIWORD64(wp) == 0);
|
|
|
|
return SendMessageA(hWnd, Msg, wp, lParam);
|
|
}
|
|
|
|
case EM_SETWORDBREAKPROC:
|
|
{
|
|
// There is a bug with how USER handles WH_CALLWNDPROC global hooks in Win95/98 that
|
|
// causes us to blow up if one is installed and a wordbreakproc is set. Thus,
|
|
// if an app is running that has one of these hooks installed (intellipoint 1.1 etc.) then
|
|
// if we install our wordbreakproc the app will fault when the proc is called. There
|
|
// does not appear to be any way for us to work around it since USER's thunking code
|
|
// trashes the stack so this API is disabled for Win9x.
|
|
TraceMsg(TF_WARNING, "EM_SETWORDBREAKPROC can fault on Win9x; see unicwrap.cpp for details");
|
|
return FALSE;
|
|
}
|
|
|
|
case EM_GETSEL:
|
|
{
|
|
//
|
|
// Convert multibyte indicies into unicode indicies
|
|
//
|
|
DWORD dw[2];
|
|
SendMessageA(hWnd, Msg, (WPARAM)&dw[0], (LPARAM)&dw[1]);
|
|
TranslateCharPos(hWnd, TRUE, dw, ARRAYSIZE(dw));
|
|
|
|
// Return the results
|
|
DWORD* pdwStart = (DWORD*)wParam;
|
|
DWORD* pdwEnd = (DWORD*)lParam;
|
|
if (pdwStart)
|
|
{
|
|
*pdwStart = dw[0];
|
|
}
|
|
if (pdwEnd)
|
|
{
|
|
*pdwEnd = dw[1];
|
|
}
|
|
|
|
LRESULT lr = (LRESULT)-1;
|
|
|
|
if (dw[0] <= 0xffff && dw[1] <= 0xffff)
|
|
{
|
|
lr = MAKELONG(dw[0], dw[1]);
|
|
}
|
|
return lr;
|
|
}
|
|
|
|
case EM_SETSEL:
|
|
{
|
|
//
|
|
// Convert unicode char indicies into multibyte indicies
|
|
//
|
|
DWORD dw[2];
|
|
dw[0] = (DWORD)wParam; // start
|
|
dw[1] = (DWORD)lParam; // end
|
|
|
|
TranslateCharPos(hWnd, FALSE, dw, ARRAYSIZE(dw));
|
|
|
|
return SendMessageA(hWnd, Msg, (WPARAM)dw[0], (LPARAM)dw[1]);
|
|
}
|
|
|
|
case EM_CHARFROMPOS:
|
|
{
|
|
DWORD dwPos = SendMessageA(hWnd, Msg, wParam, lParam);
|
|
if (HIWORD(dwPos) == 0)
|
|
{
|
|
TranslateCharPos(hWnd, TRUE, &dwPos, 1);
|
|
}
|
|
return dwPos;
|
|
}
|
|
|
|
case WM_SETTEXT:
|
|
case LB_ADDSTRING:
|
|
case CB_ADDSTRING:
|
|
case EM_REPLACESEL:
|
|
RIPMSG(wParam == 0, "wParam should be 0 for these messages");
|
|
// fall through
|
|
case LB_FINDSTRING:
|
|
case LB_FINDSTRINGEXACT:
|
|
case LB_INSERTSTRING:
|
|
case LB_SELECTSTRING:
|
|
case CB_FINDSTRING:
|
|
case CB_FINDSTRINGEXACT:
|
|
case CB_INSERTSTRING:
|
|
case CB_SELECTSTRING:
|
|
{
|
|
if (MLIsEnabled(hWnd))
|
|
{
|
|
UINT uiMsgTx;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_SETTEXT:
|
|
uiMsgTx = g_ML_SETTEXT;
|
|
break;
|
|
case LB_ADDSTRING:
|
|
uiMsgTx = g_ML_LB_ADDSTRING;
|
|
break;
|
|
case CB_ADDSTRING:
|
|
uiMsgTx = g_ML_CB_ADDSTRING;
|
|
break;
|
|
case LB_FINDSTRING:
|
|
uiMsgTx = g_ML_LB_FINDSTRING;
|
|
break;
|
|
case LB_FINDSTRINGEXACT:
|
|
uiMsgTx = g_ML_LB_FINDSTRINGEXACT;
|
|
break;
|
|
case LB_INSERTSTRING:
|
|
uiMsgTx = g_ML_LB_INSERTSTRING;
|
|
break;
|
|
case LB_SELECTSTRING:
|
|
uiMsgTx = g_ML_LB_SELECTSTRING;
|
|
break;
|
|
case CB_FINDSTRING:
|
|
uiMsgTx = g_ML_CB_FINDSTRING;
|
|
break;
|
|
case CB_FINDSTRINGEXACT:
|
|
uiMsgTx = g_ML_CB_FINDSTRINGEXACT;
|
|
break;
|
|
case CB_INSERTSTRING:
|
|
uiMsgTx = g_ML_CB_INSERTSTRING;
|
|
break;
|
|
case CB_SELECTSTRING:
|
|
uiMsgTx = g_ML_CB_SELECTSTRING;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
return SendMessageA(hWnd, uiMsgTx, wParam, lParam);
|
|
}
|
|
else if (Msg == CB_FINDSTRINGEXACT && IsUnicodeComboEx(hWnd))
|
|
{
|
|
// ComboEx is in UNICODE mode so we can send it the
|
|
// unicode string
|
|
goto Ldef;
|
|
}
|
|
else
|
|
{
|
|
// WARNING: in the ADDSTRING and INSERTSTRING cases for OWNERDRAW !HASSTRING
|
|
// then this is a pointer to a structure and not a string!!! (Seems that only
|
|
// code that does this is comctl32's comboex, which currently doesn't come here.)
|
|
//
|
|
CStrIn str((LPWSTR) lParam);
|
|
|
|
return SendMessageA(hWnd, Msg, wParam, (LPARAM) (LPSTR) str);
|
|
}
|
|
}
|
|
|
|
case WM_GETTEXT:
|
|
case LB_GETTEXT:
|
|
case CB_GETLBTEXT:
|
|
{
|
|
if (MLIsEnabled(hWnd))
|
|
{
|
|
UINT uiMsgTx;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_GETTEXT:
|
|
uiMsgTx = g_ML_GETTEXT;
|
|
break;
|
|
case LB_GETTEXT:
|
|
uiMsgTx = g_ML_LB_GETTEXT;
|
|
break;
|
|
case CB_GETLBTEXT:
|
|
uiMsgTx = g_ML_CB_GETLBTEXT;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
return SendMessageA(hWnd, uiMsgTx, wParam, lParam);
|
|
}
|
|
else if (Msg == CB_GETLBTEXT && IsUnicodeComboEx(hWnd))
|
|
{
|
|
// ComboEx is in UNICODE mode so we can send it the
|
|
// unicode string
|
|
goto Ldef;
|
|
}
|
|
else
|
|
{
|
|
int iStrLen;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_GETTEXT:
|
|
iStrLen = (int)wParam;
|
|
break;
|
|
case LB_GETTEXT:
|
|
iStrLen = SendMessageA(hWnd, LB_GETTEXTLEN, wParam, lParam);
|
|
if (iStrLen == LB_ERR)
|
|
iStrLen = 255;
|
|
break;
|
|
case CB_GETLBTEXT:
|
|
iStrLen = SendMessageA(hWnd, CB_GETLBTEXTLEN, wParam, lParam);
|
|
if (iStrLen == CB_ERR)
|
|
iStrLen = 255;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
CStrOut str((LPWSTR)lParam, (iStrLen + 1));
|
|
SendMessageA(hWnd, Msg, wParam, (LPARAM) (LPSTR) str);
|
|
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
}
|
|
|
|
case WM_GETTEXTLENGTH:
|
|
case LB_GETTEXTLEN:
|
|
case CB_GETLBTEXTLEN:
|
|
{
|
|
UINT uiMsgTx;
|
|
|
|
if (MLIsEnabled(hWnd))
|
|
{
|
|
switch (Msg)
|
|
{
|
|
case WM_GETTEXTLENGTH:
|
|
uiMsgTx = g_ML_GETTEXTLENGTH;
|
|
break;
|
|
case LB_GETTEXTLEN:
|
|
uiMsgTx = g_ML_LB_GETTEXTLEN;
|
|
break;
|
|
case CB_GETLBTEXTLEN:
|
|
uiMsgTx = g_ML_CB_GETLBTEXTLEN;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
|
|
return SendMessageA(hWnd, uiMsgTx, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
// Bug: #70280
|
|
// we can not just return the size of ANSI character back, it breaks some localized
|
|
// version of Win98 with localized IE/OE scenario: some apps rely on the returned size
|
|
// in characters to show the string and may cause the garbage displayed beyond the end of
|
|
// the actual string.
|
|
//
|
|
LPWSTR lpwszTemp = NULL;
|
|
int iWCharLen = 0;
|
|
int iAnsiCharLen = SendMessageA(hWnd, Msg, wParam, lParam);
|
|
if ((iAnsiCharLen <= 0) || (LB_ERR == iAnsiCharLen) || (CB_ERR == iAnsiCharLen))
|
|
{
|
|
iWCharLen = iAnsiCharLen; // return error if we can not get the ANSI string length
|
|
goto L_Rtn;
|
|
}
|
|
|
|
// we always allocate the wide string buffer in the size of ANSI string length plus 1,
|
|
// it should be big enough to hold the returned wide string.
|
|
lpwszTemp = (LPWSTR)LocalAlloc(LPTR, ((iAnsiCharLen + 1) * sizeof(WCHAR)));
|
|
if (!lpwszTemp)
|
|
goto L_Rtn;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_GETTEXTLENGTH:
|
|
uiMsgTx = WM_GETTEXT;
|
|
break;
|
|
case LB_GETTEXTLEN:
|
|
uiMsgTx = LB_GETTEXT;
|
|
break;
|
|
case CB_GETLBTEXTLEN:
|
|
uiMsgTx = CB_GETLBTEXT;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
iWCharLen = SendMessageAThunk(hWnd, uiMsgTx,
|
|
((uiMsgTx == WM_GETTEXT) ? (WPARAM)(iAnsiCharLen + 1) : wParam),
|
|
(LPARAM)lpwszTemp);
|
|
|
|
L_Rtn:
|
|
if (lpwszTemp)
|
|
LocalFree(lpwszTemp);
|
|
|
|
// if error occured, we'll return the error (WM_, LB_, CB_),
|
|
// if fail to allocate memory, we'll return 0, the initial value of iWCharlen.
|
|
return (LRESULT)iWCharLen;
|
|
}
|
|
}
|
|
|
|
case WM_SETTINGCHANGE:
|
|
{
|
|
if (lParam)
|
|
{
|
|
CStrIn str((LPWSTR)lParam);
|
|
LRESULT lRes = 0;
|
|
SendMessageTimeoutA(hWnd, Msg, wParam, (LPARAM) (LPSTR) str,
|
|
SMTO_NORMAL, 3000, (PULONG_PTR)&lRes);
|
|
|
|
return lRes;
|
|
}
|
|
goto Ldef;
|
|
}
|
|
|
|
// The new unicode comctl32.dll handles these correctly so we don't need to thunk:
|
|
// TTM_DELTOOL, TTM_ADDTOOL, TVM_INSERTITEM, TVM_GETITEM, TCM_INSERTITEM, TCM_SETITEM
|
|
|
|
default:
|
|
Ldef:
|
|
return SendMessageA(hWnd, Msg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT WINAPI
|
|
SendMessageTimeoutAThunk(
|
|
HWND hWnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
UINT fuFlags,
|
|
UINT uTimeout,
|
|
PULONG_PTR lpdwResult)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_SETTINGCHANGE:
|
|
{
|
|
if (lParam)
|
|
{
|
|
CStrIn str((LPWSTR)lParam);
|
|
return SendMessageTimeoutA(hWnd, uMsg, wParam, (LPARAM)(LPSTR)str,
|
|
fuFlags, uTimeout, lpdwResult);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return SendMessageTimeoutA(hWnd, uMsg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
|
|
}
|
|
|
|
|
|
LRESULT FORWARD_API WINAPI
|
|
SendMessageTimeoutWrapW(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
UINT fuFlags,
|
|
UINT uTimeout,
|
|
PULONG_PTR lpdwResult)
|
|
{
|
|
VALIDATE_PROTOTYPE(SendMessage);
|
|
|
|
// perf: we should do _asm here (see CallWindowProcWrapW), but
|
|
// to do that we need to 'outline' the below switch (o.w. we
|
|
// can't be 'naked'). that in turn slows down the non-NT case...
|
|
|
|
#ifndef UNIX
|
|
THUNK_AW(SendMessageTimeout, (hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult));
|
|
#else
|
|
return SendMessageTimeoutW(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
|
|
#endif
|
|
}
|
|
|
|
LRESULT FORWARD_API WINAPI
|
|
SendMessageWrapW(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
VALIDATE_PROTOTYPE(SendMessage);
|
|
|
|
// perf: we should do _asm here (see CallWindowProcWrapW), but
|
|
// to do that we need to 'outline' the below switch (o.w. we
|
|
// can't be 'naked'). that in turn slows down the non-NT case...
|
|
|
|
#ifndef UNIX
|
|
// n.b. THUNK not FORWARD
|
|
THUNK_AW(SendMessage, (hWnd, Msg, wParam, lParam));
|
|
#else
|
|
return SendMessageW(hWnd, Msg, wParam, lParam);
|
|
#endif
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SetCurrentDirectoryWrapW(LPCWSTR lpszCurDir)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetCurrentDirectory);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SetCurrentDirectoryW(lpszCurDir);
|
|
}
|
|
|
|
CStrIn str(lpszCurDir);
|
|
|
|
return SetCurrentDirectoryA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SetDlgItemTextWrapW(HWND hDlg, int nIDDlgItem, LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetDlgItemText);
|
|
|
|
HWND hWnd = GetDlgItem(hDlg, nIDDlgItem);
|
|
|
|
if (hWnd)
|
|
return SetWindowTextWrapW(hWnd, lpString);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SetPropWrapW(
|
|
HWND hWnd,
|
|
LPCWSTR lpString,
|
|
HANDLE hData)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetProp);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SetPropW(hWnd, lpString, hData);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return SetPropA(hWnd, str, hData);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
LONG FORWARD_API WINAPI
|
|
SetWindowLongWrapW(HWND hWnd, int nIndex, LONG dwNewLong)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetWindowLong);
|
|
|
|
FORWARD_AW(SetWindowLong, (hWnd, nIndex, dwNewLong));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HHOOK
|
|
FORWARD_API WINAPI
|
|
SetWindowsHookExWrapW(
|
|
int idHook,
|
|
HOOKPROC lpfn,
|
|
HINSTANCE hmod,
|
|
DWORD dwThreadId)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetWindowsHookEx);
|
|
|
|
FORWARD_AW(SetWindowsHookEx, (idHook, lpfn, hmod, dwThreadId));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SetWindowTextWrapW(HWND hWnd, LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetWindowText);
|
|
|
|
if (MLIsEnabled(hWnd))
|
|
return MLSetControlTextI(hWnd, lpString);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SetWindowTextW(hWnd, lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return SetWindowTextA(hWnd, str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SystemParametersInfoWrapW(
|
|
UINT uiAction,
|
|
UINT uiParam,
|
|
PVOID pvParam,
|
|
UINT fWinIni)
|
|
{
|
|
VALIDATE_PROTOTYPE(SystemParametersInfo);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SystemParametersInfoW(
|
|
uiAction,
|
|
uiParam,
|
|
pvParam,
|
|
fWinIni);
|
|
}
|
|
|
|
BOOL ret;
|
|
char ach[LF_FACESIZE];
|
|
|
|
if (uiAction == SPI_SETDESKWALLPAPER)
|
|
{
|
|
CStrIn str((LPCWSTR) pvParam);
|
|
|
|
ret = SystemParametersInfoA(
|
|
uiAction,
|
|
uiParam,
|
|
str,
|
|
fWinIni);
|
|
}
|
|
else
|
|
ret = SystemParametersInfoA(
|
|
uiAction,
|
|
uiParam,
|
|
pvParam,
|
|
fWinIni);
|
|
|
|
if ((uiAction == SPI_GETICONTITLELOGFONT) && ret)
|
|
{
|
|
strcpy(ach, ((LPLOGFONTA)pvParam)->lfFaceName);
|
|
SHAnsiToUnicode(ach, ((LPLOGFONTW)pvParam)->lfFaceName, ARRAYSIZE(((LPLOGFONTW)pvParam)->lfFaceName));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int FORWARD_API WINAPI
|
|
TranslateAcceleratorWrapW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
|
|
{
|
|
VALIDATE_PROTOTYPE(TranslateAccelerator);
|
|
|
|
FORWARD_AW(TranslateAccelerator, (hWnd, hAccTable, lpMsg));
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
UnregisterClassWrapW(LPCWSTR lpClassName, HINSTANCE hInstance)
|
|
{
|
|
VALIDATE_PROTOTYPE(UnregisterClass);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return UnregisterClassW(lpClassName, hInstance);
|
|
}
|
|
|
|
CStrIn str(lpClassName);
|
|
|
|
return UnregisterClassA(str, hInstance);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
SHORT
|
|
WINAPI
|
|
VkKeyScanWrapW(WCHAR ch)
|
|
{
|
|
VALIDATE_PROTOTYPE(VkKeyScan);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return VkKeyScanW(ch);
|
|
}
|
|
|
|
CStrIn str(&ch, 1);
|
|
|
|
return VkKeyScanA(*(char *)str);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
WinHelpWrapW(HWND hwnd, LPCWSTR szFile, UINT uCmd, ULONG_PTR dwData)
|
|
{
|
|
VALIDATE_PROTOTYPE(WinHelp);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return WinHelpW(hwnd, szFile, uCmd, dwData);
|
|
}
|
|
|
|
CStrIn str(szFile);
|
|
|
|
return WinHelpA(hwnd, str, uCmd, dwData);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wvsprintfW
|
|
//
|
|
// Synopsis: Nightmare string function
|
|
//
|
|
// Arguments: [pwszOut] --
|
|
// [pwszFormat] --
|
|
// [...] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-06-94 ErikGav Created
|
|
//
|
|
// Notes: If you're reading this, you're probably having a problem with
|
|
// this function. Make sure that your "%s" in the format string
|
|
// says "%ws" if you are passing wide strings.
|
|
//
|
|
// %s on NT means "wide string"
|
|
// %s on Chicago means "ANSI string"
|
|
//
|
|
// NOTE: This function should not be used. Use Format instead.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int WINAPI
|
|
wvsprintfWrapW(LPWSTR pwszOut, LPCWSTR pwszFormat, va_list arglist)
|
|
{
|
|
VALIDATE_PROTOTYPE(wvsprintf);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return wvsprintfW(pwszOut, pwszFormat, arglist);
|
|
}
|
|
|
|
// Old code created a 1K ansi output buffer for wvsprintfA and then
|
|
// thunked the result. If we're going to do that, might as
|
|
// well create a 1K unicode output buffer and call our wvnsprintfW
|
|
// implementation directly. Two benefits: 1) no buffer overrun
|
|
// and 2) native W implementation so we can handle unicode strings!
|
|
WCHAR wszOut[1024];
|
|
|
|
wvnsprintfW(wszOut, ARRAYSIZE(wszOut), pwszFormat, arglist);
|
|
|
|
// Roll our own "ConvertExcludingNul" since this is W->W
|
|
int ret = SHUnicodeToUnicode(wszOut, pwszOut, ARRAYSIZE(wszOut));
|
|
if (ret > 0)
|
|
{
|
|
ret -= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_MPR_WRAPPER
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: WNetRestoreConnectionWrapW
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI WNetRestoreConnectionWrapW(IN HWND hwndParent, IN LPCWSTR pwzDevice)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return WNetRestoreConnectionW(hwndParent, pwzDevice);
|
|
}
|
|
|
|
CStrIn strIn(pwzDevice);
|
|
return WNetRestoreConnectionA(hwndParent, strIn);
|
|
}
|
|
|
|
#endif // NEED_MPR_WRAPPER
|
|
|
|
#ifdef NEED_MPR_WRAPPER
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: WNetGetLastErrorWrapW
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI WNetGetLastErrorWrapW(OUT LPDWORD pdwError, OUT LPWSTR pwzErrorBuf, IN DWORD cchErrorBufSize, OUT LPWSTR pwzNameBuf, IN DWORD cchNameBufSize)
|
|
{
|
|
VALIDATE_PROTOTYPE(WNetGetLastError);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return WNetGetLastErrorW(pdwError, pwzErrorBuf, cchErrorBufSize, pwzNameBuf, cchNameBufSize);
|
|
}
|
|
|
|
// Consider: Out-string bufsize too large or small?
|
|
CStrOut strErrorOut(pwzErrorBuf, cchErrorBufSize);
|
|
CStrOut strNameOut(pwzNameBuf, cchNameBufSize);
|
|
|
|
DWORD dwResult = WNetGetLastErrorA(pdwError, strErrorOut, strErrorOut.BufSize(), strNameOut, strNameOut.BufSize());
|
|
|
|
strErrorOut.ConvertExcludingNul();
|
|
strNameOut.ConvertExcludingNul();
|
|
return dwResult;
|
|
}
|
|
|
|
#endif // NEED_MPR_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
int WINAPI DrawTextExWrapW(
|
|
HDC hdc, // handle of device context
|
|
LPWSTR pwzText, // address of string to draw
|
|
int cchText, // length of string to draw
|
|
LPRECT lprc, // address of rectangle coordinates
|
|
UINT dwDTFormat, // formatting options
|
|
LPDRAWTEXTPARAMS lpDTParams // address of structure for more options
|
|
)
|
|
{
|
|
VALIDATE_PROTOTYPE(DrawTextEx);
|
|
if (_MayNeedFontLinking(pwzText, cchText))
|
|
{
|
|
return DrawTextExFLW(hdc, pwzText, cchText, lprc, dwDTFormat, lpDTParams);
|
|
}
|
|
else if (g_bRunningOnNT)
|
|
{
|
|
return DrawTextExW(hdc, pwzText, cchText, lprc, dwDTFormat, lpDTParams);
|
|
}
|
|
CStrIn strText(pwzText, cchText);
|
|
return DrawTextExA(hdc, strText, strText.strlen(), lprc, dwDTFormat, lpDTParams);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
void SetThunkMenuItemInfoWToA(LPCMENUITEMINFOW pmiiW, LPMENUITEMINFOA pmiiA, LPSTR pszBuffer, DWORD cchSize)
|
|
{
|
|
*pmiiA = *(LPMENUITEMINFOA) pmiiW;
|
|
|
|
// MFT_STRING is Zero. So MFT_STRING & anything evaluates to False.
|
|
// so instead you have to check for the absence of non-string items
|
|
if ((pmiiW->dwTypeData) && (MFT_NONSTRING & pmiiW->fType) == 0)
|
|
{
|
|
pmiiA->dwTypeData = pszBuffer;
|
|
pmiiA->cch = cchSize;
|
|
SHUnicodeToAnsi(pmiiW->dwTypeData, pmiiA->dwTypeData, cchSize);
|
|
}
|
|
}
|
|
|
|
void GetThunkMenuItemInfoWToA(LPCMENUITEMINFOW pmiiW, LPMENUITEMINFOA pmiiA, LPSTR pszBuffer, DWORD cchSize)
|
|
{
|
|
*pmiiA = *(LPMENUITEMINFOA) pmiiW;
|
|
|
|
if ((pmiiW->dwTypeData) && (MFT_STRING & pmiiW->fType))
|
|
{
|
|
pszBuffer[0] = 0;
|
|
pmiiA->dwTypeData = pszBuffer;
|
|
pmiiA->cch = cchSize;
|
|
}
|
|
}
|
|
|
|
void GetThunkMenuItemInfoAToW(LPCMENUITEMINFOA pmiiA, LPMENUITEMINFOW pmiiW)
|
|
{
|
|
LPWSTR pwzText = pmiiW->dwTypeData;
|
|
UINT cch = pmiiW->cch;
|
|
|
|
*pmiiW = *(LPMENUITEMINFOW) pmiiA;
|
|
pmiiW->dwTypeData = pwzText;
|
|
pmiiW->cch = cch;
|
|
|
|
if ((pmiiA->cch > 0) && (pmiiA->dwTypeData) && (pwzText) && !((MFT_SEPARATOR | MFT_BITMAP) & pmiiA->fType))
|
|
SHAnsiToUnicode(pmiiA->dwTypeData, pmiiW->dwTypeData, pmiiW->cch);
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI GetMenuItemInfoWrapW(
|
|
HMENU hMenu,
|
|
UINT uItem,
|
|
BOOL fByPosition,
|
|
LPMENUITEMINFOW pmiiW)
|
|
{
|
|
BOOL fResult;
|
|
VALIDATE_PROTOTYPE(GetMenuItemInfo);
|
|
ASSERT(pmiiW->cbSize == MENUITEMINFOSIZE_WIN95); // Ensure Win95 compatibility
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
BOOL fItemData;
|
|
DWORD_PTR dwItemData;
|
|
LPWSTR pwz;
|
|
UINT cch;
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
if (MIIM_DATA & pmiiW->fMask)
|
|
fItemData = TRUE;
|
|
else
|
|
{
|
|
fItemData = FALSE;
|
|
pmiiW->fMask |= MIIM_DATA;
|
|
}
|
|
pwz = pmiiW->dwTypeData; // save original buffer pointer
|
|
cch = pmiiW->cch; // save original buffer size
|
|
dwItemData = pmiiW->dwItemData; // save original dwItemData size
|
|
}
|
|
|
|
#ifndef UNIX
|
|
// Widechar API's are messed up in MAINWIN. For now assume not ruuning on
|
|
// NT for this.
|
|
if (g_bRunningOnNT)
|
|
fResult = GetMenuItemInfoW(hMenu, uItem, fByPosition, pmiiW);
|
|
else
|
|
#endif
|
|
{
|
|
if (pmiiW->fMask & MIIM_TYPE)
|
|
{
|
|
MENUITEMINFOA miiA = *(LPMENUITEMINFOA)pmiiW;
|
|
LPSTR pszText = NULL;
|
|
|
|
if (pmiiW->cch > 0)
|
|
pszText = new char[pmiiW->cch * 2]; // for DBCS, we multifly by 2
|
|
|
|
miiA.dwTypeData = pszText;
|
|
miiA.cch = (pszText)? pmiiW->cch * 2: 0; // set correct buffer size
|
|
fResult = GetMenuItemInfoA(hMenu, uItem, fByPosition, &miiA);
|
|
GetThunkMenuItemInfoAToW(&miiA, pmiiW);
|
|
|
|
if (pszText)
|
|
delete pszText;
|
|
}
|
|
else
|
|
fResult = GetMenuItemInfoA(hMenu, uItem, fByPosition, (LPMENUITEMINFOA) pmiiW); // It doesn't contain a string so W and A are the same.
|
|
}
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
if ((MIIM_TYPE & pmiiW->fMask) && (MFT_OWNERDRAW & pmiiW->fType))
|
|
{
|
|
LPPUIMENUITEM lpItem = (LPPUIMENUITEM)pmiiW->dwItemData;
|
|
|
|
if (!IsBadReadPtr(lpItem, sizeof(lpItem->dwSig)) && PUI_OWNERDRAW_SIG == lpItem->dwSig && !(MFT_OWNERDRAW & lpItem->fType))
|
|
{
|
|
if ((cch > 0) && pwz && !((MFT_SEPARATOR | MFT_BITMAP) & pmiiW->fType))
|
|
{
|
|
StrCpyNW(pwz, lpItem->lpwz, cch);
|
|
pmiiW->dwTypeData = pwz;
|
|
pmiiW->cch = lpItem->cch;
|
|
pmiiW->fType &= ~MFT_OWNERDRAW;
|
|
if (fItemData)
|
|
pmiiW->dwItemData = lpItem->dwItemData;
|
|
else
|
|
pmiiW->dwItemData = dwItemData;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI InsertMenuItemWrapW(
|
|
HMENU hMenu,
|
|
UINT uItem,
|
|
BOOL fByPosition,
|
|
LPCMENUITEMINFOW pmiiW)
|
|
{
|
|
VALIDATE_PROTOTYPE(InsertMenuItem);
|
|
ASSERT(pmiiW->cbSize == MENUITEMINFOSIZE_WIN95); // Ensure Win95 compatibility
|
|
|
|
BOOL fResult;
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
MENUITEMINFOW miiW;
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
MungeMenuItem(hMenu, pmiiW, &miiW);
|
|
pmiiW = &miiW;
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
return InsertMenuItemW(hMenu, uItem, fByPosition, pmiiW);
|
|
|
|
MENUITEMINFOA miiA;
|
|
CHAR szText[INTERNET_MAX_URL_LENGTH];
|
|
|
|
SetThunkMenuItemInfoWToA(pmiiW, &miiA, szText, ARRAYSIZE(szText));
|
|
fResult = InsertMenuItemA(hMenu, uItem, fByPosition, &miiA);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
// This is required for ML, so do not put inside #ifdef NEED_USER32_WRAPPER
|
|
|
|
BOOL WINAPI
|
|
SetMenuItemInfoWrapW(
|
|
HMENU hMenu,
|
|
UINT uItem,
|
|
BOOL fByPosition,
|
|
LPCMENUITEMINFOW lpmiiW)
|
|
{
|
|
VALIDATE_PROTOTYPE(SetMenuItemInfo);
|
|
ASSERT(lpmiiW->cbSize == MENUITEMINFOSIZE_WIN95); // Ensure Win95 compatibility
|
|
|
|
static BOOL bOwnerDraw = NeedMenuOwnerDraw();
|
|
MENUITEMINFOW miiW;
|
|
|
|
if (bOwnerDraw)
|
|
{
|
|
if ( (MIIM_TYPE & lpmiiW->fMask) &&
|
|
0 == (lpmiiW->fType & (MFT_BITMAP | MFT_SEPARATOR)))
|
|
{
|
|
DeleteOwnerDrawMenuItem(hMenu, uItem, fByPosition);
|
|
MungeMenuItem(hMenu, lpmiiW, &miiW);
|
|
lpmiiW = &miiW;
|
|
}
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SetMenuItemInfoW( hMenu, uItem, fByPosition, lpmiiW);
|
|
}
|
|
|
|
BOOL fRet;
|
|
|
|
ASSERT( sizeof(MENUITEMINFOW) == sizeof(MENUITEMINFOA) &&
|
|
FIELD_OFFSET(MENUITEMINFOW, dwTypeData) ==
|
|
FIELD_OFFSET(MENUITEMINFOA, dwTypeData) );
|
|
|
|
if ( (MIIM_TYPE & lpmiiW->fMask) &&
|
|
0 == (lpmiiW->fType & (MFT_BITMAP | MFT_SEPARATOR)))
|
|
{
|
|
MENUITEMINFOA miiA;
|
|
// the cch is ignored on SetMenuItemInfo
|
|
CStrIn str((LPWSTR)lpmiiW->dwTypeData, -1);
|
|
|
|
memcpy( &miiA, lpmiiW, sizeof(MENUITEMINFOA) );
|
|
miiA.dwTypeData = (LPSTR)str;
|
|
miiA.cch = str.strlen();
|
|
|
|
fRet = SetMenuItemInfoA( hMenu, uItem, fByPosition, &miiA );
|
|
}
|
|
else
|
|
{
|
|
fRet = SetMenuItemInfoA( hMenu, uItem, fByPosition,
|
|
(LPCMENUITEMINFOA)lpmiiW );
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
HFONT WINAPI
|
|
CreateFontWrapW(int nHeight, // logical height of font
|
|
int nWidth, // logical average character width
|
|
int nEscapement, // angle of escapement
|
|
int nOrientation, // base-line orientation angle
|
|
int fnWeight, // font weight
|
|
DWORD fdwItalic, // italic attribute flag
|
|
DWORD fdwUnderline, // underline attribute flag
|
|
DWORD fdwStrikeOut, // strikeout attribute flag
|
|
DWORD fdwCharSet, // character set identifier
|
|
DWORD fdwOutputPrecision, // output precision
|
|
DWORD fdwClipPrecision, // clipping precision
|
|
DWORD fdwQuality, // output quality
|
|
DWORD fdwPitchAndFamily, // pitch and family
|
|
LPCWSTR pwzFace) // address of typeface name string )
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateFont);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateFontW(nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic,
|
|
fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision,
|
|
fdwClipPrecision, fdwQuality, fdwPitchAndFamily, pwzFace);
|
|
}
|
|
|
|
CStrIn str(pwzFace);
|
|
return CreateFontA(nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic,
|
|
fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision,
|
|
fdwClipPrecision, fdwQuality, fdwPitchAndFamily, str);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI CreateMutexWrapW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR pwzName)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateMutex);
|
|
|
|
if (g_bRunningOnNT)
|
|
return CreateMutexW(lpMutexAttributes, bInitialOwner, pwzName);
|
|
|
|
CStrIn strText(pwzName);
|
|
return CreateMutexA(lpMutexAttributes, bInitialOwner, strText);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
HDC WINAPI CreateMetaFileWrapW(LPCWSTR pwzFile)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateMetaFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
return CreateMetaFileW(pwzFile);
|
|
|
|
CStrIn strText(pwzFile);
|
|
return CreateMetaFileA(strText);
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
// ExpandEnvironmentStrings returns the size of the needed string
|
|
DWORD WINAPI ExpandEnvironmentStringsWrapW(LPCWSTR pwzSrc, LPWSTR pwzDst, DWORD cchSize)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
if (pwzDst)
|
|
{
|
|
VALIDATE_OUTBUF(pwzDst, cchSize);
|
|
}
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
dwRet = ExpandEnvironmentStringsW(pwzSrc, pwzDst, cchSize);
|
|
}
|
|
else
|
|
{
|
|
CStrIn strTextIn(pwzSrc);
|
|
CStrOut strTextOut(pwzDst, cchSize);
|
|
DWORD dwResult = ExpandEnvironmentStringsA(strTextIn, strTextOut, strTextOut.BufSize());
|
|
DWORD dwResultUnicode = strTextOut.ConvertIncludingNul();
|
|
|
|
// NT4 returned the number of bytes in the UNICODE string, not the number
|
|
// of bytes in the ANSI string. NT5 returns the number of bytes in the UNICODE
|
|
// string divided by 2, so it has even less bearing on the ansi string. Hopefully
|
|
// the Win9x implementations did the right thing...
|
|
//
|
|
if (dwResult <= cchSize)
|
|
{
|
|
ASSERT(dwResultUnicode <= dwResult);
|
|
dwRet = dwResultUnicode; // we fit in the out buffer, give accurate count
|
|
}
|
|
else
|
|
{
|
|
dwRet = dwResult; // buffer was too small, let caller know (NOTE: this may be bigger than needed)
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
// SHExpandEnvironmentStrings
|
|
//
|
|
// In all cases, this returns a valid output buffer. The buffer may
|
|
// be empty, or it may be truncated, but you can always use the string.
|
|
//
|
|
// RETURN VALUE:
|
|
// 0 implies failure, either a truncated expansion or no expansion whatsoever
|
|
// >0 implies complete expansion, value is count of characters written (excluding NULL)
|
|
//
|
|
DWORD WINAPI SHExpandEnvironmentStringsForUserW(HANDLE hToken, LPCWSTR pwzSrc, LPWSTR pwzDst, DWORD cchSize)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
// 99/05/28 vtan: Handle specified users here. It's a Windows NT
|
|
// thing only. Check for both conditions then load the function
|
|
// dynamically out of userenv.dll. If the function cannot be
|
|
// located or returns a problem default to the current user as
|
|
// NULL hToken.
|
|
|
|
if (g_bRunningOnNT5OrHigher && (hToken != NULL))
|
|
{
|
|
VALIDATE_OUTBUF(pwzDst, cchSize);
|
|
if (NT5_ExpandEnvironmentStringsForUserW(hToken, pwzSrc, pwzDst, cchSize) != FALSE)
|
|
{
|
|
|
|
// userenv!ExpandEnvironmentStringsForUser returns
|
|
// a BOOL result. Convert this to a DWORD result
|
|
// that matches what kernel32!ExpandEnvironmentStrings
|
|
// returns.
|
|
|
|
dwRet = lstrlenW(pwzDst) + sizeof('\0');
|
|
}
|
|
else
|
|
{
|
|
dwRet = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = ExpandEnvironmentStringsWrapW(pwzSrc, pwzDst, cchSize);
|
|
}
|
|
|
|
// The implementations of this function don't seem to gurantee gurantee certain
|
|
// things about the output buffer in failure conditions that callers rely on.
|
|
// So clean things up here.
|
|
//
|
|
// And I found code occasionally that handled semi-failure (success w/ dwRet>cchSize)
|
|
// that assumed the string wasn't properly NULL terminated in this case. Fix that here
|
|
// in the wrapper so our callers don't have to wig-out about errors.
|
|
//
|
|
// NOTE: we map all failures to 0 too.
|
|
//
|
|
if (dwRet > cchSize)
|
|
{
|
|
// Buffer too small, some code assumed there was still a string there and
|
|
// tried to NULL terminate, do it for them.
|
|
SHTruncateString(pwzDst, cchSize);
|
|
dwRet = 0;
|
|
}
|
|
else if (dwRet == 0)
|
|
{
|
|
// Failure, assume no expansions...
|
|
StrCpyNW(pwzDst, pwzSrc, cchSize);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
DWORD WINAPI SHExpandEnvironmentStringsW(LPCWSTR pwzSrc, LPWSTR pwzDst, DWORD cchSize)
|
|
{
|
|
return(SHExpandEnvironmentStringsForUserW(NULL, pwzSrc, pwzDst, cchSize));
|
|
}
|
|
|
|
DWORD WINAPI SHExpandEnvironmentStringsForUserA(HANDLE hToken, LPCSTR pszSrc, LPSTR pszDst, DWORD cchSize)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
// 99/05/28 vtan: The ANSI version of SHExpandEnvironmentStringsForUser
|
|
// exists in case somebody calls the ANSI implementation in WindowsNT.
|
|
// This is meaningless on Win9x. This just thunks parameters and invokes
|
|
// the Unicode implementation. If a problem occurs when thunking just
|
|
// use the current user.
|
|
|
|
if (g_bRunningOnNT5OrHigher && (hToken != NULL))
|
|
{
|
|
DWORD dwResultAnsi;
|
|
CStrInW strInW(pszSrc);
|
|
CStrOutW strOutW(pszDst, cchSize);
|
|
|
|
dwRet = SHExpandEnvironmentStringsForUserW(hToken, strInW, strOutW, strOutW.BufSize());
|
|
dwResultAnsi = strOutW.ConvertIncludingNul();
|
|
if (dwResultAnsi <= cchSize)
|
|
dwRet = dwResultAnsi;
|
|
}
|
|
else
|
|
{
|
|
// NT4 returns the number of bytes in the UNICODE string.
|
|
//
|
|
// NT5 (as of June 99) returns the number of bytes in the UNICODE string / 2, so it
|
|
// really has no accurate bearing on the number of ansi characters. Plus we're not
|
|
// guranteed buffer truncation in failure case.
|
|
//
|
|
// Not much we can do about it here, eh? Hopefully our callers ignore the return result...
|
|
//
|
|
dwRet = ExpandEnvironmentStringsA(pszSrc, pszDst, cchSize);
|
|
}
|
|
|
|
// The implementations of this function don't seem to gurantee gurantee certain
|
|
// things about the output buffer in failure conditions that callers rely on.
|
|
// So clean things up here.
|
|
//
|
|
// And I found code occasionally that handled semi-failure (success w/ dwRet>cchSize)
|
|
// that assumed the string wasn't properly NULL terminated in this case. Fix that here
|
|
// in the wrapper so our callers don't have to wig-out about errors.
|
|
//
|
|
// NOTE: we map all failures to 0 too.
|
|
//
|
|
if (dwRet > cchSize)
|
|
{
|
|
// Buffer too small, make sure it's NULL terminated.
|
|
SHTruncateString(pszDst, cchSize);
|
|
dwRet = 0;
|
|
}
|
|
else if (dwRet == 0)
|
|
{
|
|
// Failure, assume no expansions...
|
|
StrCpyNA(pszDst, pszSrc, cchSize);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
DWORD WINAPI SHExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pszDst, DWORD cchSize)
|
|
{
|
|
return(SHExpandEnvironmentStringsForUserA(NULL, pszSrc, pszDst, cchSize));
|
|
}
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HANDLE WINAPI CreateSemaphoreWrapW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR pwzName)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateSemaphore);
|
|
if (g_bRunningOnNT)
|
|
return CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, pwzName);
|
|
|
|
CStrIn strText(pwzName);
|
|
return CreateSemaphoreA(lpSemaphoreAttributes, lInitialCount, lMaximumCount, strText);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
// FEATURE: Todo - GetStartupInfoWrapW
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
#define ISGOOD 0
|
|
#define ISBAD 1
|
|
|
|
BOOL WINAPI IsBadStringPtrWrapW(LPCWSTR pwzString, UINT_PTR ucchMax)
|
|
{
|
|
VALIDATE_PROTOTYPE(IsBadStringPtr);
|
|
if (g_bRunningOnNT)
|
|
return IsBadStringPtrW(pwzString, ucchMax);
|
|
|
|
if (!ucchMax)
|
|
return ISGOOD;
|
|
|
|
if (!pwzString)
|
|
return ISBAD;
|
|
|
|
LPCWSTR pwzStartAddress = pwzString;
|
|
// ucchMax maybe -1 but that's ok because the loop down below will just
|
|
// look for the terminator.
|
|
LPCWSTR pwzEndAddress = &pwzStartAddress[ucchMax - 1];
|
|
TCHAR chTest;
|
|
|
|
_try
|
|
{
|
|
chTest = *(volatile WCHAR *)pwzStartAddress;
|
|
while (chTest && (pwzStartAddress != pwzEndAddress))
|
|
{
|
|
pwzStartAddress++;
|
|
chTest = *(volatile WCHAR *)pwzStartAddress;
|
|
}
|
|
}
|
|
_except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return ISBAD;
|
|
}
|
|
__endexcept
|
|
|
|
return ISGOOD;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
HINSTANCE WINAPI LoadLibraryWrapW(LPCWSTR pwzLibFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(LoadLibrary);
|
|
|
|
if (g_bRunningOnNT)
|
|
return LoadLibraryW(pwzLibFileName);
|
|
|
|
CStrIn strFileName(pwzLibFileName);
|
|
return LoadLibraryA(strFileName);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
int WINAPI GetTimeFormatWrapW(LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCWSTR pwzFormat, LPWSTR pwzTimeStr, int cchTime)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetTimeFormat);
|
|
if (g_bRunningOnNT)
|
|
return GetTimeFormatW(Locale, dwFlags, lpTime, pwzFormat, pwzTimeStr, cchTime);
|
|
|
|
CStrIn strTextIn(pwzFormat);
|
|
|
|
// Cross codepage text will be trashed if it is rendered in ANSI,
|
|
// Use system codepage for conversion to make sure we don't trash native ANSI text.
|
|
CStrOut strTextOut(pwzTimeStr, cchTime);
|
|
int nResult = GetTimeFormatA(Locale, dwFlags, lpTime, strTextIn, strTextOut, strTextOut.BufSize());
|
|
if (cchTime != 0)
|
|
nResult = strTextOut.ConvertIncludingNul();
|
|
|
|
return nResult;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
int WINAPI GetDateFormatWrapW(LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCWSTR pwzFormat, LPWSTR pwzDateStr, int cchDate)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetDateFormat);
|
|
if (g_bRunningOnNT)
|
|
return GetDateFormatW(Locale, dwFlags, lpDate, pwzFormat, pwzDateStr, cchDate);
|
|
|
|
CStrIn strTextIn(pwzFormat);
|
|
CStrOut strTextOut(pwzDateStr, cchDate);
|
|
int nResult = GetDateFormatA(Locale, dwFlags, lpDate, strTextIn, strTextOut, strTextOut.BufSize());
|
|
if (cchDate != 0)
|
|
nResult = strTextOut.ConvertIncludingNul();
|
|
|
|
return nResult;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI WritePrivateProfileStringWrapW(LPCWSTR pwzAppName, LPCWSTR pwzKeyName, LPCWSTR pwzString, LPCWSTR pwzFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(WritePrivateProfileString);
|
|
if (g_bRunningOnNT)
|
|
return WritePrivateProfileStringW(pwzAppName, pwzKeyName, pwzString, pwzFileName);
|
|
|
|
CStrIn strTextAppName(pwzAppName);
|
|
CStrIn strTextKeyName(pwzKeyName);
|
|
CStrIn strTextString(pwzString);
|
|
CPPFIn strTextFileName(pwzFileName); // PrivateProfile filename needs special class
|
|
|
|
return WritePrivateProfileStringA(strTextAppName, strTextKeyName, strTextString, strTextFileName);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
DWORD WINAPI GetPrivateProfileStringWrapW(LPCWSTR pwzAppName, LPCWSTR pwzKeyName, LPCWSTR pwzDefault, LPWSTR pwzReturnedString, DWORD cchSize, LPCWSTR pwzFileName)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetPrivateProfileString);
|
|
if (g_bRunningOnNT)
|
|
return GetPrivateProfileStringW(pwzAppName, pwzKeyName, pwzDefault, pwzReturnedString, cchSize, pwzFileName);
|
|
|
|
CStrIn strTextAppName(pwzAppName);
|
|
CStrIn strTextKeyName(pwzKeyName);
|
|
CStrIn strTextDefault(pwzDefault);
|
|
CPPFIn strTextFileName(pwzFileName); // PrivateProfile filename needs special class
|
|
|
|
CStrOut strTextOut(pwzReturnedString, cchSize);
|
|
DWORD dwResult = GetPrivateProfileStringA(strTextAppName, strTextKeyName, strTextDefault, strTextOut, cchSize, strTextFileName);
|
|
strTextOut.ConvertIncludingNul();
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
STDAPI_(DWORD_PTR) SHGetFileInfoWrapW(LPCWSTR pwzPath, DWORD dwFileAttributes, SHFILEINFOW FAR *psfi, UINT cbFileInfo, UINT uFlags)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return SHGetFileInfoW(pwzPath, dwFileAttributes, psfi, cbFileInfo, uFlags);
|
|
}
|
|
|
|
SHFILEINFOA shFileInfo;
|
|
DWORD_PTR dwResult;
|
|
|
|
shFileInfo.szDisplayName[0] = 0; // Terminate so we can always thunk afterward.
|
|
shFileInfo.szTypeName[0] = 0; // Terminate so we can always thunk afterward.
|
|
|
|
// Do we need to thunk the Path?
|
|
if (SHGFI_PIDL & uFlags)
|
|
{
|
|
// No, because it's really a pidl pointer.
|
|
dwResult = SHGetFileInfoA((LPCSTR)pwzPath, dwFileAttributes, &shFileInfo, sizeof(shFileInfo), uFlags);
|
|
}
|
|
else
|
|
{
|
|
// Yes
|
|
CStrIn strPath(pwzPath);
|
|
dwResult = SHGetFileInfoA(strPath, dwFileAttributes, &shFileInfo, sizeof(shFileInfo), uFlags);
|
|
}
|
|
|
|
psfi->hIcon = shFileInfo.hIcon;
|
|
psfi->iIcon = shFileInfo.iIcon;
|
|
psfi->dwAttributes = shFileInfo.dwAttributes;
|
|
SHAnsiToUnicode(shFileInfo.szDisplayName, psfi->szDisplayName, ARRAYSIZE(shFileInfo.szDisplayName));
|
|
SHAnsiToUnicode(shFileInfo.szTypeName, psfi->szTypeName, ARRAYSIZE(shFileInfo.szTypeName));
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
STDAPI_(ATOM) RegisterClassExWrapW(CONST WNDCLASSEXW FAR * pwcx)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegisterClassEx);
|
|
if (g_bRunningOnNT)
|
|
return RegisterClassExW(pwcx);
|
|
|
|
CStrIn strMenuName(pwcx->lpszMenuName);
|
|
CStrIn strClassName(pwcx->lpszClassName);
|
|
WNDCLASSEXA wcx = *(CONST WNDCLASSEXA FAR *) pwcx;
|
|
wcx.cbSize = sizeof(wcx);
|
|
wcx.lpszMenuName = strMenuName;
|
|
wcx.lpszClassName = strClassName;
|
|
|
|
return RegisterClassExA(&wcx);
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
STDAPI_(BOOL) GetClassInfoExWrapW(HINSTANCE hinst, LPCWSTR pwzClass, LPWNDCLASSEXW lpwcx)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetClassInfoEx);
|
|
if (g_bRunningOnNT)
|
|
return GetClassInfoExW(hinst, pwzClass, lpwcx);
|
|
|
|
BOOL fResult;
|
|
CStrIn strClassName(pwzClass);
|
|
WNDCLASSEXA wcx;
|
|
wcx.cbSize = sizeof(wcx);
|
|
|
|
fResult = GetClassInfoExA(hinst, strClassName, &wcx);
|
|
*(WNDCLASSEXA FAR *) lpwcx = wcx;
|
|
lpwcx->lpszMenuName = NULL; // GetClassInfoExA makes this point off to private data that they own.
|
|
lpwcx->lpszClassName = pwzClass;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// StartDoc
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
StartDocWrapW( HDC hDC, const DOCINFO * lpdi )
|
|
{
|
|
VALIDATE_PROTOTYPE(StartDoc);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return StartDocW( hDC, lpdi );
|
|
}
|
|
|
|
CStrIn strDocName( lpdi->lpszDocName );
|
|
CStrIn strOutput( lpdi->lpszOutput );
|
|
CStrIn strDatatype( lpdi->lpszDatatype );
|
|
DOCINFOA dia;
|
|
|
|
dia.cbSize = sizeof(DOCINFO);
|
|
dia.lpszDocName = strDocName;
|
|
dia.lpszOutput = strOutput;
|
|
dia.lpszDatatype = strDatatype;
|
|
dia.fwType = lpdi->fwType;
|
|
|
|
return StartDocA( hDC, &dia );
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_GDI32_WRAPPER
|
|
|
|
STDAPI_(HCOLORSPACE)
|
|
CreateColorSpaceWrapW(LOGCOLORSPACEW * lpLogColorSpaceW)
|
|
{
|
|
VALIDATE_PROTOTYPE(CreateColorSpace);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return CreateColorSpaceW(lpLogColorSpaceW);
|
|
}
|
|
|
|
HCOLORSPACE hColorSpace;
|
|
LOGCOLORSPACEA logColorSpaceA;
|
|
|
|
memcpy(&logColorSpaceA, lpLogColorSpaceW,
|
|
FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename));
|
|
|
|
SHUnicodeToAnsi(lpLogColorSpaceW->lcsFilename,
|
|
logColorSpaceA.lcsFilename,
|
|
ARRAYSIZE(logColorSpaceA.lcsFilename));
|
|
|
|
hColorSpace = CreateColorSpaceA(&logColorSpaceA);
|
|
|
|
return hColorSpace;
|
|
}
|
|
|
|
#endif // NEED_GDI32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
STDAPI_(UINT) DragQueryFileWrapW(HDROP hDrop, UINT iFile, LPWSTR lpszFile, UINT cch)
|
|
{
|
|
VALIDATE_OUTBUF(lpszFile, cch);
|
|
|
|
//
|
|
// We are lazy and do not support lpszFile == NULL to query the length
|
|
// of an individual string.
|
|
//
|
|
ASSERT(iFile == 0xFFFFFFFF || lpszFile);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return DragQueryFileW(hDrop, iFile, lpszFile, cch);
|
|
}
|
|
|
|
//
|
|
// If iFile is 0xFFFFFFFF, then lpszFile and cch are ignored.
|
|
//
|
|
if (iFile == 0xFFFFFFFF)
|
|
{
|
|
return DragQueryFileA(hDrop, iFile, NULL, 0);
|
|
}
|
|
|
|
CStrOut str(lpszFile, cch);
|
|
|
|
DragQueryFileA(hDrop, iFile, str, str.BufSize());
|
|
return str.ConvertExcludingNul();
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_VERSION_WRAPPER
|
|
|
|
//
|
|
// the version APIs are not conducive to using
|
|
// wrap versions of the APIs, but we are going to
|
|
// do something reasonable....
|
|
//
|
|
#define VERSIONINFO_BUFF (MAX_PATH * SIZEOF(WCHAR))
|
|
|
|
STDAPI_(DWORD)
|
|
GetFileVersionInfoSizeWrapW(LPWSTR pwzFilename, LPDWORD lpdwHandle)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetFileVersionInfoSizeW(pwzFilename, lpdwHandle);
|
|
}
|
|
else
|
|
{
|
|
char szFilename[MAX_PATH];
|
|
DWORD dwRet;
|
|
|
|
ASSERT(pwzFilename);
|
|
SHUnicodeToAnsi(pwzFilename, szFilename, ARRAYSIZE(szFilename));
|
|
dwRet = GetFileVersionInfoSizeA(szFilename, lpdwHandle);
|
|
if (dwRet > 0)
|
|
{
|
|
// Add a scratch buffer to front for converting to UNICODE
|
|
dwRet += VERSIONINFO_BUFF;
|
|
}
|
|
return dwRet;
|
|
}
|
|
}
|
|
|
|
#endif // NEED_VERSION_WRAPPER
|
|
|
|
#ifdef NEED_VERSION_WRAPPER
|
|
|
|
STDAPI_(BOOL)
|
|
GetFileVersionInfoWrapW(LPWSTR pwzFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GetFileVersionInfoW(pwzFilename, dwHandle, dwLen, lpData);
|
|
}
|
|
else
|
|
{
|
|
char szFilename[MAX_PATH];
|
|
BYTE* pb;
|
|
|
|
if (dwLen <= VERSIONINFO_BUFF)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(pwzFilename);
|
|
SHUnicodeToAnsi(pwzFilename, szFilename, ARRAYSIZE(szFilename));
|
|
//Skip over our scratch buffer at the beginning
|
|
pb = (BYTE*)lpData + VERSIONINFO_BUFF;
|
|
|
|
return GetFileVersionInfoA(szFilename, dwHandle, dwLen - VERSIONINFO_BUFF, (void*)pb);
|
|
}
|
|
}
|
|
|
|
#endif // NEED_VERSION_WRAPPER
|
|
|
|
#ifdef NEED_VERSION_WRAPPER
|
|
|
|
STDAPI_(BOOL)
|
|
VerQueryValueWrapW(const LPVOID pBlock, LPWSTR pwzSubBlock, LPVOID *ppBuffer, PUINT puLen)
|
|
{
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return VerQueryValueW(pBlock, pwzSubBlock, ppBuffer, puLen);
|
|
}
|
|
else
|
|
{
|
|
const WCHAR pwzStringFileInfo[] = L"\\StringFileInfo";
|
|
|
|
//
|
|
// WARNING: This function wipes out any string previously returned
|
|
// for this pBlock because a common buffer at the beginning of the
|
|
// block is used for ansi/unicode translation!
|
|
//
|
|
char szSubBlock[MAX_PATH];
|
|
BOOL fRet;
|
|
BYTE* pb;
|
|
|
|
ASSERT(pwzSubBlock);
|
|
SHUnicodeToAnsi(pwzSubBlock, szSubBlock, ARRAYSIZE(szSubBlock));
|
|
|
|
// The first chunk is our scratch buffer for converting to UNICODE
|
|
pb = (BYTE*)pBlock + VERSIONINFO_BUFF;
|
|
fRet = VerQueryValueA((void*)pb, szSubBlock, ppBuffer, puLen);
|
|
|
|
// Convert to unicode if ansi string returned
|
|
if (fRet && StrCmpNIW(pwzSubBlock, pwzStringFileInfo, ARRAYSIZE(pwzStringFileInfo) - 1) == 0)
|
|
{
|
|
// Convert returned string to UNICODE. We use the scratch buffer
|
|
// at the beginning of pBlock
|
|
LPWSTR pwzBuff = (LPWSTR)pBlock;
|
|
if (*puLen == 0)
|
|
{
|
|
pwzBuff[0] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
SHAnsiToUnicode((LPCSTR)*ppBuffer, pwzBuff, VERSIONINFO_BUFF/sizeof(WCHAR));
|
|
}
|
|
*ppBuffer = pwzBuff;
|
|
}
|
|
return fRet;
|
|
}
|
|
}
|
|
|
|
#endif // NEED_VERSION_WRAPPER
|
|
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
HRESULT WINAPI SHDefExtractIconWrapW(LPCWSTR pszFile, int nIconIndex,
|
|
UINT uFlags, HICON *phiconLarge,
|
|
HICON *phiconSmall, UINT nIconSize)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
hr = SHDefExtractIconW(pszFile, nIconIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striFile(pszFile);
|
|
|
|
hr = SHDefExtractIconA(striFile, nIconIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
|
|
BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszpdlLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy, UINT uFlags)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (g_bRunningOnNT5OrHigher)
|
|
{
|
|
fRet = SHGetNewLinkInfoW(pszpdlLinkTo, pszDir, pszName, pfMustCopy, uFlags);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striDir(pszDir);
|
|
CStrOut stroName(pszName, MAX_PATH);
|
|
|
|
if (SHGNLI_PIDL & uFlags)
|
|
{
|
|
fRet = SHGetNewLinkInfoA((LPCSTR)pszpdlLinkTo, striDir, stroName, pfMustCopy, uFlags);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striLinkTo(pszpdlLinkTo);
|
|
|
|
fRet = SHGetNewLinkInfoA(striLinkTo, striDir, stroName, pfMustCopy, uFlags);
|
|
}
|
|
|
|
if (fRet)
|
|
{
|
|
stroName.ConvertIncludingNul();
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
#ifdef NEED_ADVAPI32_WRAPPER
|
|
|
|
LONG WINAPI RegEnumValueWrapW(HKEY hkey, DWORD dwIndex, LPWSTR lpValueName,
|
|
LPDWORD lpcbValueName, LPDWORD lpReserved,
|
|
LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
|
|
{
|
|
VALIDATE_PROTOTYPE(RegEnumValue);
|
|
|
|
LONG lRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
lRet = RegEnumValueW(hkey, dwIndex, lpValueName, lpcbValueName,
|
|
lpReserved, lpType, lpData, lpcbData);
|
|
}
|
|
else
|
|
{
|
|
CStrOut stroValueName(lpValueName, *lpcbValueName);
|
|
DWORD dwTypeTemp;
|
|
|
|
if (lpData)
|
|
{
|
|
ASSERT(lpcbData);
|
|
|
|
CStrOut stroData((LPWSTR)lpData, (*lpcbData) / sizeof(WCHAR));
|
|
|
|
lRet = RegEnumValueA(hkey, dwIndex, stroValueName, lpcbValueName,
|
|
lpReserved, &dwTypeTemp,
|
|
(LPBYTE)(LPSTR)stroData, lpcbData);
|
|
|
|
if (ERROR_SUCCESS == lRet && REG_SZ == dwTypeTemp)
|
|
{
|
|
*lpcbData = sizeof(WCHAR) * stroData.ConvertIncludingNul();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lRet = RegEnumValueA(hkey, dwIndex, stroValueName, lpcbValueName,
|
|
lpReserved, &dwTypeTemp, lpData, lpcbData);
|
|
}
|
|
|
|
if (ERROR_SUCCESS == lRet)
|
|
*lpcbValueName = stroValueName.ConvertExcludingNul();
|
|
|
|
if (lpType)
|
|
*lpType = dwTypeTemp;
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
#endif // NEED_ADVAPI32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI WritePrivateProfileStructWrapW(LPCWSTR lpszSection, LPCWSTR lpszKey,
|
|
LPVOID lpStruct, UINT uSizeStruct,
|
|
LPCWSTR szFile)
|
|
{
|
|
VALIDATE_PROTOTYPE(WritePrivateProfileStruct);
|
|
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = WritePrivateProfileStructW(lpszSection, lpszKey, lpStruct,
|
|
uSizeStruct, szFile);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striSection(lpszSection);
|
|
CStrIn striKey(lpszKey);
|
|
CPPFIn striFile(szFile); // PrivateProfile filename needs special class
|
|
|
|
fRet = WritePrivateProfileStructA(striSection, striKey, lpStruct,
|
|
uSizeStruct, striFile);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI GetPrivateProfileStructWrapW(LPCWSTR lpszSection, LPCWSTR lpszKey,
|
|
LPVOID lpStruct, UINT uSizeStruct,
|
|
LPCWSTR szFile)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetPrivateProfileStruct);
|
|
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = GetPrivateProfileStructW(lpszSection, lpszKey, lpStruct,
|
|
uSizeStruct, szFile);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striSection(lpszSection);
|
|
CStrIn striKey(lpszKey);
|
|
CPPFIn striFile(szFile); // PrivateProfile filename needs special class
|
|
|
|
fRet = GetPrivateProfileStructA(striSection, striKey, lpStruct,
|
|
uSizeStruct, striFile);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
BOOL WINAPI CreateProcessWrapW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
BOOL bInheritHandles,
|
|
DWORD dwCreationFlags,
|
|
LPVOID lpEnvironment,
|
|
LPCWSTR lpCurrentDirectory,
|
|
LPSTARTUPINFOW lpStartupInfo,
|
|
LPPROCESS_INFORMATION lpProcessInformation)
|
|
{
|
|
BOOL fRet;
|
|
VALIDATE_PROTOTYPE(CreateProcess);
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = CreateProcessW(lpApplicationName, lpCommandLine,
|
|
lpProcessAttributes, lpThreadAttributes,
|
|
bInheritHandles, dwCreationFlags, lpEnvironment,
|
|
lpCurrentDirectory, lpStartupInfo,
|
|
lpProcessInformation);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striApplicationName(lpApplicationName);
|
|
CStrIn striCommandLine(lpCommandLine);
|
|
CStrIn striCurrentDirectory(lpCurrentDirectory);
|
|
|
|
if (NULL == lpStartupInfo)
|
|
{
|
|
fRet = CreateProcessA(striApplicationName, striCommandLine,
|
|
lpProcessAttributes, lpThreadAttributes,
|
|
bInheritHandles, dwCreationFlags,
|
|
lpEnvironment, striCurrentDirectory,
|
|
NULL, lpProcessInformation);
|
|
}
|
|
else
|
|
{
|
|
STARTUPINFOA si = *(STARTUPINFOA*)lpStartupInfo;
|
|
|
|
CStrIn striReserved(lpStartupInfo->lpReserved);
|
|
CStrIn striDesktop(lpStartupInfo->lpDesktop);
|
|
CStrIn striTitle(lpStartupInfo->lpTitle);
|
|
|
|
si.lpReserved = striReserved;
|
|
si.lpDesktop = striDesktop;
|
|
si.lpTitle = striTitle;
|
|
|
|
fRet = CreateProcessA(striApplicationName, striCommandLine,
|
|
lpProcessAttributes, lpThreadAttributes,
|
|
bInheritHandles, dwCreationFlags,
|
|
lpEnvironment, striCurrentDirectory,
|
|
&si, lpProcessInformation);
|
|
}
|
|
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
HICON WINAPI ExtractIconWrapW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex)
|
|
{
|
|
HICON hicon;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
hicon = ExtractIconW(hInst, lpszExeFileName, nIconIndex);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striExeFileName(lpszExeFileName);
|
|
|
|
hicon = ExtractIconA(hInst, striExeFileName, nIconIndex);
|
|
}
|
|
|
|
return hicon;
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
UINT WINAPI DdeInitializeWrapW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
|
|
DWORD afCmd, DWORD ulRes)
|
|
{
|
|
UINT uRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
uRet = DdeInitializeW(pidInst, pfnCallback, afCmd, ulRes);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This assumes the callback function will used the wrapped dde
|
|
// string functions (DdeCreateStringHandle and DdeQueryString)
|
|
// to access strings.
|
|
//
|
|
|
|
uRet = DdeInitializeA(pidInst, pfnCallback, afCmd, ulRes);
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
HSZ WINAPI DdeCreateStringHandleWrapW(DWORD idInst, LPCWSTR psz, int iCodePage)
|
|
{
|
|
HSZ hszRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
hszRet = DdeCreateStringHandleW(idInst, psz, iCodePage);
|
|
}
|
|
else
|
|
{
|
|
CStrIn stripsz(psz);
|
|
|
|
hszRet = DdeCreateStringHandleA(idInst, stripsz, CP_WINANSI);
|
|
}
|
|
|
|
return hszRet;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_USER32_WRAPPER
|
|
|
|
DWORD WINAPI DdeQueryStringWrapW(DWORD idInst, HSZ hsz, LPWSTR psz,
|
|
DWORD cchMax, int iCodePage)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
dwRet = DdeQueryStringW(idInst, hsz, psz, cchMax, iCodePage);
|
|
}
|
|
else
|
|
{
|
|
CStrOut stropsz(psz, cchMax);
|
|
|
|
dwRet = DdeQueryStringA(idInst, hsz, stropsz, stropsz.BufSize(),
|
|
CP_WINANSI);
|
|
|
|
if (dwRet && psz)
|
|
dwRet = stropsz.ConvertExcludingNul();
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
#endif // NEED_USER32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
ATOM WINAPI
|
|
GlobalAddAtomWrapW(LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(GlobalAddAtom);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GlobalAddAtomW(lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return GlobalAddAtomA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_KERNEL32_WRAPPER
|
|
|
|
ATOM WINAPI
|
|
GlobalFindAtomWrapW(LPCWSTR lpString)
|
|
{
|
|
VALIDATE_PROTOTYPE(GlobalFindAtom);
|
|
|
|
if (g_bRunningOnNT)
|
|
{
|
|
return GlobalFindAtomW(lpString);
|
|
}
|
|
|
|
CStrIn str(lpString);
|
|
|
|
return GlobalFindAtomA(str);
|
|
}
|
|
|
|
#endif // NEED_KERNEL32_WRAPPER
|
|
|
|
#ifdef NEED_COMDLG32_WRAPPER
|
|
|
|
BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW lpofn)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = GetSaveFileNameW(lpofn);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(lpofn);
|
|
ASSERT(sizeof(OPENFILENAMEA) == sizeof(OPENFILENAMEW));
|
|
|
|
OPENFILENAMEA ofnA = *(LPOPENFILENAMEA)lpofn;
|
|
|
|
// In parameters
|
|
CStrInMulti strimFilter(lpofn->lpstrFilter);
|
|
CStrIn striInitialDir(lpofn->lpstrInitialDir);
|
|
CStrIn striTitle(lpofn->lpstrTitle);
|
|
CStrIn striDefExt(lpofn->lpstrDefExt);
|
|
CStrIn striTemplateName(lpofn->lpTemplateName);
|
|
|
|
ASSERT(NULL == lpofn->lpstrCustomFilter); // add support if you need it.
|
|
|
|
// Out parameters
|
|
CStrOut stroFile(lpofn->lpstrFile, lpofn->nMaxFile);
|
|
CStrOut stroFileTitle(lpofn->lpstrFileTitle, lpofn->nMaxFileTitle);
|
|
|
|
//In Out parameters
|
|
SHUnicodeToAnsi(lpofn->lpstrFile, stroFile, stroFile.BufSize());
|
|
|
|
// Set up the parameters
|
|
ofnA.lpstrFilter = strimFilter;
|
|
ofnA.lpstrInitialDir = striInitialDir;
|
|
ofnA.lpstrTitle = striTitle;
|
|
ofnA.lpstrDefExt = striDefExt;
|
|
ofnA.lpTemplateName = striTemplateName;
|
|
ofnA.lpstrFile = stroFile;
|
|
ofnA.lpstrFileTitle = stroFileTitle;
|
|
|
|
fRet = GetSaveFileNameA(&ofnA);
|
|
|
|
if (fRet)
|
|
{
|
|
// Copy the out parameters
|
|
lpofn->nFilterIndex = ofnA.nFilterIndex;
|
|
lpofn->Flags = ofnA.Flags;
|
|
|
|
// Get the offset to the filename
|
|
stroFile.ConvertIncludingNul();
|
|
LPWSTR psz = PathFindFileNameW(lpofn->lpstrFile);
|
|
|
|
if (psz)
|
|
{
|
|
lpofn->nFileOffset = (int) (psz-lpofn->lpstrFile);
|
|
|
|
// Get the offset of the extension
|
|
psz = PathFindExtensionW(psz);
|
|
|
|
lpofn->nFileExtension = psz ? (int)(psz-lpofn->lpstrFile) : 0;
|
|
}
|
|
else
|
|
{
|
|
lpofn->nFileOffset = 0;
|
|
lpofn->nFileExtension = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_COMDLG32_WRAPPER
|
|
|
|
#ifdef NEED_COMDLG32_WRAPPER
|
|
|
|
BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW lpofn)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = GetOpenFileNameW(lpofn);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(lpofn);
|
|
ASSERT(sizeof(OPENFILENAMEA) == sizeof(OPENFILENAMEW));
|
|
|
|
OPENFILENAMEA ofnA = *(LPOPENFILENAMEA)lpofn;
|
|
|
|
// In parameters
|
|
CStrInMulti strimFilter(lpofn->lpstrFilter);
|
|
CStrIn striInitialDir(lpofn->lpstrInitialDir);
|
|
CStrIn striTitle(lpofn->lpstrTitle);
|
|
CStrIn striDefExt(lpofn->lpstrDefExt);
|
|
CStrIn striTemplateName(lpofn->lpTemplateName);
|
|
|
|
ASSERT(NULL == lpofn->lpstrCustomFilter); // add support if you need it.
|
|
|
|
// Out parameters
|
|
CStrOut stroFile(lpofn->lpstrFile, lpofn->nMaxFile);
|
|
CStrOut stroFileTitle(lpofn->lpstrFileTitle, lpofn->nMaxFileTitle);
|
|
|
|
//In Out parameters
|
|
SHUnicodeToAnsi(lpofn->lpstrFile, stroFile, stroFile.BufSize());
|
|
|
|
// Set up the parameters
|
|
ofnA.lpstrFilter = strimFilter;
|
|
ofnA.lpstrInitialDir = striInitialDir;
|
|
ofnA.lpstrTitle = striTitle;
|
|
ofnA.lpstrDefExt = striDefExt;
|
|
ofnA.lpTemplateName = striTemplateName;
|
|
ofnA.lpstrFile = stroFile;
|
|
ofnA.lpstrFileTitle = stroFileTitle;
|
|
|
|
fRet = GetOpenFileNameA(&ofnA);
|
|
|
|
if (fRet)
|
|
{
|
|
// Copy the out parameters
|
|
lpofn->nFilterIndex = ofnA.nFilterIndex;
|
|
lpofn->Flags = ofnA.Flags;
|
|
|
|
// Get the offset to the filename
|
|
stroFile.ConvertIncludingNul();
|
|
LPWSTR psz = PathFindFileNameW(lpofn->lpstrFile);
|
|
|
|
if (psz)
|
|
{
|
|
lpofn->nFileOffset = (int) (psz-lpofn->lpstrFile);
|
|
|
|
// Get the offset of the extension
|
|
psz = PathFindExtensionW(psz);
|
|
|
|
lpofn->nFileExtension = psz ? (int)(psz-lpofn->lpstrFile) : 0;
|
|
}
|
|
else
|
|
{
|
|
lpofn->nFileOffset = 0;
|
|
lpofn->nFileExtension = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_COMDLG32_WRAPPER
|
|
|
|
#ifdef NEED_SHELL32_WRAPPER
|
|
|
|
#define SHCNF_HAS_WSTR_PARAMS(f) ((f & SHCNF_TYPE) == SHCNF_PATHW || \
|
|
(f & SHCNF_TYPE) == SHCNF_PRINTERW || \
|
|
(f & SHCNF_TYPE) == SHCNF_PRINTJOBW )
|
|
|
|
void SHChangeNotifyWrap(LONG wEventId, UINT uFlags, LPCVOID dwItem1,
|
|
LPCVOID dwItem2)
|
|
{
|
|
if (UseUnicodeShell32() || !SHCNF_HAS_WSTR_PARAMS(uFlags))
|
|
{
|
|
SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2);
|
|
}
|
|
else
|
|
{
|
|
CStrIn striItem1((LPWSTR)dwItem1);
|
|
CStrIn striItem2((LPWSTR)dwItem2);
|
|
|
|
if ((uFlags & SHCNF_TYPE) == SHCNF_PATHW)
|
|
{
|
|
uFlags = (uFlags & ~SHCNF_TYPE) | SHCNF_PATHA;
|
|
}
|
|
else if ((uFlags & SHCNF_TYPE) == SHCNF_PRINTERW)
|
|
{
|
|
uFlags = (uFlags & ~SHCNF_TYPE) | SHCNF_PRINTERA;
|
|
}
|
|
else
|
|
{
|
|
uFlags = (uFlags & ~SHCNF_TYPE) | SHCNF_PRINTJOBA;
|
|
}
|
|
|
|
SHChangeNotify(wEventId, uFlags, (void*)(LPSTR)striItem1, (void*)(LPSTR)striItem2);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
LWSTDAPI_(void) SHFlushSFCacheWrap(void)
|
|
{
|
|
// if shell32 is not in process, then there's nothing to flush
|
|
HMODULE hShell32 = GetModuleHandleWrap(TEXT("SHELL32"));
|
|
if (hShell32)
|
|
{
|
|
// NOTE: GetProcAddress always takes ANSI strings!
|
|
DLLGETVERSIONPROC pfnGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hShell32, "DllGetVersion");
|
|
|
|
if (pfnGetVersion)
|
|
{
|
|
DLLVERSIONINFO dllinfo;
|
|
|
|
dllinfo.cbSize = sizeof(DLLVERSIONINFO);
|
|
if (pfnGetVersion(&dllinfo) == NOERROR)
|
|
{
|
|
// first, we need a version of shell32 that supports the function
|
|
if (dllinfo.dwMajorVersion >= 4)
|
|
{
|
|
if (dllinfo.dwMajorVersion == 4)
|
|
{
|
|
// to work around the "missing critical section" bug in v4 shell32.dll,
|
|
// we simply bail the call.
|
|
return;
|
|
}
|
|
|
|
SHFlushSFCache();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // NEED_SHELL32_WRAPPER
|
|
|
|
#ifdef NEED_COMDLG32_WRAPPER
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// PrintDlgWrap, PageSetupDlgWrap - wrappers
|
|
// DevNamesAFromDevNamesW, DevNamesWFromDevNamesA - helper functions
|
|
//
|
|
// Copied from mshtml\src\core\wrappers\unicwrap.cpp with some
|
|
// cosmetic changes (peterlee)
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HGLOBAL
|
|
DevNamesAFromDevNamesW( HGLOBAL hdnw )
|
|
{
|
|
HGLOBAL hdna = NULL;
|
|
|
|
if (hdnw)
|
|
{
|
|
LPDEVNAMES lpdnw = (LPDEVNAMES) GlobalLock( hdnw );
|
|
if (lpdnw)
|
|
{
|
|
CStrIn strDriver( (LPCWSTR) lpdnw + lpdnw->wDriverOffset );
|
|
CStrIn strDevice( (LPCWSTR) lpdnw + lpdnw->wDeviceOffset );
|
|
CStrIn strOutput( (LPCWSTR) lpdnw + lpdnw->wOutputOffset );
|
|
int cchDriver = strDriver.strlen() + 1;
|
|
int cchDevice = strDevice.strlen() + 1;
|
|
int cchOutput = strOutput.strlen() + 1;
|
|
|
|
hdna = GlobalAlloc( GHND, sizeof(DEVNAMES) +
|
|
cchDriver + cchDevice + cchOutput );
|
|
if (hdna)
|
|
{
|
|
LPDEVNAMES lpdna = (LPDEVNAMES) GlobalLock( hdna );
|
|
if (!lpdna)
|
|
{
|
|
GlobalFree( hdna );
|
|
hdna = NULL;
|
|
}
|
|
else
|
|
{
|
|
lpdna->wDriverOffset = sizeof(DEVNAMES);
|
|
lpdna->wDeviceOffset = lpdna->wDriverOffset + cchDriver;
|
|
lpdna->wOutputOffset = lpdna->wDeviceOffset + cchDevice;
|
|
lpdna->wDefault = lpdnw->wDefault;
|
|
|
|
lstrcpyA( (LPSTR) lpdna + lpdna->wDriverOffset, strDriver );
|
|
lstrcpyA( (LPSTR) lpdna + lpdna->wDeviceOffset, strDevice );
|
|
lstrcpyA( (LPSTR) lpdna + lpdna->wOutputOffset, strOutput );
|
|
|
|
GlobalUnlock( hdna );
|
|
}
|
|
}
|
|
|
|
GlobalUnlock( hdnw );
|
|
GlobalFree( hdnw );
|
|
}
|
|
}
|
|
|
|
return hdna;
|
|
}
|
|
|
|
HGLOBAL
|
|
DevNamesWFromDevNamesA( HGLOBAL hdna )
|
|
{
|
|
HGLOBAL hdnw = NULL;
|
|
|
|
if (hdna)
|
|
{
|
|
LPDEVNAMES lpdna = (LPDEVNAMES) GlobalLock( hdna );
|
|
if (lpdna)
|
|
{
|
|
LPCSTR lpszDriver = (LPCSTR) lpdna + lpdna->wDriverOffset;
|
|
LPCSTR lpszDevice = (LPCSTR) lpdna + lpdna->wDeviceOffset;
|
|
LPCSTR lpszOutput = (LPCSTR) lpdna + lpdna->wOutputOffset;
|
|
int cchDriver = lstrlenA( lpszDriver ) + 1;
|
|
int cchDevice = lstrlenA( lpszDevice ) + 1;
|
|
int cchOutput = lstrlenA( lpszOutput ) + 1;
|
|
|
|
// assume the wide charcount won't exceed the multibyte charcount
|
|
|
|
hdnw = GlobalAlloc( GHND, sizeof(DEVNAMES) +
|
|
sizeof(WCHAR) * (cchDriver + cchDevice + cchOutput) );
|
|
if (hdnw)
|
|
{
|
|
LPDEVNAMES lpdnw = (LPDEVNAMES) GlobalLock( hdnw );
|
|
if (!lpdnw)
|
|
{
|
|
GlobalFree( hdnw );
|
|
hdnw = NULL;
|
|
}
|
|
else
|
|
{
|
|
lpdnw->wDriverOffset = sizeof(DEVNAMES) / sizeof(WCHAR);
|
|
lpdnw->wDeviceOffset = lpdnw->wDriverOffset + cchDriver;
|
|
lpdnw->wOutputOffset = lpdnw->wDeviceOffset + cchDevice;
|
|
lpdnw->wDefault = lpdna->wDefault;
|
|
|
|
SHAnsiToUnicode( (LPSTR) lpszDriver, (LPWSTR) lpdnw + lpdnw->wDriverOffset,
|
|
cchDriver );
|
|
SHAnsiToUnicode( lpszDevice, (LPWSTR) lpdnw + lpdnw->wDeviceOffset,
|
|
cchDevice);
|
|
SHAnsiToUnicode( lpszOutput, (LPWSTR) lpdnw + lpdnw->wOutputOffset,
|
|
cchOutput);
|
|
|
|
GlobalUnlock( hdnw );
|
|
}
|
|
}
|
|
|
|
GlobalUnlock( hdna );
|
|
GlobalFree( hdna );
|
|
}
|
|
}
|
|
|
|
return hdnw;
|
|
}
|
|
|
|
#ifdef UNIX
|
|
HGLOBAL
|
|
DevModeAFromDevModeW( HGLOBAL hdmw )
|
|
{
|
|
HGLOBAL hdma = NULL;
|
|
|
|
if (hdmw)
|
|
{
|
|
LPDEVMODEW lpdmw = (LPDEVMODEW)GlobalLock( hdmw );
|
|
if (lpdmw)
|
|
{
|
|
hdma = GlobalAlloc( GHND, sizeof(DEVMODEA) );
|
|
if (hdma)
|
|
{
|
|
LPDEVMODEA lpdma = (LPDEVMODEA) GlobalLock( hdma );
|
|
if (lpdma)
|
|
{
|
|
CStrIn strDeviceName( lpdmw->dmDeviceName );
|
|
CStrIn strFormName( lpdmw->dmFormName );
|
|
|
|
// assume memory layout is identical
|
|
|
|
memcpy( lpdma->dmDeviceName, strDeviceName, CCHDEVICENAME );
|
|
|
|
memcpy( &lpdma->dmSpecVersion,
|
|
&lpdmw->dmSpecVersion,
|
|
offsetof(DEVMODEW, dmFormName) -
|
|
offsetof(DEVMODEW, dmSpecVersion) );
|
|
|
|
memcpy( lpdma->dmFormName, strFormName, CCHFORMNAME );
|
|
|
|
memcpy( &lpdma->dmLogPixels,
|
|
&lpdmw->dmLogPixels,
|
|
sizeof(DEVMODEW) -
|
|
offsetof(DEVMODEW, dmLogPixels) );
|
|
|
|
GlobalUnlock( hdma );
|
|
}
|
|
else
|
|
{
|
|
GlobalFree( hdma );
|
|
hdma = NULL;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock( hdmw );
|
|
GlobalFree( hdmw );
|
|
}
|
|
}
|
|
|
|
return hdma;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// DEVMODEW from DEVMODEA
|
|
//--------------------------------------------------------------
|
|
HGLOBAL
|
|
DevModeWFromDevModeA( HGLOBAL hdma )
|
|
{
|
|
HGLOBAL hdmw = NULL;
|
|
|
|
if (hdma)
|
|
{
|
|
LPDEVMODEA lpdma = (LPDEVMODEA)GlobalLock( hdma );
|
|
if (lpdma)
|
|
{
|
|
hdmw = GlobalAlloc( GHND, sizeof(DEVMODEW) );
|
|
if (hdmw)
|
|
{
|
|
LPDEVMODEW lpdmw = (LPDEVMODEW) GlobalLock( hdmw );
|
|
if (lpdmw)
|
|
{
|
|
CStrOut strDeviceName( lpdmw->dmDeviceName, CCHDEVICENAME );
|
|
CStrOut strFormName( lpdmw->dmFormName, CCHFORMNAME );
|
|
|
|
// assume memory layout is identical
|
|
|
|
lstrcpyA( strDeviceName, (LPCSTR)lpdma->dmDeviceName );
|
|
strDeviceName.ConvertIncludingNul();
|
|
|
|
memcpy( &lpdmw->dmSpecVersion,
|
|
&lpdma->dmSpecVersion,
|
|
offsetof(DEVMODEA, dmFormName) -
|
|
offsetof(DEVMODEA, dmSpecVersion) );
|
|
|
|
lstrcpyA( strFormName, (LPCSTR)lpdmw->dmFormName );
|
|
strFormName.ConvertIncludingNul();
|
|
|
|
memcpy( &lpdmw->dmLogPixels,
|
|
&lpdma->dmLogPixels,
|
|
sizeof(DEVMODEA) -
|
|
offsetof(DEVMODEA, dmLogPixels) );
|
|
|
|
GlobalUnlock( hdmw );
|
|
}
|
|
else
|
|
{
|
|
GlobalFree( hdmw );
|
|
hdmw = NULL;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock( hdma );
|
|
GlobalFree( hdma );
|
|
}
|
|
}
|
|
|
|
return hdmw;
|
|
}
|
|
#endif //UNIX
|
|
#endif // NEED_COMDLG32_WRAPPER
|
|
|
|
#ifdef NEED_COMDLG32_WRAPPER
|
|
|
|
//--------------------------------------------------------------
|
|
// PrintDlgW wrapper
|
|
//--------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
PrintDlgWrapW(LPPRINTDLGW lppd)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = PrintDlgW(lppd);
|
|
}
|
|
else
|
|
{
|
|
PRINTDLGA pda;
|
|
LPCWSTR lpPrintTemplateName = lppd->lpPrintTemplateName;
|
|
LPCWSTR lpSetupTemplateName = lppd->lpSetupTemplateName;
|
|
CStrIn strPrintTemplateName( lpPrintTemplateName );
|
|
CStrIn strSetupTemplateName( lpSetupTemplateName );
|
|
|
|
ASSERT( sizeof(pda) == sizeof( *lppd ));
|
|
|
|
memcpy( &pda, lppd, sizeof(pda) );
|
|
|
|
// IMPORTANT: We are not converting the DEVMODE structure back and forth
|
|
// from ASCII to Unicode on Win95 anymore because we are not touching the
|
|
// two strings or any other member. Converting the DEVMODE structure can
|
|
// be tricky because of potential and common discrepancies between the
|
|
// value of the dmSize member and sizeof(DEVMODE). (25155)
|
|
|
|
// So instead of: pda.hDevMode = DevModeAFromDevModeW( lppd->hDevMode );
|
|
// we just forward the DEVMODE handle:
|
|
pda.hDevMode = lppd->hDevMode;
|
|
pda.hDevNames = DevNamesAFromDevNamesW( lppd->hDevNames );
|
|
pda.lpPrintTemplateName = strPrintTemplateName;
|
|
pda.lpSetupTemplateName = strSetupTemplateName;
|
|
|
|
fRet = PrintDlgA( &pda );
|
|
|
|
// copy back wholesale, then restore strings.
|
|
|
|
memcpy( lppd, &pda, sizeof(pda) );
|
|
|
|
lppd->lpSetupTemplateName = lpSetupTemplateName;
|
|
lppd->lpPrintTemplateName = lpPrintTemplateName;
|
|
lppd->hDevNames = DevNamesWFromDevNamesA( pda.hDevNames );
|
|
|
|
// And instead of: lppd->hDevMode = DevModeWFromDevModeA( pda.hDevMode );
|
|
// we just forward the DEVMODE handle:
|
|
lppd->hDevMode = pda.hDevMode;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_COMDLG32_WRAPPER
|
|
|
|
#ifdef NEED_COMDLG32_WRAPPER
|
|
|
|
//--------------------------------------------------------------
|
|
// PageSetupDlgW wrapper
|
|
//--------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
PageSetupDlgWrapW(LPPAGESETUPDLGW lppsd)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (UseUnicodeShell32())
|
|
{
|
|
fRet = PageSetupDlgW(lppsd);
|
|
}
|
|
else
|
|
{
|
|
PAGESETUPDLGA psda;
|
|
LPCWSTR lpPageSetupTemplateName = lppsd->lpPageSetupTemplateName;
|
|
CStrIn strPageSetupTemplateName( lpPageSetupTemplateName );
|
|
|
|
ASSERT( sizeof(psda) == sizeof( *lppsd ) );
|
|
|
|
memcpy( &psda, lppsd, sizeof(psda));
|
|
|
|
// IMPORTANT: We are not converting the DEVMODE structure back and forth
|
|
// from ASCII to Unicode on Win95 anymore because we are not touching the
|
|
// two strings or any other member. Converting the DEVMODE structure can
|
|
// be tricky because of potential and common discrepancies between the
|
|
// value of the dmSize member and sizeof(DEVMODE). (25155)
|
|
|
|
// So instead of: psda.hDevMode = DevModeAFromDevModeW( lppsd->hDevMode );
|
|
// we just forward the DEVMODE handle:
|
|
psda.hDevMode = lppsd->hDevMode;
|
|
psda.hDevNames = DevNamesAFromDevNamesW( lppsd->hDevNames );
|
|
psda.lpPageSetupTemplateName = strPageSetupTemplateName;
|
|
|
|
fRet = PageSetupDlgA((LPPAGESETUPDLGA)&psda);
|
|
|
|
// copy back wholesale, then restore string.
|
|
|
|
memcpy( lppsd, &psda, sizeof(psda) );
|
|
|
|
lppsd->lpPageSetupTemplateName = lpPageSetupTemplateName;
|
|
lppsd->hDevNames = DevNamesWFromDevNamesA( psda.hDevNames );
|
|
|
|
// And instead of: lppsd->hDevMode = DevModeWFromDevModeA( psda.hDevMode );
|
|
// we just forward the DEVMODE handle:
|
|
lppsd->hDevMode = psda.hDevMode;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // NEED_COMDLG32_WRAPPER
|
|
|
|
#ifdef NEED_OLE32_WRAPPER
|
|
|
|
// CLSIDFromXXX puke when input is >= 248
|
|
#define SAFE_OLE_BUF_LEN 247
|
|
|
|
HRESULT WINAPI CLSIDFromStringWrap(LPOLESTR lpsz, LPCLSID pclsid)
|
|
{
|
|
return GUIDFromStringW(lpsz, pclsid) ? S_OK : E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT WINAPI CLSIDFromProgIDWrap(LPCOLESTR lpszProgID, LPCLSID lpclsid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (lstrlenW(lpszProgID) < SAFE_OLE_BUF_LEN)
|
|
{
|
|
hr = CLSIDFromProgID(lpszProgID, lpclsid);
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#endif // NEED_OLE32_WRAPPER
|
|
|
|
//************************************************************************
|
|
// function GETLONGPATHNAME :
|
|
//
|
|
// These wrappers are needed on all platforms (x86 and Alpha) because they
|
|
// implement the functionality for the Kernel32 function GetLongPathName that
|
|
// exists only on Win2K (Unicode/Ansi) and Win98 (Ansi only). Hence these
|
|
// wrappers provide this functionality for lower level platforms (NT4 & Win95)
|
|
//
|
|
|
|
#define achGETLONGPATHNAMEA "GetLongPathNameA"
|
|
typedef DWORD (*PROC_GETLONGPATHNAMEA) (LPCSTR, LPSTR, DWORD);
|
|
|
|
LWSTDAPI_(DWORD)
|
|
GetLongPathNameWrapA(
|
|
LPCSTR lpszShortPath,
|
|
LPSTR lpszLongPath,
|
|
DWORD cchBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetLongPathName);
|
|
|
|
// If NT5 or Win98, use the system API for ANSI
|
|
if (g_bRunningOnNT5OrHigher || g_bRunningOnMemphis)
|
|
{
|
|
static PROC_GETLONGPATHNAMEA s_fpGLPNA = NULL;
|
|
|
|
if (!s_fpGLPNA)
|
|
{
|
|
// This codepath is used for Memphis also, hence need to use the
|
|
// wrapper for GetModuleHandle.
|
|
s_fpGLPNA = (PROC_GETLONGPATHNAMEA)GetProcAddress(GetModuleHandleWrap(L"kernel32"),achGETLONGPATHNAMEA);
|
|
}
|
|
|
|
ASSERT(s_fpGLPNA);
|
|
|
|
if (s_fpGLPNA)
|
|
{
|
|
return s_fpGLPNA(lpszShortPath, lpszLongPath, cchBuffer);
|
|
}
|
|
}
|
|
|
|
// Otherwise use our own logic to do the conversion....
|
|
BOOL bCountMode = FALSE;
|
|
CHAR cTmp;
|
|
HANDLE hFind;
|
|
LPSTR pTmp = NULL;
|
|
DWORD dwReturnLen = 0;
|
|
WIN32_FIND_DATAA Find_Data;
|
|
UINT PrevErrorMode;
|
|
|
|
// Since we are going to be touchin the media, turn off file error
|
|
// pop-ups. Remember the current mode and set it back in the end.
|
|
PrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
|
|
if (lpszLongPath == NULL)
|
|
{ // No OUT buffer provided ==> counting mode.
|
|
bCountMode = TRUE;
|
|
}
|
|
else
|
|
{ // Initialize OUT buffer.
|
|
*lpszLongPath = '\0';
|
|
}
|
|
|
|
// Validate the input parameters...
|
|
if ((lpszShortPath == NULL)
|
|
|| (0xFFFFFFFF == GetFileAttributesA(lpszShortPath)) )
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
dwReturnLen = 0;
|
|
goto Done;
|
|
}
|
|
|
|
if (PathIsUNCA(lpszShortPath))
|
|
{
|
|
// This is a UNC Path, don't know how to handle
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
dwReturnLen = 0;
|
|
goto Done;
|
|
}
|
|
|
|
// Input must be a full path.
|
|
// Since Drive letter cannot be multi-byte, just check 2nd and 3rd chars.
|
|
if ( lpszShortPath[1] != ':' ||
|
|
lpszShortPath[2] != '\\')
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
dwReturnLen = 0;
|
|
goto Done;
|
|
}
|
|
|
|
// Create the drive root for the LFN.
|
|
if ( !bCountMode && cchBuffer >= 3)
|
|
{ // Copy the drive letter.
|
|
StrCpyNA(lpszLongPath, lpszShortPath, 3);
|
|
}
|
|
else
|
|
{ // Supplied buffer is so small, can't even copy the drive letter!!
|
|
bCountMode = TRUE;
|
|
}
|
|
dwReturnLen += 2;
|
|
|
|
|
|
// Create a local copy of the input Short name to party on.
|
|
// Also, as per the documentation, OUT buffer can be the same as the IN.
|
|
// Hence need to save the IN buffer before we start filling the OUT.
|
|
CHAR lpLocalCopy[MAX_PATH];
|
|
StrCpyNA(lpLocalCopy, lpszShortPath, MAX_PATH);
|
|
|
|
// Now starts the main processing....
|
|
// Skip past the root backslash in lpszShortPath.
|
|
pTmp = lpLocalCopy+3;
|
|
|
|
while (*pTmp)
|
|
{
|
|
// Get the next Backslash
|
|
pTmp = StrChrA(pTmp, L'\\');
|
|
if ( pTmp == NULL)
|
|
{
|
|
// Fell off the end of the str. So point pTmp to the terminating \0
|
|
pTmp = lpLocalCopy + lstrlenA(lpLocalCopy);
|
|
}
|
|
|
|
cTmp = *pTmp;
|
|
*pTmp = '\0';
|
|
|
|
hFind = FindFirstFileA(lpLocalCopy, &Find_Data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(hFind);
|
|
|
|
dwReturnLen += lstrlenA(Find_Data.cFileName);
|
|
dwReturnLen += 1; // Plus for the '\' introduced by PathCombine.
|
|
if (!bCountMode && dwReturnLen < cchBuffer)
|
|
{ // Add the LFN to the path
|
|
PathCombineA(lpszLongPath, lpszLongPath, Find_Data.cFileName);
|
|
}
|
|
else
|
|
{ // We are out of buffer space. Continue loop to find space reqd.
|
|
bCountMode = TRUE;
|
|
*lpszLongPath = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Error: Input path does not exist. The earlier check should catch
|
|
//this
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
if (!bCountMode)
|
|
*lpszLongPath = '\0';
|
|
*pTmp = cTmp;
|
|
dwReturnLen = 0;
|
|
goto Done;
|
|
}
|
|
|
|
*pTmp = cTmp;
|
|
|
|
if (*pTmp)
|
|
pTmp = CharNextA(pTmp);
|
|
}
|
|
|
|
Done:
|
|
// restore error mode.
|
|
SetErrorMode(PrevErrorMode);
|
|
|
|
if ( dwReturnLen && bCountMode)
|
|
{ // If everything OK (dwReturnLen!=0) and Counting Mode, add one.
|
|
return (dwReturnLen+1);
|
|
}
|
|
else
|
|
{ // Return error (dwReturnLen==0) Or
|
|
// No. of chars (dwReturnLen != 0 && bCountMode == FALSE)
|
|
return (dwReturnLen);
|
|
}
|
|
}
|
|
|
|
#define achGETLONGPATHNAMEW "GetLongPathNameW"
|
|
typedef DWORD (*PROC_GETLONGPATHNAMEW) (LPCWSTR, LPWSTR, DWORD);
|
|
|
|
LWSTDAPI_(DWORD)
|
|
GetLongPathNameWrapW(
|
|
LPCWSTR lpszShortPath,
|
|
LPWSTR lpszLongPath,
|
|
DWORD cchBuffer)
|
|
{
|
|
VALIDATE_PROTOTYPE(GetLongPathName);
|
|
|
|
// If we are running on NT5, use the system API for Unicode
|
|
if (g_bRunningOnNT5OrHigher)
|
|
{
|
|
static PROC_GETLONGPATHNAMEW s_fpGLPNW = NULL;
|
|
|
|
if (!s_fpGLPNW)
|
|
{
|
|
s_fpGLPNW = (PROC_GETLONGPATHNAMEW)GetProcAddress(GetModuleHandle(TEXT("kernel32")),achGETLONGPATHNAMEW);
|
|
}
|
|
|
|
ASSERT(s_fpGLPNW);
|
|
|
|
if (s_fpGLPNW)
|
|
{
|
|
return s_fpGLPNW(lpszShortPath, lpszLongPath, cchBuffer);
|
|
}
|
|
}
|
|
|
|
// All other platforms, convert UNICODE inputs to ANSI and use the
|
|
// ANSI wrapper.
|
|
CStrIn strShortPath(lpszShortPath);
|
|
CStrOut strLongPath(lpszLongPath, cchBuffer);
|
|
|
|
// DWORD dwRet = GetLongPathNameWrapA(strShortPath, strLongPath, strLongPath.BufSize());
|
|
DWORD dwRet = GetLongPathNameWrapA(strShortPath, strLongPath, cchBuffer);
|
|
if (dwRet != 0)
|
|
{ // If the call succeeded, thunk back the size.
|
|
if (dwRet < (DWORD)cchBuffer)
|
|
{ // Succeeded in getting LFN value in the OUT buffer. Thunk it back
|
|
// to Unicode.
|
|
dwRet = strLongPath.ConvertIncludingNul() - 1;
|
|
}
|
|
// else ==> buffer small, need dwRet character space.
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
// End of GETLONGPATHNAME wrapper implementation.
|
|
// NOTE: This wrapper is to be built on all platforms.
|
|
//************************************************************************
|