IUTIL.C
//******************************************************************************************* 
// 
// Filename : IUtil.c 
// 
//Implementation of Cab_MergeMenus and some other useful 
//              routines 
// 
// Copyright 1994 - 1998 Microsoft Corporation. All rights reserved 
// 
//******************************************************************************************* 
 
 
#include "pch.h" 
#include "Cabvw2.h" 
 
// Copy a menu onto the beginning or end of another menu 
// Adds uIDAdjust to each menu ID (pass in 0 for no adjustment) 
// Will not add any item whose adjusted ID is greater than uMaxIDAdjust 
// (pass in 0xffff to allow everything) 
// Returns one more than the maximum adjusted ID that is used 
// 
 
BOOL _SHIsMenuSeparator(HMENU hm, int i) 
{ 
        MENUITEMINFO mii; 
 
        mii.cbSize = sizeof(MENUITEMINFO); 
        mii.fMask = MIIM_TYPE; 
        mii.cch = 0;    // WARNING: We MUST initialize it to 0!!! 
        if (!GetMenuItemInfo(hm, i, TRUE, &mii)) 
        { 
                return(FALSE); 
        } 
 
        if (mii.fType & MFT_SEPARATOR) 
        { 
                return(TRUE); 
        } 
 
        return(FALSE); 
} 
 
UINT Cab_MergeMenus(HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags) 
{ 
        int nItem; 
        HMENU hmSubMenu; 
        BOOL bAlreadySeparated; 
        MENUITEMINFO miiSrc; 
        char szName[256]; 
        UINT uTemp, uIDMax = uIDAdjust; 
 
        if (!hmDst || !hmSrc) 
        { 
                goto MM_Exit; 
        } 
 
        nItem = GetMenuItemCount(hmDst); 
        if (uInsert >= (UINT)nItem) 
        { 
                uInsert = (UINT)nItem; 
                bAlreadySeparated = TRUE; 
        } 
        else 
        { 
                bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);; 
        } 
 
        if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 
        { 
                // Add a separator between the menus 
                InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 
                bAlreadySeparated = TRUE; 
        } 
 
 
        // Go through the menu items and clone them 
        for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--) 
        { 
        miiSrc.cbSize = sizeof(MENUITEMINFO); 
        miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA; 
                // We need to reset this every time through the loop in case 
                // menus DON'T have IDs 
                miiSrc.fType = MFT_STRING; 
                miiSrc.dwTypeData = szName; 
                miiSrc.dwItemData = 0; 
                miiSrc.cch        = sizeof(szName); 
 
                if (!GetMenuItemInfo(hmSrc, nItem, TRUE, &miiSrc)) 
                { 
                        continue; 
                } 
 
                if (miiSrc.fType & MFT_SEPARATOR) 
                { 
                        // This is a separator; don't put two of them in a row 
                        if (bAlreadySeparated) 
                        { 
                                continue; 
                        } 
 
                        bAlreadySeparated = TRUE; 
                } 
                else if (miiSrc.hSubMenu) 
                { 
                        if (uFlags & MM_SUBMENUSHAVEIDS) 
                        { 
                                // Adjust the ID and check it 
                                miiSrc.wID += uIDAdjust; 
                                if (miiSrc.wID > uIDAdjustMax) 
                                { 
                                        continue; 
                                } 
 
                                if (uIDMax <= miiSrc.wID) 
                                { 
                                        uIDMax = miiSrc.wID + 1; 
                                } 
                        } 
                        else 
                        { 
                                // Don't set IDs for submenus that didn't have 
                                // them already 
                                miiSrc.fMask &= ~MIIM_ID; 
                        } 
 
                        hmSubMenu = miiSrc.hSubMenu; 
                        miiSrc.hSubMenu = CreatePopupMenu(); 
                        if (!miiSrc.hSubMenu) 
                        { 
                                goto MM_Exit; 
                        } 
 
                        uTemp = Cab_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, 
                                uIDAdjustMax, uFlags&MM_SUBMENUSHAVEIDS); 
                        if (uIDMax <= uTemp) 
                        { 
                                uIDMax = uTemp; 
                        } 
 
                        bAlreadySeparated = FALSE; 
                } 
                else 
                { 
                        // Adjust the ID and check it 
                        miiSrc.wID += uIDAdjust; 
                        if (miiSrc.wID > uIDAdjustMax) 
                        { 
                                continue; 
                        } 
 
                        if (uIDMax <= miiSrc.wID) 
                        { 
                                uIDMax = miiSrc.wID + 1; 
                        } 
 
                        bAlreadySeparated = FALSE; 
                } 
 
                if (!InsertMenuItem(hmDst, uInsert, TRUE, &miiSrc)) 
                { 
                        goto MM_Exit; 
                } 
        } 
 
        // Ensure the correct number of separators at the beginning of the 
        // inserted menu items 
        if (uInsert == 0) 
        { 
                if (bAlreadySeparated) 
                { 
                        DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 
                } 
        } 
        else 
        { 
                if (_SHIsMenuSeparator(hmDst, uInsert-1)) 
                { 
                        if (bAlreadySeparated) 
                        { 
                                DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 
                        } 
                } 
                else 
                { 
                        if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 
                        { 
                                // Add a separator between the menus 
                                InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 
                        } 
                } 
        } 
 
MM_Exit: 
        return(uIDMax); 
} 
 
 
 
int OleStrToStrN(LPSTR psz, int cchMultiByte, LPCOLESTR pwsz, int cchWideChar) 
{ 
    return WideCharToMultiByte(CP_ACP, 0, pwsz, cchWideChar, psz, cchMultiByte, NULL, NULL); 
} 
 
int OleStrToStr(LPSTR psz, LPCOLESTR pwsz) 
{ 
    return WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz, MAX_PATH, NULL, NULL); 
} 
 
int StrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCSTR psz, int cchMultiByte) 
{ 
    return MultiByteToWideChar(CP_ACP, 0, psz, cchMultiByte, pwsz, cchWideChar); 
} 
 
int StrToOleStr(LPOLESTR pwsz, LPCSTR psz) 
{ 
    return MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, MAX_PATH); 
} 
 
/* 
 *  
 */ 
 
 
UINT ILGetSize(LPCITEMIDLIST pidl) 
{ 
    UINT cbTotal = 0; 
    if (pidl) 
    { 
        VALIDATE_PIDL(pidl); 
cbTotal += sizeof(pidl->mkid.cb);// Null terminator 
while (pidl->mkid.cb) 
{ 
    cbTotal += pidl->mkid.cb; 
    pidl = _ILNext(pidl); 
} 
    } 
 
    return cbTotal; 
} 
 
 
LPITEMIDLIST ILClone(LPCITEMIDLIST pidl) 
{ 
    UINT cb = ILGetSize(pidl); 
    LPMALLOC pMalloc; 
LPITEMIDLIST pidlRet; 
 
SHGetMalloc(&pMalloc);  
pidlRet = (LPITEMIDLIST)pMalloc->lpVtbl->Alloc(pMalloc, cb); 
pMalloc->lpVtbl->Release(pMalloc); 
 
    if (pidlRet) 
    { 
// Notes: no need to zero-init. 
hmemcpy(pidlRet, pidl, cb); 
    } 
    return pidlRet; 
} 
 
 
void ILFree(LPITEMIDLIST pidl) 
{ 
LPMALLOC pMalloc; 
 
    if (pidl) 
    { 
#ifdef DEBUG 
        UINT cbSize = ILGetSize(pidl); 
        VALIDATE_PIDL(pidl); 
 
        // Fill the memory with some bad value... 
        _fmemset(pidl, 0xE5, cbSize); 
 
        // If large enough try to save the call return address of who 
        // freed us in the 3-6 byte of the structure. 
        if (cbSize >= 6) 
            *((UINT*)((LPSTR)pidl + 2)) =  *(((UINT*)&pidl) - 1); 
 
#endif 
SHGetMalloc(&pMalloc); 
pMalloc->lpVtbl->Free(pMalloc, pidl); 
pMalloc->lpVtbl->Release(pMalloc); 
 
    } 
}