В дельфи и С++ есть такой класс как IStream, как он реализован и что из себя представляет, как такое же сделать на ассемблере. Конкретно надо для того чтобы заюзать GdipLoadImageFromStream GdipSaveImageToStream
я почти ничего не понял. Юзать как ком объект это слишком геморно, может есть у кого пример на асм. например можно ли просто выделить достаточный кусок с помошью VirtualAlloc и передать его в качастве Stream, и запишет ли туда функция данные или надо ещё что то делать, или нужна некая структура в которой будет указатель на эту память?
Возьми этот старый копипаст. Использовалось нами для чтения из ресурсов в не-продакшн-коде. Код (Text): #include <windows.h> #include <objidl.h> class ResStream: public IStream { protected: size_t size; const void* bgn; const void* cur; public: ResStream() {} ResStream(HMODULE module, const wchar* resname, const wchar* restype) { HRSRC res = FindResource(module, resname, restype); size = SizeofResource(module, res); bgn = LockResource(LoadResource(module, res)); cur = bgn; } virtual ULONG STDMETHODCALLTYPE AddRef() { return 708; } virtual ULONG STDMETHODCALLTYPE Release() { return 505; } virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObject) { return E_FAIL; } virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) { if ((char*)bgn + size < (char*)cur + cb) cb = (ULONG)(((char*)bgn + size) - (char*)cur); memcpy(pv, cur, cb); cur = (char*)cur + cb; if (pcbRead) *pcbRead = cb; return S_OK; } virtual HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) { return STG_E_ACCESSDENIED; } virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { if (dwOrigin == STREAM_SEEK_SET) cur = (char*)bgn + (uint64)dlibMove.QuadPart; else if (dwOrigin == STREAM_SEEK_CUR) cur = (char*)cur + dlibMove.QuadPart; else if (dwOrigin == STREAM_SEEK_END) cur = (char*)bgn + size - 1 - dlibMove.QuadPart; if (plibNewPosition) *(&plibNewPosition->QuadPart) = (char*)cur - (char*)bgn; return S_OK; } virtual HRESULT STDMETHODCALLTYPE Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag) { memset(pstatstg, 0, sizeof(STATSTG)); //pstatstg->type = STGTY_STREAM; pstatstg->cbSize.QuadPart = (uint64)size; //pstatstg->grfMode = STGM_READ; // read grfMode is null //pstatstg->clsid = CLSID_NULL; // null CLSID_NULL is null return S_OK; } virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Revert() { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Clone(__RPC__deref_out_opt IStream **ppstm) { return E_NOTIMPL; } };
Ладно как её через ком заюзать? в мсдн есть что передавать в CoCreateInstance в параметр REFCLSID rclsid, где взять гуид или как? и где взять её определение для coinvoke? е ещё блин говорите что через ком не гемор! ГЕМОР ЕЩЁ ТОТ! Вот жешь придумали какието Stream, нет чтоб сделать GdipLoadImageFromMemory.
Компиль Masm, у меня есть битмап в памяти, мне нужно его загрузить(GdipLoadImageFromStream) обработать кодеком и поместить обратно в память(GdipSaveImageToStream). Но вот вся засада в этой IStream, как работать с функциями объекта я знаю, но не умею его создавать, как я понял объект создаётся при помощи CoCreateInstance, так вот какой гуид первым параметром передавать?
Создаёшь IStream. Пишешь целиком образ битмапа в него методом IStream::Write. Ставишь указатель потока на начало MoveStreamIStream::Seek. Передаёшь Gdip функциям. По-моему ничего геморного.
Чтобы овладевать IStream, нет необходимости вызывать какие-либо апи. Во-первых, что такое IStream? IStream — это интерфейс. Лайк, "соглашение". Лайк, "контракт". Чтобы реализовать этот интерфейс, нужно иметь базовые представления об объектах и виртуальных функциях — хотя бы потому, что стуктура, определяющая интерфейс, в памяти представлена именно как объект класса с виртуальными функциями. Код (Text): push 0 push offset IStreamVtbl mov eax, esp На стеке создан объект класса, реализующего IStream. В данном случае у этого класса есть только один мембер (мы инициализировали его нулём) и указатель на таблицу виртуальных функций. В регистр eax мы поместили адрес этого объекта — именно адрес объекта нужно передавать в качестве параметра в функции, требующие указателя на IStream. Теперь насчёт IStreamVtbl. Говоря по-правде, это всего-навсего массив адресов функций. Адреса располагаются в строго определённом порядке — ты заключил контракт же. Все функции используют соглашение stdcall, а первым (скрытым) параметром получают адрес объекта — это тоже часть контракта. Чтобы узнать порядок функций, нужно посмотреть определение IStream (в <objidl.h>). Точнее, определения виртуальных функций у IStream и его предков (ISequentialStream и IUnknown). Код (Text): IStreamVtbl: dd offset IStream_QueryInterface ; IUnknown dd offset IStream_AddRef dd offset IStream_Release dd offset IStream_Read ; ISequentialStream dd offset IStream_Write dd offset IStream_Seek ; IStream dd offset IStream_SetSize dd offset IStream_CopyTo dd offset IStream_Commit dd offset IStream_Revert dd offset IStream_LockRegion dd offset IStream_UnlockRegion dd offset IStream_Stat dd offset IStream_Clone Всё, что осталось — это реализовать все эти функции. Хотя, на самом деле, достаточно реализовать только те, которые будут использованы функциями, в которые ты передаёшь указатель на объект. Посмотри на наш предыдущий пост — мы реализовали только Read, Seek и (частично) Stat.
Это пусть 2FED решает. Мы, лайк, не навязываем что-либо сейчас. Но можно учесть, что реализация тривиальна, GlobalAlloc неэффективна, а код может быть реиспользован. Как бы то ни было — с тех пор как один пишет на ассемблере, низкоуровневые детали делают материю.
Да, вызов трёх функций сложнее огорода, на который ещё хрен знает сколько времени нужно потратить отлаживая. И с какого боку здесь GlobalAlloc пририсовался?
Booster Эта фраза просто кричит наружу: Теперь необходимо пройтись насчёт "готового" (CreateStreamOnHGlobal) и "вызова трёх функций". Пусть битмап находится в памяти. В этом случае при вызове CreateStreamOnHGlobal и IStream::Write в памяти будет создана копия уже имеющегося битмапа. Затем Gdip* функции будут вызывать IStream::Read, для того, чтобы прочитать битмап... в память. Что там было говорилось насчёт преумножения сущностей? (Нет, серьёзно — подобная реализация недалеко ушла от "if (boolValue.ToString.Length() < 5) {..}"). И нет, здесь не получится свалить вину на MS — вина в этом случае лежит на том, кто поленился потратить несколько минут своего времени и написать ~20 строчек тривиального кода. Своя реализация IStream ещё и тем хороша, что в том случае, когда битмап у нас изначально на диске, не будет необходимости выделять буфер, читать туда файл и триплировать память. Достаточно делать вызов ReadFile внутри IStream::Read (при этом будет прочитано столько байт, сколько реально необходимо — например, если заголовок файла повреждён, дальнейшее чтение производится не будет). Нет, мы не станем ожидать, что кто-нибудь, использующий, скажем, Визуальные Основы, пойдёт "сложным" путём (который сложен лишь на первый взгляд). Но предполагаем, что уж посетители этого форума смогут видеть всё это сквозь.
Sol_Ksacap Когда человек не уложиться в сроки разработки или когда произойдёт сбой по ошибке допущенной в своём огороде, тоже будет очень весело. Про оптимизацию конечно всё интересно, но это далеко не единственный и самый важный критерий выбора. Спасибо, что предложил свой вариант, но не надо его выпячивать как единственно лучшее решение. Это камень в мой огород? Если так, то могу сказать, что IStream до этого использовал, и вполне успешно. Вроде больше добавить нечего, кроме того, что только на васме можно увидеть диспут такого рода? ^)