Что такое Stream?

Тема в разделе "WASM.BEGINNERS", создана пользователем 2FED, 17 май 2009.

  1. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    В дельфи и С++ есть такой класс как IStream, как он реализован и что из себя представляет, как такое же сделать на ассемблере.

    Конкретно надо для того чтобы заюзать

    GdipLoadImageFromStream
    GdipSaveImageToStream
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    msdn уже не работает? http://msdn.microsoft.com/en-us/library/aa380034(VS.85).aspx
     
  3. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    я почти ничего не понял.

    Юзать как ком объект это слишком геморно, может есть у кого пример на асм.


    например можно ли просто выделить достаточный кусок с помошью VirtualAlloc и передать его в качастве Stream, и запишет ли туда функция данные или надо ещё что то делать, или нужна некая структура в которой будет указатель на эту память?
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    2FED
    Издеваешься? Юзать только как ком, ничего геморного не вижу.
     
  5. Partner

    Partner Павел

    Публикаций:
    0
    Регистрация:
    28 фев 2008
    Сообщения:
    917
    Адрес:
    Los Angeles
    Юзать как COM - это проще всего.
     
  6. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Возьми этот старый копипаст. Использовалось нами для чтения из ресурсов в не-продакшн-коде.
    Код (Text):
    1. #include <windows.h>
    2. #include <objidl.h>
    3.  
    4.  
    5. class ResStream: public IStream
    6. {
    7. protected:
    8.     size_t size;
    9.     const void* bgn;
    10.     const void* cur;
    11.  
    12. public:
    13.     ResStream()
    14.     {}
    15.  
    16.  
    17.     ResStream(HMODULE module, const wchar* resname, const wchar* restype)
    18.     {
    19.         HRSRC res = FindResource(module, resname, restype);
    20.         size = SizeofResource(module, res);
    21.  
    22.         bgn = LockResource(LoadResource(module, res));
    23.         cur = bgn;
    24.     }
    25.  
    26.  
    27.     virtual ULONG STDMETHODCALLTYPE
    28.     AddRef()
    29.     {
    30.         return 708;
    31.     }
    32.  
    33.  
    34.     virtual ULONG STDMETHODCALLTYPE
    35.     Release()
    36.     {
    37.         return 505;
    38.     }
    39.  
    40.  
    41.     virtual HRESULT STDMETHODCALLTYPE
    42.     QueryInterface(const IID& riid, void** ppvObject)
    43.     {
    44.         return E_FAIL;
    45.     }
    46.  
    47.    
    48.  
    49.     virtual HRESULT STDMETHODCALLTYPE
    50.     Read(void* pv, ULONG cb, ULONG* pcbRead)
    51.     {
    52.         if ((char*)bgn + size < (char*)cur + cb)
    53.             cb = (ULONG)(((char*)bgn + size) - (char*)cur);
    54.  
    55.         memcpy(pv, cur, cb);
    56.  
    57.         cur = (char*)cur + cb;
    58.  
    59.         if (pcbRead)
    60.             *pcbRead = cb;
    61.  
    62.         return S_OK;
    63.     }
    64.  
    65.  
    66.     virtual HRESULT STDMETHODCALLTYPE
    67.     Write(void const* pv, ULONG cb, ULONG* pcbWritten)
    68.     {
    69.         return STG_E_ACCESSDENIED;
    70.     }
    71.  
    72.  
    73.     virtual HRESULT STDMETHODCALLTYPE
    74.     Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
    75.     {
    76.         if (dwOrigin == STREAM_SEEK_SET)
    77.             cur = (char*)bgn + (uint64)dlibMove.QuadPart;
    78.         else if (dwOrigin == STREAM_SEEK_CUR)
    79.             cur = (char*)cur + dlibMove.QuadPart;
    80.         else if (dwOrigin == STREAM_SEEK_END)
    81.             cur = (char*)bgn + size - 1 - dlibMove.QuadPart;
    82.  
    83.         if (plibNewPosition)
    84.             *(&plibNewPosition->QuadPart) = (char*)cur - (char*)bgn;
    85.  
    86.         return S_OK;
    87.     }
    88.        
    89.  
    90.     virtual HRESULT STDMETHODCALLTYPE
    91.     Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag)
    92.     {
    93.         memset(pstatstg, 0, sizeof(STATSTG));
    94.         //pstatstg->type = STGTY_STREAM;
    95.         pstatstg->cbSize.QuadPart = (uint64)size;
    96.         //pstatstg->grfMode = STGM_READ;    // read grfMode is null
    97.         //pstatstg->clsid = CLSID_NULL;     // null CLSID_NULL is null
    98.  
    99.         return S_OK;
    100.     }
    101.  
    102.  
    103.     virtual HRESULT STDMETHODCALLTYPE
    104.     SetSize(ULARGE_INTEGER libNewSize)
    105.     {
    106.         return E_NOTIMPL;
    107.     }
    108.        
    109.     virtual HRESULT STDMETHODCALLTYPE
    110.     CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
    111.     {
    112.         return E_NOTIMPL;
    113.     }
    114.    
    115.     virtual HRESULT STDMETHODCALLTYPE
    116.     Commit(DWORD grfCommitFlags)
    117.     {
    118.         return E_NOTIMPL;
    119.     }
    120.        
    121.     virtual HRESULT STDMETHODCALLTYPE
    122.     Revert()
    123.     {
    124.         return E_NOTIMPL;
    125.     }
    126.    
    127.     virtual HRESULT STDMETHODCALLTYPE
    128.     LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
    129.     {
    130.         return E_NOTIMPL;
    131.     }
    132.  
    133.     virtual HRESULT STDMETHODCALLTYPE
    134.     UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
    135.     {
    136.         return E_NOTIMPL;
    137.     }
    138.    
    139.     virtual HRESULT STDMETHODCALLTYPE
    140.     Clone(__RPC__deref_out_opt IStream **ppstm)
    141.     {
    142.         return E_NOTIMPL;
    143.     }
    144. };
     
  7. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    Ладно как её через ком заюзать?

    в мсдн есть
    что передавать в CoCreateInstance в параметр REFCLSID rclsid, где взять гуид или как?

    и где взять её определение для coinvoke?

    е ещё блин говорите что через ком не гемор! ГЕМОР ЕЩЁ ТОТ!

    Вот жешь придумали какието Stream, нет чтоб сделать GdipLoadImageFromMemory.
     
  8. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ты бы хоть конкретизировал что тебе надо. Какой компиль, что хочешь в итоге получить?
     
  9. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    Компиль Masm, у меня есть битмап в памяти, мне нужно его загрузить(GdipLoadImageFromStream) обработать кодеком и поместить обратно в память(GdipSaveImageToStream).

    Но вот вся засада в этой IStream, как работать с функциями объекта я знаю, но не умею его создавать, как я понял объект создаётся при помощи CoCreateInstance, так вот какой гуид первым параметром передавать?
     
  10. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    IStream создаётся функцией CreateStreamOnHGlobal.
     
  11. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Создаёшь IStream. Пишешь целиком образ битмапа в него методом IStream::Write. Ставишь указатель потока на начало MoveStreamIStream::Seek. Передаёшь Gdip функциям. По-моему ничего геморного.
     
  12. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Чтобы овладевать IStream, нет необходимости вызывать какие-либо апи.
    Во-первых, что такое IStream? IStream — это интерфейс. Лайк, "соглашение". Лайк, "контракт". Чтобы реализовать этот интерфейс, нужно иметь базовые представления об объектах и виртуальных функциях — хотя бы потому, что стуктура, определяющая интерфейс, в памяти представлена именно как объект класса с виртуальными функциями.



    Код (Text):
    1. push 0
    2. push offset IStreamVtbl
    3. mov eax, esp
    На стеке создан объект класса, реализующего IStream. В данном случае у этого класса есть только один мембер (мы инициализировали его нулём) и указатель на таблицу виртуальных функций. В регистр eax мы поместили адрес этого объекта — именно адрес объекта нужно передавать в качестве параметра в функции, требующие указателя на IStream.


    Теперь насчёт IStreamVtbl. Говоря по-правде, это всего-навсего массив адресов функций. Адреса располагаются в строго определённом порядке — ты заключил контракт же. Все функции используют соглашение stdcall, а первым (скрытым) параметром получают адрес объекта — это тоже часть контракта. Чтобы узнать порядок функций, нужно посмотреть определение IStream (в <objidl.h>). Точнее, определения виртуальных функций у IStream и его предков (ISequentialStream и IUnknown).

    Код (Text):
    1. IStreamVtbl:
    2. dd offset IStream_QueryInterface  ; IUnknown
    3. dd offset IStream_AddRef
    4. dd offset IStream_Release
    5. dd offset IStream_Read             ; ISequentialStream
    6. dd offset IStream_Write
    7. dd offset IStream_Seek             ; IStream
    8. dd offset IStream_SetSize
    9. dd offset IStream_CopyTo
    10. dd offset IStream_Commit
    11. dd offset IStream_Revert
    12. dd offset IStream_LockRegion
    13. dd offset IStream_UnlockRegion
    14. dd offset IStream_Stat
    15. dd offset IStream_Clone
    Всё, что осталось — это реализовать все эти функции. Хотя, на самом деле, достаточно реализовать только те, которые будут использованы функциями, в которые ты передаёшь указатель на объект. Посмотри на наш предыдущий пост — мы реализовали только Read, Seek и (частично) Stat.
     
  13. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Sol_Ksacap
    Проще сделать своё чем готовое? В данном случае это не имеет смысла.
     
  14. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Это пусть 2FED решает. Мы, лайк, не навязываем что-либо сейчас.
    Но можно учесть, что реализация тривиальна, GlobalAlloc неэффективна, а код может быть реиспользован.
    Как бы то ни было — с тех пор как один пишет на ассемблере, низкоуровневые детали делают материю.
     
  15. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Да, вызов трёх функций сложнее огорода, на который ещё хрен знает сколько времени нужно потратить отлаживая. И с какого боку здесь GlobalAlloc пририсовался?
     
  16. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Booster
    Эта фраза просто кричит наружу:
       

    Теперь необходимо пройтись насчёт "готового" (CreateStreamOnHGlobal) и "вызова трёх функций".
    Пусть битмап находится в памяти. В этом случае при вызове CreateStreamOnHGlobal и IStream::Write в памяти будет создана копия уже имеющегося битмапа. Затем Gdip* функции будут вызывать IStream::Read, для того, чтобы прочитать битмап... в память. Что там было говорилось насчёт преумножения сущностей? (Нет, серьёзно — подобная реализация недалеко ушла от "if (boolValue.ToString.Length() < 5) {..}"). И нет, здесь не получится свалить вину на MS — вина в этом случае лежит на том, кто поленился потратить несколько минут своего времени и написать ~20 строчек тривиального кода.
    Своя реализация IStream ещё и тем хороша, что в том случае, когда битмап у нас изначально на диске, не будет необходимости выделять буфер, читать туда файл и триплировать память. Достаточно делать вызов ReadFile внутри IStream::Read (при этом будет прочитано столько байт, сколько реально необходимо — например, если заголовок файла повреждён, дальнейшее чтение производится не будет).
       
    Нет, мы не станем ожидать, что кто-нибудь, использующий, скажем, Визуальные Основы, пойдёт "сложным" путём (который сложен лишь на первый взгляд). Но предполагаем, что уж посетители этого форума смогут видеть всё это сквозь.
     
  17. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Sol_Ksacap
    Когда человек не уложиться в сроки разработки или когда произойдёт сбой по ошибке допущенной в своём огороде, тоже будет очень весело. Про оптимизацию конечно всё интересно, но это далеко не единственный и самый важный критерий выбора. Спасибо, что предложил свой вариант, но не надо его выпячивать как единственно лучшее решение.

    Это камень в мой огород? Если так, то могу сказать, что IStream до этого использовал, и вполне успешно.
    Вроде больше добавить нечего, кроме того, что только на васме можно увидеть диспут такого рода? ^)