Re: Сделал! в избранное  msdn  новое всё   Оценить +1123x:) +-   подписка   модер. 
От: avs99 
Дата: 23.03.06 04:24
Оценка:3 (1)
Ну что ж, позвольте отчитаться о проделанной работе

Вкратце — да, таки получилось объект поднимать в другой сессии. Но с БОЛЬШИМ "но".

Теперь что делал.

1. Взял DLL-синглтон из статьи HOWTO: Глобальный COM-синглтон в DLL
Автор(ы): Егор Синькевич, Сергей Холодилов
Дата: 16.02.2005
Статья описывает реализацию синглтона, физически размещаемого в DLL, но уникального в пределах компьютера. Данная реализация позволяет создавать подобные синглтоны в своих проектах изменением одной­единственной строки кода.

.

2. Немного его поменял, что бы он выдавал CurrentProcessID() для облегчения контроля

3. В фабрике классов заменил CoGet/RegisterClassOBject на вызовы маршалинга/размаршалинга.

4. В клиенте (кстати, только сейчас я задумался, а зачем я так делал?? --- ааа, что бы DLL вообще не загружать в свой процесс, если уже где-то есть одна) пробуем размаршалить интерфейс фабрики классов, и если получается, то вызываем CreateInstance прям от него (и тут же другая мысля — а это, вообще-то, хорошо в "идейном" плане?).


    CComPtr<ITestObj> pTestObj = NULL;
    LONG pID;    

    CComPtr<IClassFactory> spCF;

    if (SUCCEEDED(CInMemoryMarshalling::UnMarshalInterface(IID_IClassFactory, (void**)&spCF)))
        hr = spCF->CreateInstance(NULL, IID_ITestObj, (void**)&pTestObj);

    if (pTestObj == NULL && FAILED(hr = pTestObj.CoCreateInstance(CLSID_TestObj)))
    {
        _tprintf(_T("Failed to create TestObj. hr = 0x%x"), hr);
        return;
        //goto clean;
    }





Возникшие и решенные проблемы.

1. Маршалинг. Обычный, в файл через ShellCreateStreamOnFile (или как-то так) работает прекрасно, но некрасиво в файл писать. Пробовал делать в Memory-Mapped — не срабатывал CreateStreamOnHGlobal после MapViewOfFile — потому что то, что возвращает MapViewOfFile != тому, что возвращает GlobalAlloc. Тоже с этим намучался изрядно. В итоге — сначала создаем CreateStreamOnHGlobal, маршалим туда интерфейс при помощи CoMarshalInterface, а вот затем создаем Memory-Mapped файл через CreateFileMapping, открываем его в своем процессе при помощи MapViewOfFile и затем в эту память пишем содержимое IStream:


         hr = pStream->Read( (char*)pMappedFile + sizeof(DWORD), dwStreamSize, dwBytesWritten);



Не забываем закрыть отображение файла через UnmapViewOfFile. Про таинственный sizeof(DWORD) см. ниже.

2. Размаршаливание интерфейса. Делается примерно также, открывается файл через OpenFileMapping -> MapViewOfFile, создается стрим через CreateStreamOnHGlobal и в него записывается содержимое этого файл.

    hr = pStream->Write((char*)pMappedFile + sizeof(DWORD), dwFileSize, &dwBytesWritten);
    hr = pStream->Commit(STGC_DEFAULT);



Тут проблема была с определение размера этого самого файл в памяти. GetFileSize(), естественно не работает. В итоге я его просто записываю первым словом в начало самого файла (тот самый sizeof(DWORD) ).

3. Но это еще цветочки... Когда это все заработало в одной сессии, я попробовал через сессию это делать. Фиг вам. Для этого надо сбросить настройки безопастности:


    HRESULT hr;    
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    // This provides a NULL DACL which will allow access to everyone.
    CSecurityDescriptor sd;
    sd.InitializeFromProcessToken();
    hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);




Вот здесь, честно сказать, я потерялся. Я не понимаю, что и зачем я делаю. С этим работает, без — нет. Почему именно так, какие конкретно права надо дать (полностью же сбрасывать это совсем неправильно) — вот здесь нужен комментарий специалиста.

После этого работает и между сессиями.

4. Ну и на сладенькое. Во-первых, спасибо Владимиру за совет, он указал, что фабрике классов синглтона мьютекс надо делать глобальным (Global\\MutexName), соответственно, тоже самое надо и для memory-mapped файла. А также для них надо передавать не дефолтный SECURITY_DESCRIPTOR, а со сброшенным DACL-ом, иначе фиг кто этот самый мьютекс откроет из другой сессии.


А теперь внимание, вопрос


Это все работает для процесса DllSingletonClient в примере. Мне же, в моем проекте, приходится подгружать DLL в произвольный процесс. Я реализовал это при помощи другой статьи с любимого сайта HOWTO: Вызов функции в другом процессе
Автор(ы): Сергей Холодилов
Дата: 13.02.2005
В статье описывается один из методов внедрения DLL. Разбираются способы взаимодействия с внедренной библиотекой.
. Вот в произвольном случае это и не работает. Например, банальный notepad.exe не поддерживает эту фишку. А вот explorer.exe — запросто (( Какие-нибудь идеи по этому поводу? Вообще, рыть-то куда?


Вот такие вот пироги


Ну и персональная благодарность Тому и Владимиру за подкинутые идеи!

Спасибо, мужики, вы меня очень здорово выручили!


Алексей


ЗЫ код всего выложу вечером или в выходные.