1 (изменено: Xameleon, 2017-02-11 12:18:15)

Тема: WSC: Script Component для чтения ресурсов из файлов через res протокол

Решил эту затею в отдельную тему вынести. Вдруг кому пригодится. А если повезёт, то может кто и допилит дальше.

Пересобрал код в виде WSC resReader.wsc.
Компонент содержит методы:

Open - открытие ресурса (всего лишь принимает имя файла)
GetStrings - чтение строковой таблицы по ID
GetString - чтение строки по ID
GetIcon - чтение содержимого иконки
GetBitmap - чтение содержимого рисунка

Пример работы с компонентом:


/* Restart in CScript */
if(WScript.FullName.match(/CScript/gi) == null){
	new ActiveXObject("WScript.Shell").Run("cscript \"" + WScript.ScriptFullName + "\"")
	WScript.Quit();
}

var StdOut = WScript.StdOut
var StdIn = WScript.StdIn

with (GetObject("script:file:resReader.wsc")){
	/* Opening file */
	Open("shell32.dll")

	StdOut.WriteLine("1) Loading STRINGTABLE 337 from from \"shell32.dll\"\r\n")
	
	/* Reading STRINGTABLE resource */
	var Strings = GetStrings(337)
	StdOut.WriteLine("String table 337 contains " + Strings.Count + " strings\r\n")

	/* Building STRINGTABLE visualisation */
	var arr = [], item
	for(var i=0;i < Strings.Count;i++){
		item = Strings.Item(i)
		arr.push(item.id + ", \"" + String(item).replace(/\"/g,"\\\"") + "\"")
	}
	StdOut.WriteLine("{\r\n" + arr.join("\r\n") + "\r\n}\r\n")

	StdOut.WriteLine("2) Input id resource for checking")

	/* Сheck the existence of the resource */
	var id = StdIn.ReadLine()
	if(Strings.Exists(id)){
		StdOut.WriteLine("Resource \"" + id + "\" found in string table\r\n")
		StdOut.WriteLine("It's value is \"" + Strings.ItemByID(id) + "\"\r\n")
	} else {
		StdOut.WriteLine("Resource \"" + id + "\" not found in string table\r\n")
	}
	
	/* Loading icon resource */
	StdOut.WriteLine("3) Loading ICON resource 203... \r\n")
	with(new ActiveXObject("ADODB.Stream")){
		Type = 1;
		Open();
		Write(GetIcon(203));
		SaveToFile("testImage.png", 2);
	}

	StdOut.WriteLine("Press ENTER key to show the image...")

	StdIn.ReadLine();
	
	new ActiveXObject("WScript.Shell").Run("testImage.png");
}
Post's attachments

resReader.wsc 3.39 kb, 17 downloads since 2017-02-10 

You don't have the permssions to download the attachments of this post.
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

2

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Xameleon, вновь твои идеи будоражат мое сознание.
Я и раньше пробовал извлекать ресурсы с помощью протокола res:\\ но скудность документации и собственных знаний оборвали этот процесс.
К сожалению, приведенный пример не отвечает на оказавшиеся для меня тупиковыми вопросы. Может быть совместными усилиями сможем найти на них ответ?

  1. Существующие просмотрщики ресурсов (тот же ResEdit, например) показывают совсем иной перечень ресурсов (диалоги, иконки, битмапы) нежели то, что извлекается с помощью протокола res:\\. Xameleon, а ты как вычислил эти цифири 337, 203 ? Методом "научного тыка"?

  2. Есть ли какой либо способ с помощью res:\\ получить перечень ресурсов?

  3. Самое востребованное действие - получить дефолтовую иконку файла. Я вот так и не смог этого сделать - пришлось прибегать к WinAPI.

3

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers
А в чём суть научного тыка? Открываем ru-RU\shell32.dll.mui в PEViewer. На вкладке Ресурсы смотрим в String и находим нужное в 337. Так?

4

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

2Flasher
Спасибо за подсказку (я то искал в c:\windows\system32\shell32.dll).
В c:\WINDOWS\System32\ru-RU\shell32.dll.mui действительно 337 String имеется. Правда с помощью ResEdit его найти затруднительно. Зато в PE Explorer и ResHacker его действительно можно найти в блоке String.
Хорошо, а тогда 203 где искать?

5

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers
В shell32.dll. ICLView номера показывает.
Не про PE Explorer пишу, а про то, к чему руки ближе, - плагины ТС.

Хотя у меня какой-то сломанный png создаётся. Определяется как cel.

Post's attachments

testImage.png
testImage.png 3.66 kb, 5 downloads since 2017-02-11 

You don't have the permssions to download the attachments of this post.

6

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Данное изображение (комп с глобусом) видят все редакторы ресурсов. Но все они показывают это изображение (самое большое - 255х255) как одно из 8 входящих в набор одной из встроенных икон.
Иконка эта числится под номером 18 (ResHacker) 0016 (ICLView). Все просмотрщики позволяют сохранить это как файл ico содержащих все 8 иконок.
Запрос res://C:\windows\system32\shell32.dll/#3/#203 извлекает это изображение как файл png!
Это что же, получается что содержимое и местоположение реального ресурса и может быть совсем не связано ни с содержанием запроса res:// ни с его результатом???
Наверное, это все таки неверно и есть какое то четкое соответствие...

7

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Flasher, твой testImage.png какой то изуродованный. Предлагаю использовать скриптик попроще:

url = "res://C:\windows\system32\shell32.dll/#3/#203"

With CreateObject("MSXML2.XMLHTTP")
	.Open "GET", url, False
	.Send
	data = .responseBody
End With

With CreateObject("SAPI.spFileStream")
	.Open "out.png", 2
	.Write data
	.Close
End With

8

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

То же самое.

9 (изменено: Xameleon, 2017-02-11 19:11:11)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers

вновь твои идеи будоражат мое сознание smile

Приветствую. Рад, что пригодилось. ) Если примите участие в "допиливании", буду ещё больше рад !

+ открыть спойлер

Рядом ещё тема с форматированием даты, времени и чисел используя "двигло" msxml . Как говорится - welcome.

но скудность документации и собственных знаний оборвали этот процесс.

Не поверите, я как раз от туда и подчерпнул всю информацию. )))
Именно ссылки с этой страницы привели меня к необходимой информации:
1) типы ресурсов
2) Описание формата STRINGTABLE

По поводу расположения ресурсов в mui файлах, я так понимаю Flasher, вас уже проинформировал. Мы как раз обсуждали этот момент тут:

Данное изображение (комп с глобусом) видят все редакторы ресурсов. Но все они показывают это изображение (самое большое - 255х255) как одно из 8 входящих в набор одной из встроенных икон.
Иконка эта числится под номером 18 (ResHacker) 0016 (ICLView). Все просмотрщики позволяют сохранить это как файл ico содержащих все 8 иконок.
Запрос res://C:\windows\system32\shell32.dll/#3/#203 извлекает это изображение как файл png!

Несколько раз перечитал Ваше последнее сообщение, но не смог понять, почему такой вывод:

Это что же, получается что содержимое и местоположение реального ресурса и может быть совсем не связано ни с содержанием запроса res:// ни с его результатом???
Наверное, это все таки неверно и есть какое то четкое соответствие...

Наборы иконок идут группой. От самой большой к самой маленькой: 203 - 210
203 - 256x254
204 - 64x64
205 - 48x48
206 - 40x40
207 - 32x32
208 - 24x24
209 - 20x20
210 - 16x16

Вроде всё логично ?

P.S Наваял интерактивный скрипт. Ностальгия по паскалю... ))

Post's attachments

interactive.zip 2.52 kb, 4 downloads since 2017-02-11 

You don't have the permssions to download the attachments of this post.
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

10

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

2Xameleon
Да не "катит" такая логика.
Во-первых - почему именно 203? Почему иконка вдруг сохраняется как PNG?
Во вторых, res://C:\windows\system32\shell32.dll/#3/#204 должно извлечь 2ю иконку, однако извлекается какой то мусор (как у Flasherа)?
Да, и, пожалуйста, не называйте меня в множественном числе (я еще маленький).

11 (изменено: Xameleon, 2017-02-11 23:10:20)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, теперь понял о чём речь. Выгрузил через Resource Hacker этот же ресурс. Наблюдаю такое же странное содержимое. Хм. Буду разбираться. ) Видимо это тоже специальным образом форматированные данные, как и STRINGTABLE.

почему именно 203

Честно говоря, в этом случае, взял первый попавшийся. А иконки меньшего размера в голову не пришло проверить.

Да, и, пожалуйста, не называйте меня в множественном числе (я еще маленький).

Пардоньте, я не против, но форум обязывает. ) Да и к тому же я сам не так уж стар. ))

UPD

Провёл исследование. Выгрузил из Resource Hacker ресурс как ".bin", и как ".ico". Сравнил содержимое. У ico файла присутствует заголовок, а у bin он отсутствует. В остальном тела файлов совпадают.

UPD 2

По ходу формат заголовка такой:
http://www.codeguru.com/cpp/w-p/win32/t … ources.htm

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

12

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Я тоже провел собственное исследование.
С номером - все нормально (соответсвует PE Explorer). Видимо ResHacker как то иначе нумерует.
Крупные иконы (255х255) хранятся в формате png, поэтому их так легко извлечь. Их даже обычный html показывает.

<HTML>
<BODY>
<IMG src="res://shell32.dll/3/1">
</BODY>
</HTML>

Такие же иконы, но помельче, хранятся в виде набора ico. Протокол res:// извлекает их скопом, так, что не понимает ни один вьюер.
Чтобы их увидеть, надо эти данные обработать. Алгоритм заморочанный донельзя. Реализовать на vbs/js, боюсь, не получится. А если и получится, то тормоза будут - дикие.

13 (изменено: Xameleon, 2017-02-12 02:07:07)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, ну не будем опускать руки. ) Пока что я понял, что Icon Group содержит всю информацию об иконках в разделе Icons. Задача выяснить - можно ли в обратную сторону - зная идентификатор иконки, узнать какой группе она принадлежит.

Вот код, на котором я пока что отлаживаюсь. Это получение информации о нашем злосчастном ресурсе ICON 203. Информация о нём хранится в ICON GROUP 18.

Один из источников инфы:https://msdn.microsoft.com/en-us/library/ms997538.aspx


Dim oReader
Dim oStream
Dim i
Dim sTmp

Set oReader = CreateObject("MSXML2.XMLHTTP")
oReader.Open "?","res://shell32.dll/14/18"
oReader.Send

Dim imgCount, nImg

print("Reserved: " & GetBytes(2))
print("Type: " & GetBytes(2))
imgCount = GetBytes(2)
print("ImageCount:" & imgCount)

For nImg = 1 to ImgCount
	print("Width: " & GetBytes(1))
	print("Height: " & GetBytes(1))
	print("Colors: " & GetBytes(1))
	print("Reserved: " & GetBytes(1))
	print("Planes: " & GetBytes(2))
	print("BitsPerPixel: " & GetBytes(2))
	print("ImageSize: " & GetBytes(4))
	print("ImageOffset: " & GetBytes(2))
	print("-----------------------------")
Next

MsgBox sTmp

Function print(text)
	sTmp = sTmp & text & vbCrlf
End Function

Function GetBytes(n)
	GetBytes = AscB(MidB(oReader.ResponseBody,i+1,n))
	i = i + n
End Function
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

14

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Исправлю своё ложное утверждение:

Протокол res:// извлекает их скопом

Если использовать в res:// запросе RT_ICON(3), то по указанному номеру извлекается конкретная иконка в формате ico, но вот только без 22 байтного заголовка.
Т.е. сейчас задача-минимум состоит в том чтобы добавить эти 22 байта, используя инфу, извлеченную из RT_GROUP_ICON(14) (см. пример by Xameleon выше).

15

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, именно так ! ) Но я пока всё-таки ищу способ связи от идентификатора иконки к группе, которой она принадлежит. ) Заголовок то сделать, вроде не проблема.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

16

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Разрази меня гром, чтобы там не писали разные умники, мои многочисленные эксперименты показывают что все 22 байтные заголовки любых ico-шек различаются только 15 и 16 байтом!
Xameleon, имхо связывать надо от группы к иконке, а наоборот получится только тупым перебором всех групп подряд с поиском нужной.

17 (изменено: Xameleon, 2017-02-13 10:54:07)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers,
1) О ! Интересно. ) Я еще не сравнивал.
2)

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

Согласен. Тоже думал об этом. Но интересно - как же тогда работает API FindResource. ПМСМ, сомневаюсь, что тупым перебором.

UPD
Ещё немного подумал... В принципе можно сделать функцию LoadImage(id,type)
И набор констант типа:

Const PNG = 0
Const ICON64 = 1
...

И на основании их подсовывать заголовок. Но как-то.... не аккуратненько )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

18 (изменено: mozers, 2017-02-13 14:07:19)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

В общем, если внимательно (а не так, как я вчера) прочитать документацию, то окажется что умники - абсолютно правы.
Сначала по запросу типа res://shell32.dll/3/46 считываем данные.
Если вначале данных присутствует строка "PNG", то просто сохраняем данные как файл png.
Иначе вставляем в начало константу - hex-строку "0000010001002020200000000000" (т.к. Винда и все вьюеры - умные и игнорируют неверные данные о размере и цвете иконки которые задаются в этом блоке).
Затем надо вставить 4байтовую строку, указывающую размер считанных нами данных (вставить тут ерунду не получится - этот параметр проверяется строго). Получится что то типа "88090000".
Теперь - опять константа "16000000" указывающая на смещение данных.
Ну а теперь - сами данные.
Теперь все это в склеенном виде можно сохранить как файл ico.
Таким образом, для просмотра единичных иконок нет никакой необходимости извлекать какую то дополнительную инфу.

19 (изменено: Xameleon, 2017-02-13 16:36:33)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, не понял. Поля заголовка должны же содержать шрину, высоту, цветность и т.п. параметры иконки. O_o Как при этом заголовок может быть общей константой для разных иконок ?

UPD
Пардон, перечитал. Увидел. Ну на мой взгляд некорректно так поступать. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

20 (изменено: mozers, 2017-02-13 23:13:12)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Xameleon
Ну, например, PE Explorer при сохранении из ресурсов одинарных ico-нок поступает именно так "некорректно".
В первом грубом приближении получается как то так - IconExtractor.vbs:

On Error Resume Next

file = "c:\Windows\SYSTEM32\shell32.dll"
' file = "c:\Program Files (x86)\Skype\Phone\Skype.exe"

inum = 0
Do
	inum = inum + 1
	With CreateObject("MSXML2.XMLHTTP")
		.Open "GET", "res://" & file & "/#3/#" & inum, False
		.Send
		idata = .responseBody
	End With
	ilen = LenB(idata)
	If ilen = 0 Then WScript.Quit

	With CreateObject("SAPI.spFileStream")
		If AscB(idata) = &H89 Then ' ----- Save as PNG
			.Open inum & ".png", 2
			.Write idata
			.Close
		Else ' ---------- Save as ICO
			.Open inum & ".ico", 2
			.Write CInt(0) 'reserved
			.Write CInt(1) 'type
			.Write CInt(1) 'count

			.Write CByte(32) 'width
			.Write CByte(32) 'height
			.Write CByte(32) 'colors
			.Write CByte(0) 'reserved
			.Write CInt(0) 'planes
			.Write CInt(0) 'bpp
			.Write CLng(ilen) 'size
			.Write CLng(22) ' offset
			.Write idata
			.Close
		End If
	End With
Loop

21

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, запустил, получил несколько дёрганий курсора, но иконки выгрузились успешно ! ) Клёво ! Завтра изучу подробнее код. ) Сэр, крайне благодарен вам за активное участие ! Начинаю чувствовать, что не одинок в своих экспериментах.

+ открыть спойлер

https://68.media.tumblr.com/dc2acffbea837dc5277bb1b469aafbb7/tumblr_n7u8czdwFI1qzs5cqo1_500.gif

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

22

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Главная неприятность - то что номера иконок идут не подряд. В случае с shell32.dll скрипт обрывается на 64, поскольку следующий номер - 70. Вот как бы узнать все эти номера... Или придумать функцию, получающую следующий доступный номер...
Можно узнать номера иконок входящих в одну группу (из RT_GROUP_ICON), но с остальными - тоже самое, т.к. номера групп тоже не подряд идут.

23 (изменено: Xameleon, 2017-02-14 13:07:06)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, ага. ) Именно так. Более того, идентификаторы иконок и групп могут быть строковыми. Например в файле explorer.exe есть группа "ICO_MYCOMPUTER". Видимо есть 2 пути:
1) Разбирать весь PE заголовок через ADODB.Stream / SAPI.spFileStream и находить все эти данные внутри и тогда вообще можно отказаться от res протокола. )))

2) Забить на поиск и реализовать по принципу, как я описывал тут.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

24 (изменено: Xameleon, 2017-02-15 15:23:06)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Ещё одна интересная альтернативка.


Const adSaveCreateOverWrite = 2
With CreateObject("CDO.Message").AddAttachment("res://shell32.dll/3/1")
	MsgBox .ContentMediaType
	.GetDecodedContentStream.SaveToFile "1.png", adSaveCreateOverWrite
End With
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

25

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Xameleon
Выдаёт text/html и сохраняет пустой png.

26 (изменено: Xameleon, 2017-02-15 15:33:11)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Flasher, видимо на Win 7 эта картинка в ресурсах не существует. У меня на Win 10 выдаёт:

image/x-png

и сохраняет картинку успешно.

UPD

Выяснил. Взял Вашу shell32.dll, натравил на неё скрипт и получил такой же (неудачный) результат. Оказалось внутри ICON 1 лежит тело иконки без заголовка 32x32, а не PNG, как на Win 10. Файл создаётся, в него пишется тело этой ущербной иконки. Поэтому он и не открывается.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

27

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Xameleon, интересный метод. Надо его поизучать на досуге как альтернативу ADODB.Stream / SAPI.spFileStream.
О наших баранах:
Вариант побитового парсинга уже реализован. Недостатки - налицо: чрезвычайно замудрено и медленно. Поскольку все параметры заданы жестко, а правила достаточно гибки - много иконок тупо не находит.
Вся прелесть предложенного тобой метода - в протоколе res:// , позволяющем запросто извлекать любые заданные ресурсы. Увы, видимо, придется смирится с его ограничениями:
- неспособностью извлекать ресурсы из неномерных секций;
- отсутствием возможности получить список доступных номеров.
Хотя, может быть, найдется новый гений и предложит решение хотя бы одной из этих проблем.

Flasher, как уже сказал Xameleon в res://shell32.dll/3/1 (Win7) никакой png-шки просто нет (там - обычная иконка без заголовка). Проще всего проверять на hta-шке

<HTML><BODY><IMG src="res://shell32.dll/3/1"></BODY></HTML>

Пусто? Тогда меняем во всех примерах res://shell32.dll/3/1 на res://c:\Program Files (x86)\Skype\Phone\Skype.exe/3/5 - там точно png-шка имеется.

28 (изменено: Xameleon, 2017-02-16 13:45:26)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers,

неспособностью извлекать ресурсы из неномерных секций;

Почему ? Ни кто не запрещает именованные извлекать через res.

Не уверен, что на семёрке есть эта иконка, взял первую попавшуюся из ieframe.dll на 10-ке.


<img src="res://ieframe.dll/2/CONTROL_HOT_120.BMP">

Вариант побитового парсинга уже реализован

Изучаю ! ) КРАЙНЕ ПОЛЕЗНЫЙ материал. ) Взял на заметку. Благодарю !

UPD

Поизучал код. ) Автор, как и я, подумал, что заголовок можно цеплять к иконке на основании размера её содержимого в байтах. Но я откинул эту идею, как кривое решение, а автор всё-таки реализовал.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

29

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Xameleon

Ни кто не запрещает именованные извлекать через res.

Действительно так! А я, сделав лишь одну неудачную попытку, тут же поверил документации

// This is not correct.
"res://mydll.dll/#2/MYBITMAP"

Ну тогда осталась лишь одна реальная проблема - найти способ извлекать список имен ресурсов.

30

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers

Ну тогда осталась лишь одна реальная проблема - найти способ извлекать список имен ресурсов.

Так в том то и дело, что и это Вы уже сделали, поделившись ссылкой.
Там уже всё это реализовано. ) Если причесать код, то должно получиться вполне удачное решение.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

31

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Option Explicit

SaveSingleIcon "shell32.dll", "162"
SaveWholeIcon "g:\Total Commander\TOTALCMD.EXE", "MAINICON"

Sub SaveSingleIcon(resFile, iconID)
	Dim iconData, iconSize, iconHeader
	iconData = GetIconData(resFile, "3", iconID) ' Icon Entry
	If IsEmpty(iconData) Then
		WScript.Echo "res://" & resFile & "/3/" & iconID & " not found!" : Exit Sub
	End If
	With CreateObject("SAPI.spFileStream")
		If AscB(iconData) = &H89 Then ' ----- Save as PNG
			.Open iconID & ".png", 2
			.Write iconData
		Else ' ---------- Save as ICO
			.Open iconID & ".ico", 2
			' Общий заголовок (6 байт)
			.Write CInt(0) 'reserved
			.Write CInt(1) 'type
			.Write CInt(1) 'count

			' Заголовок иконки (16 байт)
			iconSize = CLng(LenB(iconData))
			Select Case iconSize
				Case 67624 : iconHeader = Array(CByte(128), CByte(128), CInt(32))
				Case 38056 : iconHeader = Array(CByte(96), CByte(96), CInt(32))
				Case 16936 : iconHeader = Array(CByte(64), CByte(64), CInt(32))
				Case 9640  : iconHeader = Array(CByte(48), CByte(48), CInt(32))
				Case 6760  : iconHeader = Array(CByte(40), CByte(40), CInt(32))
				Case 4264  : iconHeader = Array(CByte(32), CByte(32), CInt(32))
				Case 2440  : iconHeader = Array(CByte(24), CByte(24), CInt(32))
				Case 1720  : iconHeader = Array(CByte(20), CByte(20), CInt(32))
				Case 1128  : iconHeader = Array(CByte(16), CByte(16), CInt(32))
				Case 2216  : iconHeader = Array(CByte(32), CByte(32), CInt(8))
				Case 1384  : iconHeader = Array(CByte(16), CByte(16), CInt(8))
				Case 1736  : iconHeader = Array(CByte(24), CByte(24), CInt(8))
				Case 296   : iconHeader = Array(CByte(16), CByte(16), CInt(4))
				Case 744   : iconHeader = Array(CByte(32), CByte(32), CInt(4))
				Case 488   : iconHeader = Array(CByte(24), CByte(24), CInt(4))
				Case Else  : iconHeader = Array(CByte(32), CByte(32), CInt(0))
			End Select
			.Write CByte(32) 'width
			.Write CByte(32) 'height
			.Write CByte(32) 'colors
			.Write CByte(0) 'reserved
			.Write CInt(0) 'planes
			.Write CInt(0) 'bpp
			.Write iconSize 'size
			.Write CLng(6 + 16) ' offset
			' Содержимое иконки
			.Write iconData
		End If
		.Close
	End With
End Sub

Sub SaveWholeIcon(resFile, groupID)
	Dim groupData, imgCount, offset, pos, nImg, imgSize, arrResOffset

	groupData = GetIconData(resFile, "14", groupID) ' Group Icon
	If IsEmpty(groupData) Then
		WScript.Echo "res://" & resFile & "/14/" & groupID & " not found!" : Exit Sub
	End If
	With CreateObject("SAPI.spFileStream")
		.Open groupID & ".ico", 2

		' Общий заголовок группы иконок (6 байт)
		.Write CInt(GetValue(groupData, pos, 2)) 'reserved
		.Write CInt(GetValue(groupData, pos, 2)) 'type
		imgCount = GetValue(groupData, pos, 2)
		.Write CInt(imgCount) 'count

		' Заголовки иконок (по 16 байт каждая)
		Set arrResOffset = CreateObject("Scripting.Dictionary")
		offset = 6 + 16 * imgCount
		For nImg = 1 To imgCount
			.Write CByte(GetValue(groupData, pos, 1)) 'width
			.Write CByte(GetValue(groupData, pos, 1)) 'height
			.Write CByte(GetValue(groupData, pos, 1)) 'colors
			.Write CByte(GetValue(groupData, pos, 1)) 'reserved
			.Write CInt(GetValue(groupData, pos, 2)) 'planes
			.Write CInt(GetValue(groupData, pos, 2)) 'bpp
			imgSize = CLng(GetValue(groupData, pos, 4))
			.Write imgSize 'size
			arrResOffset.Add arrResOffset.Count, GetValue(groupData, pos, 2) ' offset
			.Write CLng(offset) ' offset
			offset = offset + imgSize
		Next

		' Содержимое иконок
		For nImg = 0 To arrResOffset.Count - 1
			.Write GetIconData(resFile, "3", arrResOffset.Item(nImg)) ' Icon Entry
		Next
		.Close
	End With
End Sub

' Возвращает 1/2/4 байтное число и новое смещение
Function GetValue(data, start, length)
	Dim val, s
	For s = 0 To length - 1
		val = val + AscB(MidB(data, start + s + 1, 1)) * 256 ^ s
	Next
	GetValue = val
	start = start + length
End Function

Function GetIconData(resFile, resType, resID)
	With CreateObject("MSXML2.XMLHTTP")
		.Open "GET", "res://" & resFile & "/" & resType & "/" & resID, False
		On Error Resume Next
		.Send
		GetIconData = .responseBody
	End With
End Function

Xameleon, похоже это - финальный вариант (за неделю не изменил ни строчки - так и выложил). Если есть желание - можешь включить в свой WSC:Script Component.

32

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

mozers, О ! Отлично ! ) А я пока что никак не успевал заняться. Как освобожусь от рабочих дел - изучу. Спасибо ! )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

33

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Интересно, почему при подстановке %COMMANDER_EXE% вместо g:\Total Commander\TOTALCMD.EXE иконка сохраняется, но возникает неопознаная ошибка на строке с .Open "GET", "res://"?

mozers пишет:

Пусто? Тогда меняем во всех примерах res://shell32.dll/3/1 на res://c:\Program Files (x86)\Skype\Phone\Skype.exe/3/5 - там точно png-шка имеется.

А перед этим не забыть сменить систему на x64 и установить скайп.

34 (изменено: Xameleon, 2017-03-01 23:13:50)

Re: WSC: Script Component для чтения ресурсов из файлов через res протокол

Flasher, мда. Скайп не панацея. )

mozers, решил ещё подробнее поковырять "тело иконок". И тут заметил - в заголовке тела иконки имеем:

typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG  biWidth;
  LONG  biHeight;
  WORD  biPlanes;
  WORD  biBitCount;
  DWORD biCompression;
  DWORD biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

А раз так, то этого вполне достаточно для составления заголовка иконки. Вот и переделал Ваш код слегка. Благодаря вашей заготовке разобрался с offset. Внёс следующие изменения:
1) Вместо XMLHTTP использовал CDO.Message
2) Переделал чтение группы иконок. Решил, что собирать весь заголовок по байтам накладно, поэтому сделал его блочное чтение из ресурсов, что подсократило код и количество вызовов "Write"
3) Для отдельных иконок стал собирать информацию из BITMAPINFOHEADER, который содержится в теле ресурса иконки


Option Explicit
Dim oResReader
Set oResReader = new cResReader
oResReader.Open "shell32.dll"

On Error Resume Next
With oResReader
	SaveToFile .ReadIcon("1"), "ICON1.png"
	SaveToFile .ReadIcon("2"), "ICON2.ico"
	SaveToFile .ReadIcon("3"), "ICON3.ico"
	SaveToFile .ReadIcon("4"), "ICON4.ico"
	SaveToFile .ReadIcon("5"), "ICON5.ico"
	SaveToFile .ReadIcon("6"), "ICON6.ico"
	SaveToFile .ReadIcon("7"), "ICON7.ico"
	SaveToFile .ReadIcon("8"), "ICON8.ico"
	SaveToFile .ReadIconGroup("62998"), "FULL_ICON.ico"
End With

MsgBox "DONE !",vbInformation

Sub SaveToFile(data, fileName)
	With CreateObject("ADODB.Stream")
		.Type = 1
		.Open
		.Write data
		.SaveToFile fileName, 2
	End With
End Sub

Class cResReader
	Dim FileName, Source
	Private Sub Class_Initialize()
		'Saving class name for using as source with err.raise
		Source = TypeName(Me)
	End Sub
		
	'Sub for selecting file for parsing
	Sub Open(Path)
		FileName = Path
	End Sub
	
	'Function for loading single icon
	Function ReadIcon(Id)
		Dim Stream, Buffer, ColorCount, BitCount
		'3 - RT_ICON
		Set Stream = ReadRes(3,Id)
		'Reading 5 field of BITMAPINFOHEADER [DWORD biSize; LONG biWIdth; LONG  biHeight; WORD  biPlanes; WORD  biBitCount]
		Buffer = Stream.Read(16)
		'Rewinding Stream for second use
		Stream.Position = 0
		'Checking for PNG prefix
		If InStrB(1,Buffer,ChrB(&H89) & ChrB(&H50) & ChrB(&H4E) & ChrB(&H47)) Then
			ReadIcon = Stream.Read
		Else
			'Calculating color Count
			BitCount = ToNum(MidB(Buffer,15,2))
			ColorCount = 2 ^ BitCount: if ColorCount > 32 Then ColorCount = 0
			'Building icon data
			With CreateObject("SAPI.spMemoryStream")
				.Write CInt(0)								'idReserved 	(must be 0)
				.Write CInt(1)								'idType			(must be 1)
				.Write CInt(1)								'idCount		(1 icon)
				.Write CByte(ToNum(MidB(Buffer,5,4)))		'bWIdth			(biWIdth)
				.Write CByte(ToNum(MidB(Buffer,9,4)))		'bHeight		(biHeight)
				.Write CByte(ColorCount)					'bColorCount	(2 ^ biBitCount [8,16,32] if more than 0)
				.Write CByte(0)								'bReserved		(always 0)
				.Write CInt(ToNum(MidB(Buffer,13,2)))		'wPlanes		(biPlanes)
				.Write CInt(BitCount)						'wBitCount		(biBitCount)
				.Write CLng(Stream.Size)					'dwBytesInRes	(stream.Size)
				.Write Clng(22)								'dwImageOffset
				.Write Stream.Read							
				ReadIcon = .GetData
			End With
		End if
	End Function
	
	'Function for loading icon group
	Function ReadIconGroup(GroupId)
		Dim Buffer, Count, Id, Offset, Size, Stream, i
		'Reading resource data (14 - RT_ICON_GROUP)
		Set Stream = ReadRes(14,GroupId)
		'Reading GRPICONDIR struct
		Buffer = Stream.Read(6)
		'Checking fields idReserved (must be 0) and IdType (1 for icons)
		If ToNum(MidB(Buffer,1,2)) <> 0 Then Err.Raise vbObjectError + 1, Source, "Invalid value in reserved field"
		If ToNum(MidB(Buffer,3,2)) <> 1 Then Err.Raise vbObjectError + 2, Source, "Invalid resource type"
		'Reading icons count
		Count = ToNum(MidB(Buffer,5,2))
		'Prepairing array for icon id-s (for future loading it's data)
		Redim Ids(Count-1)
		'Creating stream for data
		With CreateObject("SAPI.spMemoryStream")
			'Calculating first offset [GRPICONDIR size + GRPICONDIRENTRY size * icons Count]
			Offset = 6 + 16 * Count
			'Writing header to stream
			.Write Buffer
			For i=0 to Count-1
				'Reading Icon fields [bWidth, bHeight, bColors, bReserved, wPlanes, BitCount, dwBytesInRes] except [nId]
				Buffer = Stream.Read(12)
				'Writing ICON header block to stream
				.Write Buffer
				'Reading DWORD dwBytesInRes
				Size = Clng(ToNum(RightB(Buffer,4)))
				'Reading Icon Id for future reading icon data
				Ids(i) = ToNum(Stream.Read(2))
				'Writing DWORD dwImageOffset
				.Write CLng(Offset)
				'Calculating next Offset
				Offset = Offset + Size
			Next
			'Reading icon "bodies" from resource and writing to stream 
			For Each Id in Ids
				.Write ReadRes(3,Id).Read
			Next
			ReadIconGroup = .GetData
		End With
	End Function
	
	'Function for loading data from url
	Private Function ReadRes(ResType,Id)
		Set ReadRes = CreateObject("CDO.Message") _
		.AddAttachment("res://" & FileName & "/" & ResType & "/" & Id) _
		.GetDecodedContentStream
		'Enabling binary mode
		ReadRes.Type = 1
	End Function
	
	'Function for converting bytes to number
	Private Function ToNum(b)
		Dim i: For i = 1 To LenB(b)
			ToNum = ToNum Or AscB(MidB(b, i, 1)) * &H100 ^ (i - 1)
		Next
	End Function
End Class
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !