/* * Microsoft Confidential * Copyright (C) Microsoft Corporation 1991 * All Rights Reserved. * * * PIFSUB.C * Misc. subroutines for PIFMGR.DLL * * History: * Created 31-Jul-1992 3:30pm by Jeff Parsons */ #include "shellprv.h" #pragma hdrstop // shell priv can alter the definition of IsDBCSLeadByte! #if defined(FE_SB) #ifdef IsDBCSLeadByte #undef IsDBCSLeadByte #define IsDBCSLeadByte(x) IsDBCSLeadByteEx(CP_ACP,x) #endif #endif /* * Most of the routines in this file will need to stay ANSI. If a UNICODE * version is needed, it is supplied. * * This is because for the most part, the information in the PIF files * is ANSI and needs to stay that way. * * (RickTu) * */ /** lstrcpytrimA - copy fixed-length string, trimming trailing blanks * * INPUT * lpszDst -> destination string * lpszSrc -> fixed-length source string * cchMax = size (in characters) of fixed-length source string * * OUTPUT * Nothing */ void lstrcpytrimA(LPSTR lpszDst, LPCSTR lpszSrc, int cchMax) { CHAR ch; int cchSave = 0; LPSTR lpszSave = lpszDst; FunctionName(lstrcpytrim); while (cchMax && *lpszSrc) { ch = *lpszSrc++; if (ch == ' ') { if (!cchSave) { cchSave = cchMax; lpszSave = lpszDst; } } else cchSave = 0; *lpszDst = ch; if (--cchMax) { lpszDst++; #if (defined(DBCS) || defined(FE_SB)) if (IsDBCSLeadByte(ch) && --cchMax) { *lpszDst++ = *lpszSrc++; } #endif } } while (cchSave--) *lpszSave++ = '\0'; *lpszDst = '\0'; } /** lstrcpypadA - copy to fixed-length string, appending trailing blanks * * INPUT * lpszDst -> fixed-length destination string * lpszSrc -> source string * cchMax = size of fixed-length destination string (count of characters) * * OUTPUT * Nothing */ void lstrcpypadA(LPSTR lpszDst, LPCSTR lpszSrc, int cchMax) { FunctionName(lstrcpypadA); while (cchMax && *lpszSrc) { cchMax--; *lpszDst++ = *lpszSrc++; } while (cchMax--) { *lpszDst++ = ' '; } } /** lstrcpyncharA - copy variable-length string, until char * * INPUT * lpszDst -> fixed-length destination string * lpszSrc -> source string * cchMax = size of fixed-length destination string (count of characters) * ch = character to stop copying at * * OUTPUT * # of characters copied, excluding terminating NULL */ int lstrcpyncharA(LPSTR lpszDst, LPCSTR lpszSrc, int cchMax, CHAR ch) { int cch = 0; FunctionName(lstrcpyncharA); while (--cchMax && *lpszSrc && *lpszSrc != ch) { #if (defined(DBCS) || defined(FE_SB)) if (IsDBCSLeadByte(*lpszSrc)) { cch++; *lpszDst++ = *lpszSrc++; if (!*lpszSrc) break; /* Eek! String ends in DBCS lead byte! */ } #endif cch++; *lpszDst++ = *lpszSrc++; } *lpszDst = '\0'; return cch; } /** lstrskipcharA - skip char in variable-length string * * INPUT * lpszSrc -> source string * ch = character to skip * * OUTPUT * # of characters skipped, 0 if none */ int lstrskipcharA(LPCSTR lpszSrc, CHAR ch) { int cch = 0; FunctionName(lstrskipcharA); while (*lpszSrc && *lpszSrc == ch) { cch++; lpszSrc++; } return cch; } /** lstrskiptocharA - skip *to* char in variable-length string * * INPUT * lpszSrc -> source string * ch = character to skip *to* * * OUTPUT * # of characters skipped, 0 if none; if char didn't exist, then all * characters are skipped. */ int lstrskiptocharA(LPCSTR lpszSrc, CHAR ch) { int cch = 0; FunctionName(lstrskiptocharA); while (*lpszSrc && *lpszSrc != ch) { cch++; lpszSrc++; } return cch; } /** lstrcpyfnameA - copy filename appropriately * * INPUT * lpszDst -> output buffer * lpszSrc -> source filename * cbMax = size of output buffer * * OUTPUT * # of characters copied, including quotes if any, excluding terminating NULL */ int lstrcpyfnameA(LPSTR lpszDst, LPCSTR lpszSrc, int cchMax) { int cch; CHAR ch; FunctionName(lstrcpyfnameA); if (TEXT('\0') != (ch = lpszSrc[lstrskiptocharA(lpszSrc, ' ')])) { cchMax -= 2; *lpszDst++ = '\"'; } lstrcpynA(lpszDst, lpszSrc, cchMax); cch = lstrlenA(lpszDst); if (ch) { lpszDst[cch++] = '\"'; lpszDst[cch] = 0; } return cch; } /** lstrunquotefnameA - unquote filename if it contains quotes * * INPUT * lpszDst -> output buffer * lpszSrc -> source filename (quoted or unquoted) * cchMax = size of output buffer (count of characters) * fShort = TRUE if filename should be converted to 8.3 (eg, for real-mode); * -1 if the filename is known to not be quoted and should just be converted * OUTPUT * # of characters copied, excluding terminating NULL */ int lstrunquotefnameA(LPSTR lpszDst, LPCSTR lpszSrc, int cchMax, BOOL fShort) { int cch; FunctionName(lstrunquotefnameA); if (fShort != -1) { if (lpszSrc[0] == '\"') { cch = lstrcpyncharA(lpszDst, lpszSrc+1, cchMax, '\"'); } else { cch = lstrcpyncharA(lpszDst, lpszSrc, cchMax, ' '); } lpszSrc = lpszDst; } if (fShort) { cch = 1; CharToOemA(lpszSrc, lpszDst); cch = GetShortPathNameA( lpszSrc, lpszDst, cchMax ); if (cch) { // if no error... if (fShort == TRUE) { // if conversion for real-mode... if ((int)GetFileAttributesA(lpszDst) == -1) { // if filename doesn't exist, // then just copy the 8.3 portion // and hope the user's real-mode PATH // ultimately finds it! if (NULL != (lpszSrc = StrRChrA(lpszDst, NULL, '\\'))) { lstrcpyA(lpszDst, lpszSrc+1); } } } cch = lstrlenA(lpszDst); // recompute the length of the string } } return cch; } /** lstrskipfnameA - skip filename in string * * INPUT * lpszSrc -> string beginning with filename (quoted or unquoted) * * OUTPUT * # of characters skipped, 0 if none */ int lstrskipfnameA(LPCSTR lpszSrc) { int cch = 0; FunctionName(lstrskipfname); if (lpszSrc[0] == '\"') { cch = lstrskiptocharA(lpszSrc+1, '\"') + 1; if (lpszSrc[cch] == '\"') cch++; } else cch = lstrskiptocharA(lpszSrc, ' '); return cch; } /* * NOTE! The careful definitions of achBuf and achFmt, so that * we can support total output of 2 * MAX_STRING_SIZE bytes. */ int cdecl Warning(HWND hwnd, WORD id, WORD type, ...) { LPCTSTR lpchFmt; PPROPLINK ppl = NULL; TCHAR achBuf[2*MAX_STRING_SIZE]; #define achFmt (&achBuf[MAX_STRING_SIZE]) va_list ArgList; FunctionName(Warning); lpchFmt = achFmt; // We never use MB_FOCUS to mean whatever it's really supposed // to mean; we just use it as a kludge to support warning dialogs // when all we have is a ppl, not an hwnd. if (type & MB_NOFOCUS) { ppl = (PPROPLINK)hwnd; hwnd = NULL; type &= ~MB_NOFOCUS; } else if (hwnd) ppl = ((PPROPLINK)GetWindowLongPtr(hwnd, DWLP_USER))->ppl; if (id == IDS_ERROR + ERROR_NOT_ENOUGH_MEMORY) lpchFmt = TEXT(""); else { if (!LoadString(g_hinst, id, achFmt, MAX_STRING_SIZE)) { ASSERTFAIL(); lpchFmt = TEXT(""); } } va_start(ArgList,type); wvnsprintf(achBuf, MAX_STRING_SIZE, lpchFmt, ArgList); va_end(ArgList); lpchFmt = NULL; if (ppl) { ASSERTTRUE(ppl->iSig == PROP_SIG); if (!(lpchFmt = ppl->lpszTitle)) lpchFmt = ppl->szPathName+ppl->iFileName; } return MessageBox(hwnd, achBuf, lpchFmt, type); } #undef achFmt int MemoryWarning(HWND hwnd) { FunctionName(MemoryWarning); return Warning(hwnd, IDS_ERROR + ERROR_NOT_ENOUGH_MEMORY, MB_ICONEXCLAMATION | MB_OK); } LPTSTR LoadStringSafe(HWND hwnd, UINT id, LPTSTR lpsz, int cchsz) { FunctionName(LoadStringSafe); if (!LoadString(g_hinst, id, lpsz, cchsz)) { ASSERTFAIL(); if (hwnd) { MemoryWarning(hwnd); return NULL; } lpsz = TEXT(""); } return lpsz; } /** SetDlgBits - Check various dialog checkboxes according to given flags * * INPUT * hDlg = HWND of dialog box * pbinf -> array of bitinfo descriptors * cbinf = size of array * wFlags = flags * * OUTPUT * Returns NOTHING */ void SetDlgBits(HWND hDlg, PBINF pbinf, UINT cbinf, WORD wFlags) { FunctionName(SetDlgBits); ASSERTTRUE(cbinf > 0); do { ASSERTTRUE((pbinf->bBit & 0x3F) < 16); CheckDlgButton(hDlg, pbinf->id, !!(wFlags & (1 << (pbinf->bBit & 0x3F))) == !(pbinf->bBit & 0x80)); } while (++pbinf, --cbinf); } /** GetDlgBits - Set various flags according to dialog checkboxes * * INPUT * hDlg = HWND of dialog box * pbinf -> array of bitinfo descriptors * cbinf = size of array * lpwFlags -> flags word * * OUTPUT * Returns NOTHING */ void GetDlgBits(HWND hDlg, PBINF pbinf, UINT cbinf, LPWORD lpwFlags) { WORD wFlags; FunctionName(GetDlgBits); ASSERTTRUE(cbinf > 0); wFlags = *lpwFlags; do { ASSERTTRUE((pbinf->bBit & 0x3F) < 16); if (pbinf->bBit & 0x40) // 0x40 is a special bit mask continue; // that means "set but don't get // this control's value" wFlags &= ~(1 << (pbinf->bBit & 0x3F)); if (!!IsDlgButtonChecked(hDlg, pbinf->id) == !(pbinf->bBit & 0x80)) wFlags |= (1 << (pbinf->bBit & 0x3F)); } while (++pbinf, --cbinf); *lpwFlags = wFlags; } /** SetDlgInts - Set various edit controls according to integer fields * * INPUT * hDlg = HWND of dialog box * pvinf -> array of validation info descriptors * cvinf = size of array * lp -> structure of integers * * OUTPUT * Returns NOTHING */ void SetDlgInts(HWND hDlg, PVINF pvinf, UINT cvinf, LPVOID lp) { WORD wMin, wMax; FunctionName(SetDlgInts); ASSERTTRUE(cvinf > 0); do { wMin = wMax = *(WORD UNALIGNED *)((LPBYTE)lp + pvinf->off); if (pvinf->fbOpt & VINF_AUTO) { SendDlgItemMessage(hDlg, pvinf->id, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)g_szAuto); AddDlgIntValues(hDlg, pvinf->id, pvinf->iMax); if (wMin == 0) { SetDlgItemText(hDlg, pvinf->id, g_szAuto); continue; } } if (pvinf->fbOpt & VINF_AUTOMINMAX) { SendDlgItemMessage(hDlg, pvinf->id, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)g_szAuto); SendDlgItemMessage(hDlg, pvinf->id, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)g_szNone); AddDlgIntValues(hDlg, pvinf->id, pvinf->iMax); // When AUTOMINMAX is set, we assume that the field // we're validating is followed in its structure by a // corresponding max WORD. wMax = *(WORD UNALIGNED *)((LPBYTE)lp + pvinf->off + sizeof(WORD)); if (wMin == 0 && wMax == 0) { SetDlgItemText(hDlg, pvinf->id, g_szNone); continue; } // Let's try to simplify things by mapping 0xFFFF (aka -1) // to settings that mean "Auto" if (wMin == 0xFFFF || wMax == 0xFFFF) { wMin = 0; wMax = (WORD)pvinf->iMax; } if (wMax == (WORD)pvinf->iMax) { SetDlgItemText(hDlg, pvinf->id, g_szAuto); continue; } if (wMin != wMax) { // // We're in a bit of a quandary here. The settings show // explicit min and max values which are not equal, probably // due to settings inherited from a 3.1 PIF file. We'll // just go with the wMax value. Fortunately for us, we // don't actually have to *do* anything to make this happen. // } } SetDlgItemInt(hDlg, pvinf->id, wMin, pvinf->iMin < 0); } while (++pvinf, --cvinf); } /** AddDlgIntValues - Fill integer combo-box with appropriate values * * INPUT * hDlg = HWND of dialog box * id = dialog control ID * iMax = maximum value * * OUTPUT * Returns NOTHING */ void AddDlgIntValues(HWND hDlg, int id, int iMax) { int iStart, iInc; TCHAR achValue[16]; // HACK to make this do something sensible with the environment max; // they can still enter larger values (up to ENVSIZE_MAX) but I don't // see any sense in encouraging it. -JTP if ((WORD)iMax == ENVSIZE_MAX) iMax = 4096; if ((iMax < 0) || (iMax == 0xFFFF)) // HACK to make this do something sensible iMax = 16384; // with fields that allow huge maximums -JTP iStart = iInc = iMax/16; // arbitrarily chop the range up 16 times while (iStart <= iMax) { wsprintf(achValue, TEXT("%d"), iStart); SendDlgItemMessage(hDlg, id, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)achValue); iStart += iInc; } } /** GetDlgInts - Set various integer fields according to dialog edit controls * * INPUT * hDlg = HWND of dialog box * pvinf -> array of validation info descriptors * cvinf = size of array * lp -> structure of integers * * OUTPUT * Returns NOTHING */ void GetDlgInts(HWND hDlg, PVINF pvinf, int cvinf, LPVOID lp) { WORD wMin, wMax; UINT uTemp; BOOL fSuccess; TCHAR achText[32]; FunctionName(GetDlgInts); ASSERTTRUE(cvinf > 0); do { uTemp = GetDlgItemInt(hDlg, pvinf->id, &fSuccess, pvinf->iMin < 0); ASSERT(HIWORD(uTemp)==0); wMin = LOWORD(uTemp); // In case of error, make sure wMin doesn't actually change if (!fSuccess) wMin = *(WORD UNALIGNED *)((LPBYTE)lp + pvinf->off); if (pvinf->fbOpt & VINF_AUTO) { GetDlgItemText(hDlg, pvinf->id, achText, ARRAYSIZE(achText)); if (lstrcmpi(achText, g_szAuto) == 0) { wMin = 0; } } if (pvinf->fbOpt & VINF_AUTOMINMAX) { // When AUTOMINMAX is set, we assume that the field // we're validating is followed in its structure by a // corresponding max WORD, which we will ZERO if the // user selects NONE, or set to its MAXIMUM if the user // selects AUTO, or otherwise set to match the specified // MINIMUM. wMax = wMin; GetDlgItemText(hDlg, pvinf->id, achText, ARRAYSIZE(achText)); if (lstrcmpi(achText, g_szAuto) == 0) { wMin = 0; wMax = (WORD)pvinf->iMax; } else if (lstrcmpi(achText, g_szNone) == 0) { wMin = 0; wMax = 0; } *(WORD UNALIGNED *)((LPBYTE)lp + pvinf->off + sizeof(WORD)) = wMax; } *(WORD UNALIGNED *)((LPBYTE)lp + pvinf->off) = wMin; } while (++pvinf, --cvinf); } /** ValidateDlgInts - Validate that integer fields are value * * INPUT * hDlg = HWND of dialog box * pvinf -> array of validation descriptors * cvinf = size of array * * OUTPUT * Returns TRUE if something is wrong; FALSE if all is okay. */ BOOL ValidateDlgInts(HWND hDlg, PVINF pvinf, int cvinf) { DWORD dw; BOOL fSuccess; TCHAR achText[32]; FunctionName(ValidateDlgInts); ASSERTTRUE(cvinf > 0); do { dw = GetDlgItemInt(hDlg, pvinf->id, &fSuccess, pvinf->iMin < 0); // NOTE: AUTO is for "Auto" only, whereas AUTOMINMAX is for // "Auto" and "None". However, in the interest of simplicity, I // don't complain if either string is used in either case. if (pvinf->fbOpt & (VINF_AUTO | VINF_AUTOMINMAX)) { if (!fSuccess) { GetDlgItemText(hDlg, pvinf->id, achText, ARRAYSIZE(achText)); if (lstrcmpi(achText, g_szNone) == 0 || lstrcmpi(achText, g_szAuto) == 0) { continue; // things be lookin' good, check next int... } } } if (!fSuccess || dw < (DWORD)pvinf->iMin || dw > (DWORD)pvinf->iMax) { Warning(hDlg, pvinf->idMsg, MB_ICONEXCLAMATION | MB_OK, pvinf->iMin, pvinf->iMax); SendDlgItemMessage(hDlg, pvinf->id, EM_SETSEL, 0, MAKELPARAM(0,-1)); SetFocus(GetDlgItem(hDlg, pvinf->id)); return TRUE; // things be lookin' bad, bail out... } } while (++pvinf, --cvinf); return FALSE; } /* * NOTE -- The compiler emits really bad code for some of these guys. * In those cases, we are merely wrapping a call; there is no need to save BP. */ /** LimitDlgItemText - Sets the limit for a dialog edit control * * INPUT * hDlg = HWND of dialog box * iCtl = ID of control * uiLimit = text limit * * OUTPUT * None. */ void LimitDlgItemText(HWND hDlg, int iCtl, UINT uiLimit) { FunctionName(LimitDlgItemText); SendDlgItemMessage(hDlg, iCtl, EM_LIMITTEXT, uiLimit, 0); } /** SetDlgItemPosRange - Sets the pos and range for a dialog slider control * * INPUT * hDlg = HWND of dialog box * iCtl = ID of control * uiPos = Current position * dwRange = Range (min in low word, max in high word) * * OUTPUT * None. */ void SetDlgItemPosRange(HWND hDlg, int iCtl, UINT uiPos, DWORD dwRange) { FunctionName(SetDlgItemPosRange); SendDlgItemMessage(hDlg, iCtl, TBM_SETRANGE, 0, dwRange); SendDlgItemMessage(hDlg, iCtl, TBM_SETPOS, TRUE, uiPos); } /** GetDlgItemPos - Gets the pos of a dialog slider control * * INPUT * hDlg = HWND of dialog box * iCtl = ID of control * * OUTPUT * Trackbar position. */ UINT GetDlgItemPos(HWND hDlg, int iCtl) { FunctionName(GetDlgItemPos); return (UINT)SendDlgItemMessage(hDlg, iCtl, TBM_GETPOS, 0, 0); } /** SetDlgItemPct - Sets the pos for a dialog slider control that measures % * * INPUT * hDlg = HWND of dialog box * iCtl = ID of control * uiPct = Current position (range 0 .. 100) * * OUTPUT * None. */ void SetDlgItemPct(HWND hDlg, int iCtl, UINT uiPct) { FunctionName(SetDlgItemPct); SetDlgItemPosRange(hDlg, iCtl, uiPct / (100/NUM_TICKS), MAKELONG(0, NUM_TICKS)); } /** GetDlgItemPct - Gets the pos of a dialog slider control that measures % * * INPUT * hDlg = HWND of dialog box * iCtl = ID of control * * OUTPUT * Slider position in the range 0 .. 100. */ UINT GetDlgItemPct(HWND hDlg, int iCtl) { FunctionName(GetDlgItemPct); return GetDlgItemPos(hDlg, iCtl) * (100/NUM_TICKS); } /** EnableDlgItems - Enables or disables a collection of dialog controls * * INPUT * hDlg = HWND of dialog box * pbinf -> array of bitinfo descriptors * cbinf = size of array * fEnable = whether the control should be enabled or disabled * * OUTPUT * Dialog items have changed state. */ void EnableDlgItems(HWND hDlg, PBINF pbinf, int cbinf, BOOL fEnable) { FunctionName(EnableDlgItems); ASSERTTRUE(cbinf > 0); do { EnableWindow(GetDlgItem(hDlg, pbinf->id), fEnable); } while (++pbinf, --cbinf); } /** DisableDlgItems - Disables a collection of dialog controls * * Most of the time, we call EnableDlgItems with fEnable = TRUE, so * this is a handy wrapper. (Too bad the compiler emits awful code.) * * INPUT * hDlg = HWND of dialog box * pbinf -> array of bitinfo descriptors * cbinf = size of array * * OUTPUT * Dialog items have been disabled. */ void DisableDlgItems(HWND hDlg, PBINF pbinf, int cbinf) { FunctionName(DisableDlgItems); EnableDlgItems(hDlg, pbinf, cbinf, 0); } /** AdjustRealModeControls - Disables selected items if single-app mode * * If the proplink says that "single-application mode" is enabled, * then hide all controls whose IDs are less than 4000 and show all * controls whose IDs are greater than or equal to 5000. Controls whose * IDs are in the 4000's are immune to all this hiding/showing. Controls * in the 3000's are actually disabled rather than hidden. Controls in * the 6000's are actually disabled rather than hidden as well. * * RST: Ok, this is nice in theory, but now that we've pulled over this * stuff into shell32.dll, we'll have to go off the actual IDC_ * defines instead of the magic #'s of 3000, 4000 and 5000. * * IDC_ICONBMP == 3001 * IDC_PIF_STATIC == 4000 * IDC_REALMODEISABLE == 5001 * * So, when adding things to shell232.rc or ids.h, plan * accordingly. * * INPUT * ppl = proplink * hDlg = HWND of dialog box * * OUTPUT * Dialog items have been disabled/enabled shown/hidden. * Returns nonzero if we are in normal (not single-app) mode. */ BOOL CALLBACK EnableEnumProc(HWND hwnd, LPARAM lp) { int f; LONG l; f = SW_SHOW; l = GetWindowLong(hwnd, GWL_ID); if (!LOWORD(lp) && l < IDC_PIF_STATIC || LOWORD(lp) && l >= IDC_REALMODEDISABLE) f = SW_HIDE; if (l < IDC_ICONBMP || l >= IDC_PIF_STATIC && l < IDC_CONFIGLBL) ShowWindow(hwnd, f); else EnableWindow(hwnd, f == SW_SHOW); return TRUE; } BOOL AdjustRealModeControls(PPROPLINK ppl, HWND hDlg) { BOOL fNormal; FunctionName(AdjustRealModeControls); fNormal = !(ppl->flProp & PROP_REALMODE); EnumChildWindows(hDlg, EnableEnumProc, fNormal); return fNormal; } /** OnWmHelp - Handle a WM_HELP message * * This is called whenever the user presses F1 or clicks the help * button in the title bar. We forward the call on to the help engine. * * INPUT * lparam = LPARAM from WM_HELP message (LPHELPINFO) * pdwHelp = array of DWORDs of help info * * OUTPUT * * None. */ void OnWmHelp(LPARAM lparam, const DWORD *pdwHelp) { FunctionName(OnWmHelp); WinHelp((HWND) ((LPHELPINFO) lparam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR) (LPTSTR) pdwHelp); } /** OnWmContextMenu - Handle a WM_CONTEXTMENU message * * This is called whenever the user right-clicks on a control. * We forward the call on to the help engine. * * INPUT * wparam = WPARAM from WM_HELP message (HWND) * pdwHelp = array of DWORDs of help info * * OUTPUT * * None. */ void OnWmContextMenu(WPARAM wparam, const DWORD *pdwHelp) { FunctionName(OnWmContextMenu); WinHelp((HWND) wparam, NULL, HELP_CONTEXTMENU, (DWORD_PTR) (LPTSTR) pdwHelp); } #ifdef UNICODE /** PifMgr_WCtoMBPath - Converts UNICODE path to it's ANSI representation * * This is called whenever we need to convert a UNICODE path to it's * best approximation in ANSI. Sometimes this will be a direct mapping, * but sometimes not. We may have to use the short name, etc. * * INPUT * lpUniPath -> pointer UNICODE path (NULL terminated) * lpAnsiPath -> pointer to buffer to hold ANSI path * cchBuf -> size of ANSI buffer, in characters * * OUTPUT * * lpAnsiPath buffer contains ANSI representation of lpUniPath */ void PifMgr_WCtoMBPath(LPWSTR lpUniPath, LPSTR lpAnsiPath, UINT cchBuf ) { WCHAR awchPath[ MAX_PATH ]; // Should be bigger than any PIF string CHAR achPath[ MAX_PATH ]; // Should be bigger than any PIF string UINT cchAnsi = 0; FunctionName(PifMgr_WCtoMBPath); // Try converting to Ansi and then converting back and comparing. // If we get back exactly what we started with, this is the "simple" // case. cchAnsi = WideCharToMultiByte( CP_ACP, 0, lpUniPath, -1, achPath, MAX_PATH, NULL, NULL ); if (cchAnsi && (cchAnsi<=cchBuf)) { // Now try converting back MultiByteToWideChar( CP_ACP, 0, achPath, -1, awchPath, MAX_PATH ); if (lstrcmp(lpUniPath,awchPath)==0) { // We're done...copy over the string. lstrcpynA( lpAnsiPath, achPath, cchBuf ); *(BYTE UNALIGNED *)(lpAnsiPath+cchBuf-1) = '\0'; return; } // Well, the string has some unmappable UNICODE // character in it, so try option #2 -- using the // short path name. goto TryShortPathName; } else { TryShortPathName: // Hmmm, the best we can do is to use the short path name and map // it to ANSI. GetShortPathName( lpUniPath, awchPath, MAX_PATH ); awchPath[ MAX_PATH-1 ] = TEXT('\0'); WideCharToMultiByte( CP_ACP, 0, awchPath, -1, lpAnsiPath, cchBuf, NULL, NULL ); // Make sure we're NULL terminated *(BYTE UNALIGNED *)(lpAnsiPath+cchBuf-1) = '\0'; } } #endif