Показаны сообщения с ярлыком portable. Показать все сообщения
Показаны сообщения с ярлыком portable. Показать все сообщения

понедельник, 27 октября 2008 г.

Про создание COM-объектов без регистрации DLL в системе

Как известно, чтобы создать некий COM-объект, надо прежде всего зарегистрировать DLL в которой этот объект реализован. И делается это примерно так

regsvr32.exe SomeCOMObjects.dll

Дальше можно вызывать CoCreateInstance, получать экземпляр объекта и работать с ним.

Однако, иногда возникает желание, пользовать объекты не регистрируя библиотеку, например, когда хочется получить portable версию программы. Один способ я описывал вот здесь. Но к сожалению на Vista этот вариант у меня не прошел или я просто не слишком активно пытался.

Второй вариант создавать объект, загружая соответствующую длл-ку при помощи функции LoadLibrary. Выглядит это следующим образом:

показать код

class CCOMDll
{
typedef HRESULT (__stdcall *DllGetClassObjectProc)(REFCLSID rclsid, REFIID riid, LPVOID * ppvObj);
public :
CCOMDll()
: m_sDLLFilePath(_T(""))
, m_hLib(NULL)
, m_pDllGetClassObjectProc(NULL)
, m_pDllCanUnloadNowProc(NULL)
{
}
virtual ~CCOMDll()
{
if (NULL!=m_hLib)
::FreeLibrary(m_hLib);
}
BOOL LoadLibrary(const CString &sDLLFilePath)
{
m_sDLLFilePath = sDLLFilePath;
m_hLib = ::LoadLibrary(m_sDLLFilePath);

m_pDllGetClassObjectProc = (DllGetClassObjectProc)::GetProcAddress(m_hLib, "DllGetClassObject");
return (NULL!=m_hLib);
}
BOOL IsValid() const
{
return (NULL!=m_hLib);
}
//
HRESULT CoCreateInstance(REFCLSID rclsid, REFIID riid, LPVOID* ppvObj)
{
*ppvObj = NULL;
if (NULL==m_pDllGetClassObjectProc)
return S_FALSE;

IClassFactory *pFactory = NULL;
HRESULT hr = (m_pDllGetClassObjectProc)(rclsid, IID_IClassFactory, (void**)&pFactory);
if (S_OK!=hr)
return hr;

hr = pFactory->CreateInstance(NULL, riid, ppvObj);
if (NULL!=pFactory)
pFactory->Release();
return hr;
}
protected :
CString m_sDLLFilePath;
HINSTANCE m_hLib;

DllGetClassObjectProc m_pDllGetClassObjectProc;
};



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

воскресенье, 1 июня 2008 г.

Про регистрацию COM объектов при помощи манифестов

Одна из проблем возникающая при попытке сделать "portable" версию некоторой программы, это использование основным exe-файлом COM-объектов.

COM-объекты обычно реализуются в виде dll-файлов, которые регистрируются в системе примерно так:

regsvr32.exe SomeCOMObjects.dll

На самом деле вся регистрация сводится к прописыванию в реестре ключей со списком GUID-ов и ссылками на путь к SomeCOMObjects.dll.

Понятно, что теперь, чтобы программа заработала на компьютере отличном от того, где она установлена, не достаточно утащить туда только exe-файл. В рамках нашей задачи создания portable версии программы, которую можно будет носить на внешнем винчестере или Flash Drive, неплохим вариантом решения будет следующие действия:

1. На внешнем носителе создаем папку для программы и копируем туда, непосредственно exe-файл и все используемые им dll-файлы с COM-объектами.

2. Создаем два bat-файла (или, например, два vbs-файла): COMDllRegister.bat и COMDllUnregister.bat в первом для каждой dll прописываем

regsvr32.exe SomeCOMObjects.dll

во втором

regsvr32.exe /u SomeCOMObjects.dll

Приходя на новый компьютер, запускаем вначале COMDllRegister.bat, потом саму программу, работаем, а перед уходом запускаем COMDllUnregister.bat. Если кроме COM-объектов никаких других привязок в системе у программы нет, то все работает замечательно.

Какие минусы у данного способа?

Минусы очевидны. Если в системе уже были зарегистрированы COM-объекты используемые программой, с которой Вы работаете (известно, что COM это в том числе и способ разделения кода и многие программы используют одни и те же COM-объекты, например, DirectX это исключительно набор COM-компонентов). То при запуске первого bat-файла Вы перенаправите пути с Dll-файлов, расположенных на компьютере, на Dll-файлы на вашем внешнем диске, а после запуска второго, эти COM-объекты из системы исчезнут, что может отрицательно сказаться на работоспособности программ на этом компьютере.

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

Но есть способ лучше. Он подробно, с примерами, расписан в статье Registration-Free Activation of COM Components: A Walkthrough.

Суть этого способа сводится к тому, чтобы вместо регистрации COM-объектов в реестре системы, использовать manifest-файлы. Таким образом, в том числе можно использовать в программе вместо dll-зарегистрированной в системе свою.

Итак, что надо сделать.

1. Для каждой dll, содержащей COM-объекты надо создать manifest-файл. Можно это сделать вручную (предварительно придется зарегистрировать dll, а затем воспользоваться утилитой OLE/COM Object viewer), можно воспользоваться утилитой mt.exe из Visual Studio 2005. В результате должен получится набор manifest-файлов примерно такого содержания


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="STDUCore.X" version="1.0.0.0"/>
<file name="STDUCore.dll">
<comClass
clsid="{2BB2E135-4B81-4840-B7CD-A744DD236AB0}"
threadingModel = "Apartment"/>
<comClass
clsid="{1740E2A8-ACF7-4930-B6DF-5D0C85E874DA}"
threadingModel = "Apartment"/>
<typelib tlbid="{A11D2AA5-3D39-448E-B9D0-177A73707C98}" version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="ISTDUImage"
iid="{3905360D-3C87-498C-93D2-27E002B941B1}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid="{A11D2AA5-3D39-448E-B9D0-177A73707C98}"/>
<comInterfaceExternalProxyStub
name="ISTDUTransform"
iid="{721B21ED-7BCD-4127-9EFF-6C06AA95FE31}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid="{A11D2AA5-3D39-448E-B9D0-177A73707C98}"/>
</assembly>



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


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type = "win32" name = "client" version = "1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="STDUCore.X" version="1.0.0.0" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="STDUDjVuFile.X" version="1.0.0.0" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="STDUPDFFile.X" version="1.0.0.0" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="STDUTiffFile.X" version="1.0.0.0" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="STDUViewer.X" version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>


STDUCore.X, STDUViewer.X и т.п. это имена файлов manifest для соответствующих dll.

3. Теперь собираем все dll-файлы, основную программу, и manifest-файлы в одну директорию - "portable" версия программы готова.

Выше в качестве примера используются куски manifest-файлов для "portable" версии STDU Viewer



Какие минусы у данного способа?

Во-первых, не всегда возможно определить, какие COM-объекты из каких dll-файлов использует конкретная программа. Во-вторых, мне так и не удалось заставить работать этот способ под Windows Vista, что скорее всего это связано с UAC (но нельзя сказать, что я сильно старался). И, наконец, создание manifest-файлов в ручном режиме, для серьезной программы, мягко говоря, работа не простая, и не шибко веселая.

четверг, 29 мая 2008 г.

Про "portable" программы

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

Итак. Вспоминаем славные времена, когда деревья были большими (хотя тенденция к их уменьшению уже прослеживалась), винчестеры маленькими, а про всякого рода USB Flash Drive и прочие полезности никто еще не знал. В то время происходил переход прогрессивной части народонаселения с MS-DOS на Windows 95 (с промежуточной остановкой в районе 3.11). Те кто может объяснить, что нарисовано на копке Save в большинстве программ, так же наверняка вспомнит, как обстояли дела с установкой программ под MS-DOS. В большинстве случаев дела обстояли крайне просто. Папка с программой просто копировалась с одного компьютера на другой, а иногда и копировать ничего было не надо, запускали прямо с дискеты.

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

Однако, время не стоит на месте, и все возвращается к тому откуда началось. Возвращение это проявляется в двух вариантах, во-первых, с развитием интернет, некоторые из приложений переродились в интернет варианте, неплохой набор таких сервисов есть, например, у google. Во-вторых, как я понял не так давно (до меня вообще все доходит крайне медленно), многие жаждут иметь "portable" версию программы. Ибо даже на флешку объемом 8 ГБ, можно положить практически полный набор программ, которыми пользуешься в повседневной жизни. Что позволяет быть очень даже мобильным, без всякого ноутбука весом пару килограмм. Я уже не говорю, о каком-нибудь внешнем винчестере размером 1.8'. А на подходе еще и SSD девайсы.

Это как обычно была преамбула, и лирическое отступление на предмет пофилософствовать.

Теперь некоторые размышления на тему.

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

А вот тема "portable" программ вполне себе ничего. И имеется минимум два варианта почему оно нравится. Первый, это именно мобильность, т.е. ходить с винчестером и на любом компьютере иметь, весь набор нужных приложений (причем настроенных так как надо), крайне приятная перспектива. Второй, удобство возникающие при перестановке системы, ибо на данный момент, после того как на компьютер взгромоздился WindowsXP, а для всего железа, которое имеет место быть в этом самом компьютере, установлены драйвера (этот этап сам по себе навевает уныние). Начинается установка всего нужного софта. Процесс может затянуться часов на 6-7, и нажатие кнопки Next, выбор директорий и перезагрузка повергает лично меня в полное уныние. А завершается все это настройкой софта под себя (там фонт поменять, здесь панель инструментов вытащить).

Вообщем наличие "portable" версии на мой взгляд сугубо плюс, для любой программы.

Минусы правда тоже имеют место быть. Например, на данный момент нет никакой возможности Word таскаемый на флешке, привязать на открытие doc файлов на компьютере в который эта флешка вставлена. Для случая когда "portable" софт нужен только, чтобы не переустанавливать его каждый раз при переустановки системы, эта проблема решается одним reg файлом. Но этот случай вообще достаточно тривиален, и поддается хорошей автоматизации.

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