1 (изменено: LEXYS, 2009-01-28 08:58:46)

Тема: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Поддержка скинов (Dll-метод + Файл конфигурации)

Вообщем здесь не будет сказано ничего сложного или важного. Просто захотел поделиться тем как я реализовал поддержку скинов в своем скрипте.

Для чего это нужно? Для того что в зависимости от системы взяв стандартные картинки и иконки мы пожем получить кучу ошибок при выполнении скрипта на других машинах. Но собрав все необходимые файлы в один dll можно за ЭТО уже непереживать! Плюс это эстетичнее смотрится, чем когда файлы разбросаны по подпапкам. Плюс можно собрать сколько угодно dll файлов с разными иконками и картинками реализовав тем самым систему скинов.

Для работы нам потребуются файлы .dll содержащие иконки и картинки участвующие в вашей программе.

Итак создаем файл menu.txt и прописываем в него начальный скин:

FileAppend, Resource=resource1.dll!, %A_ScriptDir%\menu.txt

Далее берем из него значение параметра Resource:

IfExist, %A_ScriptDir%\menu.txt ; Проверяем наличие menu.txt
FileRead, Contents, %A_ScriptDir%\menu.txt ; Читаем файл menu.txt
Loop, parse, Contents, `n ; Начинаем перебор строк
{
   ifInString, A_Loopfield, Resource ; Вводим параметр на котором перебор оканчивается т.е. Искомый параметр Resource
   {
       Resource:=SubStr(A_LoopField,InStr(A_LoopField,"=")+1)     ; Убираем из найденной строки знак "="
       Resource:=SubStr(Resource,1,InStr(Resource,"!")-1) ; Убираем из найденной строки знак "!"
} }

Все параметр мы взяли. Т.к. он находится в секции автовыполнения - он доступен теперь нам в любой части кода!
Использовать его мы будем как: %Resource%
Теперь то, как мы будем его использовать:

Пример:

Menu, Tray, Icon , %Resource%, 11

Здесь мы устанавливаем иконку для трея - берем 11ю иконку из нашего файла указанного в menu.txt параметром Resource

Для того чтобы сменить скин достаточно прописать в файле menu.txt вместо resource1.dll любую другую.

2

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

LEXYS пишет:

Плюс можно собрать сколько угодно dll файлов с разными иконками и картинками...

А можно с этого места по-подробнее?
Какие есть инструменты для изготовления подобных dll?

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

3

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Можно! Че ж нельзя то?!
Вот 2 утилитки должны лежать в 1й папке, все иконки и картинки распологаем в папке Resource

ROD-Ex.ahk

;  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   ;
;                                                                                        ;
;          Title        :  Script to Automate creation of Resource only DLL              ;

#SingleInstance, Force      
SetBatchLines, -1        
SetWorkingDir, %A_ScriptDir%

;----------------------------------------------------------------------------------------- 
; *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  CONFIGURATION SECTION
;-----------------------------------------------------------------------------------------

ResFolder     := A_WorkingDir . "\Resource"           ; The folder where resources reside
FileSizeLimit := ( 1024*1024*16 )                     ; 16 MB limit for a single resource
; The following target resource file will be placed/created in script's working folder

ResourceFile  := "AutoHotkeySC.bin"                   ;  you many comment out one of 
ResourceFile  := "Resource.dll"                       ;  these two lines

IxIcoN := 1000                                        ;  Ordinal Counter for RT_ICON
IxIcoG := 5000                                        ;  Ordinal Counter for RT_ICON_GROUP
IxBitM := 6000                                        ;  Ordinal Counter for RT_BITMAP
IxRDat := 9000                                        ;  Ordinal Counter for RT_RCDATA 

;-----------------------------------------------------------------------------------------
; *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
;-----------------------------------------------------------------------------------------


Loop, %ResFolder%\*.*,0,1                             ; Prepare a list of resource files
  {
      If ( InStr( FileExist( A_LoopFileFullPath), "H" ) )
         Continue 
      If A_LoopFileExt in EXE,DLL,CUR,ANI,ICL,BAK
         Continue

      FileGetSize, FileSize, %A_LoopFileLongPath%
      IfGreater, FileSize, %FileSizeLimit%, Continue
     
      ResFiles .= ( A_Index=1 ? "" : "`n" ) . SubStr( A_LoopFileExt "   ",1,3 )
               .  "|" A_LoopFileLongPath  
  }

IfEqual,ResFiles,, Return                           ; no files .. no joy!                              
Sort, ResFiles, D`n                                 ; Sort file list in alphabetical order  

If ( ResourceFile = "AutoHotkeySC.bin" )
  {
     SplitPath,A_AhkPath,,A_AhkDir
     FileCopy, %A_AhkDir%\Compiler\AutoHotkeySC.bin, %A_WorkingDir%\AutoHotkeySC.bin, 1
     MsgBox, % Errorlevel
     IfNotExist, %A_WorkingDir%\AutoHotkeySC.bin, SetEnv,ResourceFile,resource.dll
  }
IfNotEqual,ResourceFile,AutoHotkeySC.bin, SetEnv,ResourceFile, % CreateDLL("resource.dll") 

FileIO16_Init()  ; Requires  http://www.autohotkey.net/~Skan/wrapper/FileIO16/FileIO16.ahk

hUpdate := DllCall( "BeginUpdateResourceA", Str,ResourceFile, Int,0 )
Loop, Parse, ResFiles, `n
     {
        StringSplit, fPart, A_LoopField, |
        Ext := fPart1, SourceFile := fPart2
    
        If ( Ext = "ICO" )
             GoSub,RT_ICON
        Else  
        If ( Ext = "BMP" )
             GoSub,RT_BITMAP

        Else GoSub,RT_RCDATA
     }
DllCall( "EndUpdateResourceA", UInt,hUpdate, Int,0 )

; ----------------------------------------------------------------------------------------

Return ;                                           * *  end of auto-execute section * *
;_________________________________________________________________________________________
;   ----------------------------------------------------------------------------------- 



RT_BITMAP:
  FileGetSize, nSize, %SourceFile%
  cbData := FileReadEx( SourceFile, lpData, nSize-14, 14  )    ; skipping first 14 bytes
  DllCall( "UpdateResourceA", UInt,hUpdate
                            , UInt,2                           ; RT_BITMAP := 2           
                            , UInt,IxBitM
                            , UInt,0x0409                      ; LANG_NEUTRAL := 0
                            , UInt,&lpData, UInt,cbData )
  IxBitM += 1
Return                                       ; Increment the Ordinal counter for RT_BITMAP



RT_RCDATA:
  FileGetSize, nSize, %SourceFile%
  cbData := FileReadEx( SourceFile, lpData, nSize, 0 )   

  DllCall( "UpdateResourceA", UInt,hUpdate
                            , UInt,10                          ; RT_RCDATA := 10
                            , UInt,IxRDat
                            , UInt,0x0409                      ; LANG_NEUTRAL := 0
                            , UInt,&lpData, UInt,cbData )

  IxRDat += 1                                ; Increment the Ordinal counter for RT_RCDATA
Return



RT_ICON:
  hFile := FOpen( SourceFile, F_READ )                     ; Open ICO file
  FRead( hFile, IconHdr, 6 )                               ; Read header. First 6 bytes
  IconCount := NumGet( IconHdr,4, "UShort" )               ; Extract Icon Count for Header
  
  ; Create empty ICONGROUPDATA structure to hold RT_GROUP_ICON data 
  ; Header requires 6 bytes + GRPICONDIRENTRY is 14 bytes for each Icon
  VarSetCapacity( IconGroupData, ( ICGS := 6+(IconCount*14 ) ) )
  
  MemCopy( &IconHdr, &IconGroupData, 6 ) ; Copy header into ICONGROUPDATA structure 
  pICGD := &IconGroupData + 6            ; Increment the pointer to ICONGROUPDATA


  /*

  GRPICONDIRENTRY in a resource is much similar to ICONDIRENTRY of .ICO except:
    - GRPICONDIRENTRY is 14 bytes long the last two bytes contain RT_ICON ordinal
    - ICONDIRENTRY is 16 bytes long and last four bytes would contain file offset to data

  Therefore to add a .ICO as ICON resource:
    - Read .ICO and translate ICONDIRENTRY into GRPICONDIRENTRY
    - Read and Update each ICONIMAGE as a seperate RT_ICON Ordinal
    - Update ICONGROUPDATA ( Header + array of GRPICONDIRENTRY ) as a single RT_GROUP_ICON
     
  */     
  

  Loop %IconCount% 
   {
     FRead( hFile,ICGD,16 )              ; Read ICONDIRENTRY of .ICO into ICGD
     IDS := NumGet( ICGD,08 )            ; Get IconData Size from ICONDIRENTRY 
     IDO := NumGet( ICGD,12 )            ; Get IconData Offset from ICONDIRENTRY
     NumPut( IxIcoN,ICGD,12 )            ; Put RT_ICON ordinal into ICONDIRENTRY
     MemCopy( &ICGD, pICGD, 14 )         ; Copy ICONDIRENTRY into ICONGROUPDATA
     pICGD += 14                         ; Increment the pointer to ICONGROUPDATA
     
     CPF := FSeek( hFile, 0, F_CPF )     ; save the current position of file pointer 
     FSeek( hFile, IDO, F_BOF )          ; Seek IconData offset from beginning of file
     FRead( hFile, ICD, IDS )            ; Read ICONIMAGE into ICD 
     FSeek( hFile, CPF, F_BOF )          ; move the file pointer to the previous position

     ; The following adds ICONIMAGE as RT_ICON in resource
     DllCall( "UpdateResourceA", UInt,hUpdate
                               , UInt,3                        ; RT_ICON := 3           
                               , UInt,IxIcoN
                               , UInt,0x0409                   ; LANG_NEUTRAL := 0
                               , UInt,&ICD, UInt,IDS )
     IxIcoN += 1                         ; Increment the Ordinal counter for RT_ICON
   }  

  FClose( hFile )                        ; Close the .ICO file
  
  ; The following adds GRPICONDIRENTRY as RT_GROUP_ICON in resource
  DllCall( "UpdateResourceA", UInt,hUpdate
                            , UInt,14                          ; RT_GROUP_ICON := 14           
                            , UInt,IxIcoG 
                            , UInt,0x0409                      ; LANG_NEUTRAL := 0
                            , UInt,&IconGroupData, UInt,ICGS )
                               
  IxIcoG += 1                          ; Increment the Ordinal counter for RT_GROUP_ICON
Return

;  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

CreateDLL( file="empty.dll" ) {                       ; Creates an empty DLL sized @ 2.5K

hex := "4D5A9X3U4VFFFFXB8N4KLMFF8BX8TE1FBA0EZB409CD21B8014CCD214175746F486F746B6579205363" 
. "72697074696E67204C616E67756167652C205265736F757263652D6F6E6C7920444C4C2E245045X4C0103L" 
. "REXE210B0103W2U2N2U2U1Q1Y1T2W4U1U4L4T4O2Y3V1W1S1LY1JLS3VCIKV2E64617461U4T1T2U4LP4WC02E" 
. "74657874V11T2T2U6LP2W602E72656C6F63WCT3T2U8LP4W4JL02E737263T2D01V4T2UALP4Z8Y6GGGHI8B44" 
. "2408A3Z1Y10B801VC20CGHIJKZ2VCU53GHIJKND0A" 
VarSetCapacity(Z,512,48),   Nums:="512|256|128|64|32|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2" 
Loop, Parse, Nums, |                                  ;  Uncompressing nulls in hex data 
  StringReplace,hex,hex,% Chr(70+A_Index),% SubStr(Z,1,A_LoopField),All 
; MCode() by Laszlo Hars : http://www.autohotkey.com/forum/viewtopic.php?p=135302#135302
VarSetCapacity( Bin,(cLen:=StrLen(hex)//2)), h:=DllCall("_lcreat",str,file,int,0) 
Loop %cLen% 
  NumPut("0x" SubStr(hex,2*a_index-1,2),Bin,a_index-1,"char") 
b:=DllCall("_lwrite",uint,h,str,Bin,uint,cLen),DllCall("_lclose",uint,h), Bin:="", hex:="" 
Return b ? file : "" 
}
;  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#Include FileIO16.ahk ;      http://www.autohotkey.net/~Skan/wrapper/FileIO16/FileIO16.ahk

FileIO16.ahk

FileIO16_Init() {
  Global F_READ:=0,F_READWRITE:=2,F_WRITE:=1,F_SHARE_COMPAT:=0,F_SHARE_DENY_NONE:=0x40
       , F_SHARE_DENY_READ :=0x30,F_SHARE_DENY_WRITE:=0x20,F_SHARE_EXCLUSIVE:=0x10
       , F_BOF:=0,F_CPF:=1,F_EOF:=2
       , F_NORMAL:=0, F_READONLY:=1,F_HIDDEN:=2,F_SYSTEM:=4
}


FClose( hfil  ) {
  Return DllCall( "_lclose", UInt,hFil )
}

FCreate( sFile, nAttr ) {
  Return DllCall( "_lcreat", Str,sFile, UInt,nAttr )
}

FOpen( sFile, nAttr ) {
  Return DllCall( "_lopen", Str,sFile, UInt,nAttr )
}

FRead( hFil, byref var, nSize ) {
 Return (VarSetCapacity(var,nSize)+n) DllCall( "_lread", UInt,hFil, Str,var, UInt,nSize )
}

FSeek( hfil, nSize, nOrigin ) {
  Return DllCall( "_llseek", UInt,hFil, UInt,nSize, UInt,nOrigin )
}                             

FWrite( hFil, nPtr, nSize ) {
  Return DllCall( "_lwrite", UInt,hFil, UInt,nPtr, UInt,nSize )
}



FileReadEx( F,ByRef V,B,O=0 )  {   
 by:= (B<0 ? ABS(B-1) : B), VarSetCapacity(V,By,0), H:=DllCall("_lopen",Str,F,UInt,0)
 IfLess,H,1, Return,-1
 DllCall( "_llseek",UInt,H,UInt,( B < 0 ? B : O), UInt,(B < 0 ? 2 : 0) )
 Return DllCall("_lread",UInt,H,Str,V,UInt,by) ( DllCall("_lclose",UInt,H)+n )      
}

FileWriteEx( F,ByRef V,B,O=0 ) {  
 H:=(FileExist(F)="") ? DllCall("_lcreat",Str,F,UInt,0) : DllCall("_lopen",Str,F,UInt,1) 
 IfLess,H,1, Return, -1
 DllCall("_llseek",UInt,H,UInt,( O < 0 ? O+1 : O ), UInt,(O < 0 ? 2 : 0) )
 Return DllCall("_lwrite",UInt,H,Str,V,UInt,B) ( DllCall("_lclose",UInt,H)+n ) 
} 

MemCopy( SPtr, TPtr, nSize ) {
 Return DllCall( "RtlMoveMemory", UInt,TPtr, UInt,SPtr, UInt,nSize )
}

Собрали рексурсы в папке Resource ? Все запускаем ROD-Ex.ahk и радуемся созданной resource.dll !

4 (изменено: LEXYS, 2009-01-28 13:00:20)

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Ресурсы которые можно использовать:
ICON
BITMAP
RCD

мой пример использования: http://forum.oszone.net/thread-127660.html

5

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Попробовал — не получается.
Положил в каталог Resource два bmp-файла (107 Кб и 1 Кб). Файл resource.dll в результате собирается, но использовать его нельзя. Ярлыки Windows говорят, что файл не содержит иконок, а команда:

Menu, Tray, Icon, Resource.dll, 1

говорит "Can't load icon".

P.S. Про это не забыл?

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

6

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Выкладываю на обменник: вместе с примером!
http://webfile.ru/placed?id=2592146

Главное понимать что размер иконки в трее 16х16, стандартный размер иконки 32х32, 48х48, 64х64!
Я пы таюсь в своем деле добиться минимальных размеров, поэтому в иконках оставляю только нужный размер!
Смотри пример!

7

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

The gray Cardinal
А у меня получилось, я положил туда ico-файлы, а не bmp.

8

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Спасибо, теперь получилось.
ROD-45L.ahk в архиве зачем?
Иконки в архиве будет нагляднее пронумеровать с единицы, имхо (и последняя будет одиннадцатой).

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

9

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Я использую эти иконки по другому. Перебором.
Поэтому чтобы они правильно заняли свое место в длл  они должны начинаться с 0!

ROD-45L.ahk - случайно попал.

"Can't load icon". - может отображаться если используется иконка которая в данном случае использоваться не может!

10

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

LEXYS
Ты в Коллекцию будешь постить или мне самому? А то я тебе два раза уже "намекал", а ты чего-то отмалчиваешься .

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

11

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Да тут-то все расписано и готово к применению, перенеси да и все в коллекцию.
А тот пример нужно расписывать досканально! Щас пока времени нету Экзамен сдам!
Кстати у меня завтра День рождения!

12

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

LEXYS, с днём рождения!!! Пожалуйста, покажи пример, когда из этой DLL загружается BMP в окно GUI?

13

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

LEXYS, а нельзя туда *.ini вкладывать? (в библиотеку), а то очень даже удобно было бы!!! (видел это в shell32.dll)

Ещё вопрос не в тему (возможно для этого следует новую тему создать, но это позже):
Где можно найти инфу по возможностям библиотек винды? Как то: BeginUpdateResourceA, UpdateResourceA....
Это я взял из функции DLLCALL, примера, описанного выше.

14

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

LEXYS, а нельзя туда *.ini вкладывать? (в библиотеку),

А смысл? ini предназначен для хранения изменяемой информации. Вряд ли кого-то обрадует перезапись сделанных настроек. Лучше создавать ini-файл и работать с ним непосредственно, с помощью IniWrite, IniRead, IniDelete.

15

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Приведите пример добавления картинки в формате BMP в окно GUI из resource.dll.
Как загрузить эту самую .BMP?

16

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Куда загрузить, в dll, или в окно? И в каком размере, первоначальном, или изменённом?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Выше описанным способом мне удалось добавить файлы .ico в resource.dll. Затем я смог вот так загрузить иконку.

Menu, Tray, Icon, Resource.dll, 1

С изображением не получается. Добавил файлы .bmp в resource.dll. Как теперь их использовать?
Как сделать тоже самое, но загрузить изображение не из директории скрипта, а из resource.dll, созданной выше описанным способом?

Gui, add, picture, x0 y0, Image.bmp

18

Re: AHK: Поддержка скинов (Dll-метод + Файл конфигурации)

Можно так:

DllFileName = resource.dll    ; указать путь к dll c ресурсами
Index = 6000   ; первый bmp-файл — 6000, второй — 6001 и т. д.
W = 0
H = 0   ; размеры, если ноли — как есть

hModule := DllCall("LoadLibrary", Str, DllFileName)
hBitmap := DllCall("LoadImage", UInt, hModule
                              , UInt, Index
                              , UInt, IMAGE_BITMAP := 0
                              , Int, W, Int, H  
                              , Uint, LR_SHARED := 0x8000)
DllCall("FreeLibrary", UInt, hModule)

Gui, Add, Pic, x0 y0 hwndhPic +0xE   ; SS_BITMAP = 0xE
SendMessage, STM_SETIMAGE:=0x172, IMAGE_BITMAP:=0, hBitmap,, ahk_id %hPic%
ControlGetPos,,, W, H,, ahk_id %hPic%
Gui, Show, w%W% h%H%
DllCall("DeleteObject", UInt, hBitmap)
Return

GuiClose:
   ExitApp

Тема на форуме: http://www.autohotkey.com/forum/viewtopic.php?t=30228

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder