Расширение оболочки Explorer (контекстное меню для проводника)

 

Всем известны программы winrar или winamp , которые умеют добавлять свой пункт меню в контекстное меню. При клике по этому пункту , в программу передается\передаются нужные файлы. Когда я только начинал программировать, то обходился более простой реализацией: добавлял в реестр ключ для передачи файлов через командную строку. Но данный способ хорош только для простых программ вроде notepad (то есть когда нужно передать 1 файл). Когда нужно передать несколько файлов, то командная строка для каждого переданного файла запускает новые копии программы. Конечно при добротных костылях можно реализовать и этот способ (и я так уже делал), но все это будет выглядеть очень некрасиво, да и работать медленно при больших кол-вах переданных файлов. Более того данный способ не дает всей широты возможностей , например нет возможности добавить свою иконку. Майкрософт создавая проводник (explorer) , внедрили возможность его расширения. Код ниже как раз показывает как можно создать свое расширение explorer (контекстное меню для проводника). Я не знаю будет ли работать код в 64х битной системе, но на моей 32х битной кажется работает нормально. Чтобы не засорять сервер лишними архивами или файлами, я поместил изображение бинарно в код DLL. То есть данный код самодостаточен, просто скомпилируйте DLL под любым именем.  Для тестирования запустите CMD под администратором, пройдите в папку расположения вашей DLL и введите в CMD следующее:

regsvr32 ваше_имя.dll  (это для регистрации пункта меню)

При успешной регистрации , должно получиться примерно следующее:

regsvr32.png

 

Ну а дальше просто выделяете любой файл\файлы в проводнике и щелкаете правой кнопкой мыши. Должно появится примерно следующее:

fbcontextmenu.png

При выборе нашего пункта, появится messageBox с именами выбранных файлов. 

Да... на папках не работает. Чтобы можно было выделять и папки, нужно в функцию регистрации и удаления регистрации добавлять соотвествующие ключи для реестра. 

Когда захотите удалить меню, наберите: regsvr32 /u ваше_имя.dll

Чтобы удалить dll , нужно либо перезагрузить explorer либо перезагрузить компьютер. Вот пожалуй и все!

Платформа: Windows (тестировалась на windows 7 , 32х бит)
Компилятор: freebasic 1.03.0 , но должен работать и более старых версиях
Автор: Станислав Будинов

#DEFINE _UNICODE
#DEFINE ID_SHELLTEST_C 1

#INCLUDE Once "windows.bi"
#INCLUDE Once "crt.bi"
#INCLUDE Once "win/ocidl.bi"
#INCLUDE Once "win/shlobj.bi"
#INCLUDE Once "win/olectl.bi"

Static Shared CLSIDS_POINT As ZString*2048 = "{9D267B24-B27F-46E1-9062-6FC17716095E}"
Dim Shared  CLSID_POINT As IID=Type(&h9D267B24, &hB27F, &h46E1, {&h90, &h62, &h6F, &hC1, &h77, &h16, &h09, &h5E})

Dim Shared nRefDll As UINT
Dim Shared As Integer nNumberFileSelect
Redim Shared As ZString*MAX_PATH ArrayFiles()
Dim Shared As IContextMenuVtbl pIContextMenuVtbl
Dim Shared As IShellExtInitVtbl  pIShellExtInitVtbl
Extern data_1(0 To 1654-1) As Ubyte
Dim pBi As BITMAPINFO Ptr
Dim Shared bmpMenu As HBITMAP           
Dim pBih As BITMAPFILEHEADER Ptr = Cast( Any Ptr, @data_1(0) )
pBi = Cast(BITMAPINFO Ptr, pBih + 1)
Dim As HDC hdc = GetDC( 0 )
bmpMenu = CreateDIBitmap( hdc, _
                                  @pBi->bmiHeader, _
                                  CBM_INIT, _
                                  Cast(Byte Ptr, pBih) + pBih->bfOffBits, _
                                  pBi, _
                                  DIB_RGB_COLORS ) 
ReleaseDC(0,hdc)                                  

Type ConText_ClassFactory
    icf         As IClassFactory
    cRef        As Integer
End Type

Type ConTextMenu_Class
    cm As IContextMenu
    si As IShellExtInit
    cRef As Integer
End Type

Function IContextMenu_QueryInterface_(pIm As IContextMenu Ptr, iid As REFIID, ppv As LPVOID Ptr) As HRESULT
    Dim  pThis As ConTextMenu_Class  Ptr
    pThis   = Cast(ConTextMenu_Class  Ptr,pIm)
    If memcmp(iid, @IID_IUnknown, Sizeof(GUID))=0 Or memcmp(iid, @IID_IContextMenu, Sizeof(GUID))=0 Then
        *ppv = pThis
        pThis->cRef+=1
        Return  S_OK
    Elseif memcmp(iid, @IID_IShellExtInit, Sizeof(GUID))=0 Then
        *ppv = @(pThis->si)
        pThis->cRef+=1
        Return  S_OK
    End If
    ppv = NULL
    Return  E_NOINTERFACE
End Function


Function IContextMenu_AddRef_(pIm As IContextMenu Ptr) As Ulong
    Dim   pThis As ConTextMenu_Class  Ptr
    pThis = Cast(ConTextMenu_Class  Ptr,pIm)
    pThis->cRef +=1
    Return  pThis->cRef
End Function


Function IContextMenu_Release_(pIm As IContextMenu Ptr) As Ulong
    Dim   pThis As ConTextMenu_Class  Ptr
    pThis = Cast(ConTextMenu_Class  Ptr,pIm)
    pThis->cRef-=1
    If pThis->cRef = 0 Then
        Deallocate(pIm)
        nRefDll -=1
        Return 0
    End If
    Return pThis->cRef
End Function

Function IContextMenu_QueryContextMenu_( pIm As IContextMenu Ptr, hmenu As HMENU, indexMenu As Uinteger, idCmdFirst As Uinteger, idCmdLast As Uinteger, uFlags As Uinteger) As HRESULT
    If (uFlags And CMF_DEFAULTONLY) Then
        Return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,0)
    Endif
    InsertMenu(hMenu,1, MF_STRING Or MF_BYPOSITION, (idCmdFirst + ID_SHELLTEST_C),("Test item FreebasicShell"))
    SetMenuItemBitmaps(hMenu,1,MF_BITMAP Or MF_BYPOSITION,bmpMenu,bmpMenu)
    Return MAKE_HRESULT(0, FACILITY_NULL, ID_SHELLTEST_C + 1)
End Function


Function IContextMenu_GetCommandString_( pIm As IContextMenu Ptr, idCmd As Uinteger, uFlags As Uinteger, pwReserved As PUINT, pszName As LPSTR, cchMax As Uinteger) As Integer
    Return E_NOTIMPL
End Function

Function IContextMenu_InvokeCommand_( pIm As IContextMenu Ptr, pici As LPCMINVOKECOMMANDINFO) As HRESULT
    Select Case Loword(pici->lpVerb)
        Case ID_SHELLTEST_C
            Dim As String szValue
            If nNumberFileSelect>=1 Then
                For i As Integer = 0 To nNumberFileSelect-1
                    szValue &= (ArrayFiles(i) & !"\r\n" )
                Next
                MessageBox(NULL, szValue ,"Selected files", MB_OK + MB_ICONINFORMATION)
            Endif
            Return S_OK
        Case Else
            Return E_FAIL
    End Select
End Function

Function  CShellInitExt_QueryInterface_(pThis As IShellExtInit Ptr, riid As REFIID , ppv As LPVOID Ptr) As HRESULT
    Return Cast(IContextMenu Ptr ,pThis - 1)->lpVtbl->QueryInterface(Cast(IContextMenu Ptr ,(pThis - 1)),riid,ppv)
End Function

Function CShellInitExt_AddRef_(pThis As IShellExtInit Ptr)As Ulong
    Return Cast(IContextMenu Ptr ,pThis - 1)->lpVtbl->AddRef(Cast(IContextMenu Ptr ,(pThis - 1)))
End Function

Function  CShellInitExt_Release_( pThis As IShellExtInit Ptr) As Ulong
    Return Cast(IContextMenu Ptr ,pThis - 1)->lpVtbl->Release(Cast(IContextMenu Ptr ,(pThis - 1)))
End Function

Function CShellInitExt_Initialize_(Byval pIShell As IShellExtInit Ptr,Byval pidlFolder As LPCITEMIDLIST,Byval pdtobj As LPDATAOBJECT, Byval hkeyProgID As HKEY)As HRESULT
    If pdtobj <>0 Then
        Dim fe As FORMATETC
        fe.cfFormat = CF_HDROP
        fe.dwAspect = DVASPECT_CONTENT
        fe.lindex = -1
        fe.tymed = TYMED_HGLOBAL
        Dim medium As STGMEDIUM

        If pdtobj->lpVtbl->GetData(pdtobj,@fe, @medium)=S_OK Then
            Var uCount = DragQueryFile(medium.hGlobal, -1, 0, 0)
            nNumberFileSelect = uCount
            Redim As ZString*MAX_PATH ArrayFiles(uCount)
            If uCount>=1 Then
                For dd As Integer=0 To uCount-1
                    Dim As ZString*MAX_PATH m_szFile
                    DragQueryFile(medium.hGlobal, dd, m_szFile, MAX_PATH)
                    If Len(m_szFile)=0 Then
                        uCount = 0
                    Else
                        ArrayFiles(dd) = m_szFile
                    Endif
                Next
            Endif
            ReleaseStgMedium(@medium)
            If uCount>=1 Then
                Return S_OK
            Endif
        Endif
    Endif
    Return S_FALSE
End Function

pIShellExtInitVtbl = Type(@CShellInitExt_QueryInterface_, _
@CShellInitExt_AddRef_, _
@CShellInitExt_Release_, _
@CShellInitExt_Initialize_)

pIContextMenuVtbl = Type(@IContextMenu_QueryInterface_, _
@IContextMenu_AddRef_, _
@IContextMenu_Release_, _
@IContextMenu_QueryContextMenu_ , _
@IContextMenu_InvokeCommand_ , _
@IContextMenu_GetCommandString_ )

Function ClassFactory_CFQueryInterface(pCF As IClassFactory Ptr, iid As REFIID, ppvObject As LPVOID Ptr) As HRESULT
    Dim   pThis As ConText_ClassFactory Ptr
    pThis = Cast(ConText_ClassFactory Ptr,pCF)
    If IsEqualIID( iid, @IID_IUnknown) Or IsEqualIID( iid, @IID_IClassFactory) Then
        *ppvObject = pThis
        pThis->icf.lpVtbl->AddRef(pCF)
        Return  S_OK
    End If
    *ppvObject = NULL
    Return  E_NOINTERFACE
End Function

Function ClassFactory_CFAddRef(pCF As IClassFactory Ptr) As Ulong
    Dim   pThis As ConText_ClassFactory Ptr
    pThis = Cast(ConText_ClassFactory Ptr,pCF)
    pThis->cRef +=1
    Return pThis->cRef
End Function

Function  ClassFactory_CFRelease( pCF As IClassFactory Ptr) As Ulong
    Dim   pThis As ConText_ClassFactory Ptr
    pThis = Cast(ConText_ClassFactory Ptr,pCF)
    pThis->cRef -=1
    If pThis->cRef = 0 Then
        Deallocate( pThis )
        pThis = 0
        nRefDll -=1
        Return  0
    End If
    Return pThis->cRef
End Function

Function ClassFactory_CFCreateInstance( pICF As IClassFactory Ptr, pUnkOuter As IUnknown Ptr, riid As REFIID, ppvObject As LPVOID Ptr) As HRESULT
    Dim   pThis As ConText_ClassFactory Ptr
    Dim   pCM As ConTextMenu_Class  Ptr

    pThis = Cast(ConText_ClassFactory Ptr,pICF)
    If pUnkOuter <> NULL Then
        Return  CLASS_E_NOAGGREGATION
    End If

    pCM = Cast(ConTextMenu_Class  Ptr,Callocate(Sizeof(ConTextMenu_Class)))
    If NULL = pCM Then
        Return  E_OUTOFMEMORY
    End If

    pCM->cm.lpVtbl = @pIContextMenuVtbl
    pCM->si.lpVtbl = @pIShellExtInitVtbl
    pCM->cRef = 1
    nRefDll +=1

    Var hr = pCM->cm.lpVtbl->QueryInterface(@(pCM->cm), riid, ppvObject)
    If hr <>  S_OK Then
        Deallocate( pCM )
        Return  E_NOINTERFACE
    End If

    pCM->cm.lpVtbl->Release(@(pCM->cm))
    Return hr
End Function

Function ClassFactory_CFLockServer( pICF As IClassFactory Ptr, fLock As BOOL) As HRESULT
    Return E_NOTIMPL
End Function

Static Shared As IClassFactoryVtbl pIClassFactoryVtbl = Type(@ClassFactory_CFQueryInterface, _
@ClassFactory_CFAddRef, _
@ClassFactory_CFRelease, _
@ClassFactory_CFCreateInstance,  _
@ClassFactory_CFLockServer)

Extern "windows-ms"
#Undef DllRegisterServer
#Undef DllUnregisterServer
Function DllRegisterServer() As Long   Export
    Dim As HKEY hKey1
    If RegCreateKeyEx(HKEY_CLASSES_ROOT, "*\shellex\ContextMenuHandlers\FreeBasicShell", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, Null, @hKey1, 0)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    RegSetValueEx(hKey1, "", 0, REG_SZ, @"{9D267B24-B27F-46E1-9062-6FC17716095E}", 38)
    If hKey1<>0 Then  RegCloseKey(hKey1):hKey1 = 0
    If RegCreateKeyEx(HKEY_CLASSES_ROOT, "FreeBasicShell\shellex\ContextMenuHandlers", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, Null, @hKey1, 0)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    RegSetValueEx(hKey1, "", 0, REG_SZ, @"{9D267B24-B27F-46E1-9062-6FC17716095E}", 38)
    If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    If RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, Null, @hKey1, 0)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    RegSetValueEx(hKey1, "{9D267B24-B27F-46E1-9062-6FC17716095E}", 0, REG_SZ, @"FreeBasicShell", 15)
    If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    Dim As ZString*MAX_PATH szBuffer
    Dim As HMODULE hmod
    GetModuleHandleEx(4,Cast(LPSTR,@DllRegisterServer) , @hMod)
    If GetModuleFileName(hMod, szBuffer, MAX_PATH)<>0 Then
        If RegCreateKeyEx(HKEY_CLASSES_ROOT, "CLSID\{9D267B24-B27F-46E1-9062-6FC17716095E}", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, Null, @hKey1, 0)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
        RegSetValueEx(hKey1, "", 0, REG_SZ, @"FreeBasicShell", 15)
        If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
        If RegCreateKeyEx(HKEY_CLASSES_ROOT, "CLSID\{9D267B24-B27F-46E1-9062-6FC17716095E}\InProcServer32", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, Null, @hKey1, 0)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
        RegSetValueEx(hKey1, "", 0, REG_SZ, @szBuffer, Len(szBuffer)+1)
        RegSetValueEx(hKey1, "ThreadingModel", 0, REG_SZ, @"Apartment", 10)
        If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    Else
        Return SELFREG_E_CLASS
    Endif
    Return S_OK
End Function

Function DllUnregisterServer()As HRESULT  Export
    Dim As HKEY hkey1
    If RegDeleteKey(HKEY_CLASSES_ROOT, "*\shellex\ContextMenuHandlers\FreeBasicShell")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteKey(HKEY_CLASSES_ROOT, "FreeBasicShell\shellex\ContextMenuHandlers")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteKey(HKEY_CLASSES_ROOT, "FreeBasicShell\shellex")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteKey(HKEY_CLASSES_ROOT, "FreeBasicShell")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", 0, KEY_ALL_ACCESS, @hKey1)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteValue(hKey1, "{9D267B24-B27F-46E1-9062-6FC17716095E}")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    If RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID\{9D267B24-B27F-46E1-9062-6FC17716095E}", 0, KEY_ALL_ACCESS, @hKey1)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteKey(hKey1, "InProcServer32")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    If RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_ALL_ACCESS, @hKey1)<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If RegDeleteKey(hKey1, "{9D267B24-B27F-46E1-9062-6FC17716095E}")<>ERROR_SUCCESS Then Return SELFREG_E_CLASS
    If hKey1<>0 Then RegCloseKey(hKey1):hKey1 = 0
    Return S_OK
End Function

#Undef DllCanUnloadNow
Function DllCanUnloadNow() As HRESULT  Export
    If nRefDll = 0 Then 
        Return  S_OK
    End If
    Return S_FALSE 
End Function

#Undef DllGetClassObject
Function DllGetClassObject(rclsid As REFCLSID, riid As REFIID , ppv As LPVOID Ptr) As HRESULT  Export
    Dim As ConText_ClassFactory Ptr  pCF = NULL

    If IsEqualCLSID( @CLSID_POINT, rclsid ) Then
        If pCF = NULL Then
            pCF = Callocate(Sizeof(pCF))
            If pCF = NULL Then
                Return E_OUTOFMEMORY
            End If
        End If
        pCF->icf.lpVtbl = @(pIClassFactoryVtbl)
        pCF->cRef = 0
        Return  ClassFactory_CFQueryInterface(Cast(IClassFactory Ptr,pCF), riid, ppv )
    End If
    Return  CLASS_E_CLASSNOTAVAILABLE
End Function

End Extern


Dim Shared data_1(0 To 1654-1) As Ubyte = { _
&h42,&h4D,&h76,&h6,&h0,&h0,&h0,&h0,&h0,&h0,&h36,&h4,&h0,&h0,&h28,&h0,&h0,&h0,&h18,&h0,&h0,&h0,&h18,&h0,&h0,&h0,&h1,&h0,&h8,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&hC4,&hE,&h0,&h0,&hC4,&hE,&h0,&h0,&h0,&h1,&h0,&h0,&h0,&h1,&h0,&h0,&h0,&h0,&h0,&hFF,&h1,&h1,&h4,&hFF, _
&h4,&h4,&h8,&hFF,&h6,&h6,&hC,&hFF,&h8,&h9,&h10,&hFF,&hA,&hC,&h14,&hFF,&hD,&hD,&h18,&hFF,&hF,&h10,&h1C,&hFF,&h11,&h12,&h20,&hFF,&h13,&h15,&h24, _
&hFF,&h16,&h18,&h28,&hFF,&h18,&h1A,&h2C,&hFF,&h1A,&h1C,&h30,&hFF,&h1D,&h1E,&h34,&hFF,&h1F,&h21,&h38,&hFF,&h21,&h24,&h3C,&hFF,&h23,&h26,&h40,&hFF,&h26,&h28, _
&h44,&hFF,&h2A,&h2D,&h4C,&hFF,&h2C,&h30,&h50,&hFF,&h2F,&h32,&h54,&hFF,&h31,&h34,&h58,&hFF,&h33,&h37,&h5C,&hFF,&h36,&h39,&h60,&hFF,&h3A,&h3E,&h68,&hFF,&h3C, _
&h40,&h6C,&hFF,&h3F,&h43,&h70,&hFF,&h41,&h45,&h74,&hFF,&h43,&h48,&h78,&hFF,&h46,&h4A,&h7C,&hFF,&h49,&h4E,&h83,&hFF,&h4E,&h53,&h8B,&hFF,&h50,&h55,&h8F,&hFF, _
&h53,&h58,&h93,&hFF,&h55,&h5A,&h97,&hFF,&h57,&h5D,&h9B,&hFF,&h5C,&h61,&hA3,&hFF,&h5E,&h64,&hA7,&hFF,&h60,&h66,&hAB,&hFF,&h65,&h6B,&hB3,&hFF,&h67,&h6E,&hB7, _
&hFF,&h69,&h70,&hBB,&hFF,&h6E,&h75,&hC3,&hFF,&h70,&h77,&hC7,&hFF,&h72,&h7A,&hCB,&hFF,&h75,&h7C,&hCF,&hFF,&h77,&h7E,&hD3,&hFF,&h79,&h81,&hD7,&hFF,&h7E,&h86, _
&hDF,&hFF,&h80,&h88,&hE3,&hFF,&h82,&h8B,&hE7,&hFF,&h85,&h8D,&hEB,&hFF,&h87,&h8F,&hEF,&hFF,&h89,&h92,&hF3,&hFF,&h8B,&h94,&hF7,&hFF,&h8E,&h97,&hFB,&hFF,&h91, _
&h9A,&hFF,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0, _
&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0, _
&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0, _
&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF, _
&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&hFF,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&hD,&h21,&h6,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h17,&hC,&h1D,&h30,&h29,&h1E,&h4,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h27,&h38,&h10,&h0,&h0,&h0,&h0,&h0,&h0,&h5,&h38,&h2A,&h12,&h2F,&h38,&h38, _
&h32,&h12,&h0,&h0,&h0,&h0,&h0,&h0,&h28,&h38,&h15,&h0,&h0,&h0,&h0,&h0,&h0,&h5,&h38,&h36,&h0,&h0,&h1,&h15,&h33,&h37,&h14,&h0,&h0,&h0,&h0, _
&h0,&h23,&h38,&h17,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h32,&h38,&h5,&h0,&h0,&h0,&hA,&h34,&h37,&h3,&h0,&h0,&h0,&h0,&h1D,&h38,&h1F,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h28,&h38,&hC,&h0,&h0,&h0,&h0,&h27,&h38,&h12,&h0,&h0,&h0,&h0,&h16,&h38,&h38,&h35,&h2C,&h26,&h20,&h12,&h0,&h0,&h21,&h38,&h13, _
&h11,&h14,&h5,&h13,&h36,&h38,&h7,&h0,&h0,&h0,&h0,&hE,&h38,&h34,&h2A,&h32,&h38,&h38,&h37,&h4,&h0,&h1B,&h38,&h19,&h2D,&h38,&h38,&h38,&h37,&h1E,&h0, _
&h0,&h0,&h0,&h0,&h6,&h38,&h2E,&h0,&h0,&h3,&hC,&h7,&h0,&h0,&h12,&h38,&h21,&h2,&h1B,&h35,&h38,&h1A,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h34,&h37, _
&h2,&h0,&h0,&h0,&h0,&h0,&h0,&h9,&h38,&h28,&h0,&h0,&h8,&h2B,&h38,&h1A,&h0,&h0,&h0,&h0,&h0,&h0,&h2C,&h38,&hC,&h0,&h0,&h0,&h0,&h0,&h0, _
&h16,&h38,&h31,&h0,&h0,&h0,&h3,&h31,&h38,&h8,&h0,&h0,&h0,&h0,&h0,&h2A,&h38,&h2D,&h21,&h1C,&h17,&h17,&hF,&h4,&h35,&h38,&h38,&h22,&hE,&h8,&hA, _
&h2F,&h38,&h16,&h0,&h0,&h0,&h0,&h0,&h25,&h38,&h38,&h38,&h38,&h38,&h38,&h36,&h5,&hB,&h24,&h35,&h38,&h38,&h38,&h38,&h38,&h2E,&h5,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h5,&hC,&h10,&h17,&hB,&h0,&h0,&h0,&h0,&h6,&h10,&h18,&h1D,&hF,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0, _
&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0,&h0 }