c++windowswinapikeyboard-shortcutsaccelerator

LoadAccelerators for a specific resource language


I want to call LoadAccelerators but for a specific language in the resources. Is there a way to do it?


Solution

  • I did some reverse engineering and here's how to load it from memory for a specific LCID:

    #pragma pack(push, 1) // exact fit - no padding
    struct ACCEL_MEM{
        BYTE fVirt;
        BYTE byteReserved;
        WORD wKey;
        WORD wCmd;
        WORD wReserved;
    };
    #pragma pack(pop)
    
    HACCEL LoadAcceleratorsIndirectWithLCID(UINT nResourceID, LCID lcid)
    {
        //Open accelerators table with the 'nResourceID'
        //'nResourceID' = Resource ID to use
        //'lcid' = LCID to load resources for, or NULL to use the one from current thread
        //RETURN:
        //      = HACCEL loaded -- must be removed with DestroyAcceleratorTable(), or
        //      = NULL if error
        ASSERT(nResourceID);
    
        HACCEL hAccel = NULL;
    
        HINSTANCE hInst = ::GetModuleHandle(NULL);
        if(hInst)
        {
            //Do we have a LCID?
            if(lcid == NULL)
                lcid = ::GetThreadLocale();
    
            //Get language ID
            LANGID langid = LANGIDFROMLCID(lcid);
    
            //Try to load for specified resource
            HRSRC hResource = ::FindResourceEx(hInst, RT_ACCELERATOR, MAKEINTRESOURCE(nResourceID), langid);
            if(hResource == NULL)
            {
                //If failed, use default lcid
                hResource = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_ACCELERATOR);
            }
    
            if(hResource)
            {
                HGLOBAL hglb = LoadResource(hInst, hResource);
                if(hglb)
                {
                    LPVOID lpsz = LockResource(hglb);
                    DWORD dwcbSz = ::SizeofResource(hInst, hResource);
                    if(lpsz &&
                        dwcbSz)
                    {
                        ACCEL_MEM* pMem = (ACCEL_MEM*)lpsz;
    
                        //Count items in the table
                        int nCnt = 0;
                        ACCEL_MEM* pTest = pMem;
                        for(;; pTest++)
                        {
                            nCnt++;
                            if(pTest->fVirt & 0x80)
                                break;
                        }
    
                        //Reserve mem
                        ACCEL* pAccels = new ACCEL[nCnt];
    
                        //Parse data
                        for(int i = 0; i < nCnt; i++)
                        {
                            pAccels[i].fVirt = pMem[i].fVirt & 0x7f;
                            pAccels[i].key = pMem[i].wKey;
                            pAccels[i].cmd = pMem[i].wCmd;
                        }
    
                        //Create accel table
                        hAccel = ::CreateAcceleratorTable(pAccels, nCnt);
    
                        //Free mem
                        delete[] pAccels;
                        pAccels = NULL;
                    }
                }
            }
        }
    
        return hAccel;
    }