Ресурсы в .Net

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Недавно начал изучать платформу don't Net и сталкнулся с проблемой загрузки строки из ресурсов приложения. Если в Win32API это делается с помощью функции LoadString(), то в CLR-классах я так и не нашёл аналогичного метода. Попробовал через ResourceManager, но у меня ничего не получилось, непонятно какие параметры ему требуются для инициализации. Как быть?
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Понимаю тебя, Decoder. Когда-то сам столкнулся с подобной задачей.
Суть в том, что нативные ресурсы обычных Win32-приложений в программах на don't Net практически не используются. Там хранятся лишь иконки и информация о версии файла, которые в "Проводнике" отображаются, да и их тоже в новых версиях Windows потом перестанут использовать. Вместо этого там используются ресурсы другого типа. У тебя в проекте должен быть файл с расширением .resx, в котором и содержится текст с описанием ресурсов в виде данных XML. Потом этот файл компилируется в бинарный модуль с расширением .resources, который и встраивается в исполняемый модуль приложения.
Я вместо класса ResourceManager использовал ResourceSet, а доступ к модулю исполняемого приложения получил через Reflection.Assembly...
В файле ресурсов должна быть строковая таблица хотя бы с одной строкой, обозначенная к примеру как "String1".
Вот как это выглядит в коде на C++/CLI

Код: Выделить всё

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
	Reflection::Assembly^ ass = // kiss my ass...
		Reflection::Assembly::GetExecutingAssembly();
	IO::Stream^ stream = 
		ass->GetManifestResourceStream(ass->GetManifestResourceNames()[0]);
	Resources::ResourceSet^ rset = gcnew Resources::ResourceSet(stream);
	Console::WriteLine(rset->GetString(L"String1"));
	Console::Read();
	//
    return 0;
}
В результате на экране должен появиться текст строки String1 из ресурсов.
Но дело ещё в том, что в приложении может быть несколько ресурсных файлов, тогда вместо ass->GetManifestResourceNames()[0] нужно будет указать конкретный ресурсный нэйм-спэйс, в котором содержится вызываемая строка.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо, WinMain.
Я тут сам немного потренировался с ресурсами. Написал небольшую программку, которая выводит на экран имена ресурсных частей, входящих в исполняемый модуль...

Код: Выделить всё

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
	Reflection::Assembly^ ass = // kiss my ass...
		Reflection::Assembly::GetExecutingAssembly();
	for each (String^ str in ass->GetManifestResourceNames())
	{
		Console::WriteLine(str);
	}
	Console::Read();
	//
    return 0;
}
Получается что имя ресурснй части совпадает с именем бинарного ресурсного файла, который встраивается в модуль приложения.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Хочется ещё спросить на эту тему: можно ли использовать бинарные ресурсы .NET в обычных приложениях Win32 без поддержки CLR?
Например: строковые таблицы, как внешний ресурс.
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

В принципе можно. Даже в ряде случаев это было бы более правильным решением, чем создавать отдельную DLL, содержащую некий набор внешних ресурсов.
Например: если создавать приложения с многоязычным пользовательским интерфейсом. Все текстовые строки вынести в отдельный файл и обращаться к нему в момент загрузки программы. При выборе другого языка, программа будет обращаться уже к другому ресурсному файлу.
Файл с XML-ресурсами .NET (расширение resx) можно включить и в обычный проект Win32 Application. При этом ресурсы данного файла можно будет редактировать всё тем же редактором Visual Studio, как если бы он использовался в проекте на C#. Мало того, этот файл .resx будет компилироваться вместе с другими файлами проекта, только потом полученный бинарный файл не будет встраиваться внутрь приложения (если конечно принудительно не включить его в состав ресурсов).
Сложность в том, что в составе Win32API нет специальных функций для работы с такими ресурсами (на самом деле функции имеются, но они работают через ядро .NET FrameWork). Поэтому нужно будет самому написать (или найти готовую) процедуру чтения данных из бинарных ресурсов .NET
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Интересно было бы найти готовую функцию. Но я не нашёл даже описания формата файла с расширением .resources, который получается после компиляции resx файла. Жаль, что хорошая идея может так и остаться всего лишь идеей.
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Ну а сам что... не можешь с бинарником разобраться? Неужели так сложно?

А вот и спецификация по формату этого файла...
http://msdn.microsoft.com/en-us/library ... 10%29.aspx
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Подход "разберись сам" плох по одной причине. Со временем формат бинарника может поменяться. В этом случае нам придётся менять и наш код. В то время, как если бы мы использовали стандартную функцию (имплементация которой была обязана поменяться вместе со сменой формата), то наш код бы остался без изменений и даже не потребовал рекомпиляции. Именно поэтому поиск стандартной функции куда более правилен, чем самостоятельный разбор бинаря.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Кто бы спорил. Ну а что делать, если необходимый SDK не реализован на Win32API? Приходится таким вот образом выкручиваться.
С другой стороны, если использовать этот файл только внутри собственного приложения, то изменения его формата дадут о себе знать лишь при смене среды разработки, например: переход на Visual Studio 2010 и .NET FrameWork 4.0
У меня была схожая ситуация, когда мне нужно было ресурс окна диалога читать напрямую из бинарника. Я только тогда заметил, что бинарный формат диалогов в ресурсах VC++ 6.0 и VC++ 2005 заметно отличается.
Пока используешь функции Win32API, эти изменения остаются незаметными и на работе программы никак не сказываются.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо, WinMain.
Я по твоей рекомендации написал процедуру чтения строковой таблицы из бинарного ресурса .Net
Данная процедура правильно работает только с теми бинарниками, в которых содержатся лишь строковые таблицы и никаких других ресурсов. В дальнейшем можно будет дописать эту процедуру для чтения других ресурсов и сделать её универсальной.
Вложения
ReadResx.zip
(8.23 КБ) 29 скачиваний
Поумнеть несложно, куда труднее от дури избавиться.
Ответить