Встретил топик похожий, налабал решение попроще. Так можно сохранять хучь битмапы, хучь иконки, хучь метафайлы и вообще все объекты, поддерживающие IPicture. Написал на Cи — так круче.
Здравствуйте Hollander, Вы писали:
VD>>Посмотри (в MSDN) IPictureDisp (IPicture) и функции с ними связанные.
H>Экий ты торопыга,а чем же я и пользовался ? Посмотри код, или ты COM только на C++ понимаешь ?
Сори увидел разные "PICTDESC pDesc;" и решил, что ты нас АПИшнинкой решил удивить.
Слушай, а зачем ты так:
pPicture->lpVtbl->AddRef(pPicture);
? А?
Да, и зачем делать AddRef перед передачей параметра в функцию?
Делать же Release переданного в функцию объекта вообще нельзя (по правилам COM).
И HRESULT проверять немешало бы.
А короче, можно... испльзуем смартпоинтеры и библиотечные реализации стрима над файлом и будет короче.
PS
Ты ы малость причисал этот код и можно было бы его в журнал (RSDN Mag) сунуть как FAQ.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте IT, Вы писали:
IT>Здравствуйте VladD2, Вы писали:
VD>>Ты ы малость причисал этот код и можно было бы его в журнал (RSDN Mag) сунуть как FAQ.
IT>Точно, но лучше бы убрать мазахизм в виде "Написал на Cи — так круче" (C) Hollander
Господи, это же на C! Во блин не узнал. О дожил!
Не ну COM на С это уже перебор. Я конечно понимаю, что это круто, но... ооо... ууу...
Но все равно программирование COM-а на C не снимает ответственности за правильную работу с AddRef/Release.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, Вы писали:
VD>Сори увидел разные "PICTDESC pDesc;" и решил, что ты нас АПИшнинкой решил удивить.
VD>Слушай, а зачем ты так: VD>
pPicture->>lpVtbl->AddRef(pPicture);
VD>
VD>?
Можно и так : IPicture_Release(pPicture);
VD>Да, и зачем делать AddRef перед передачей параметра в функцию?
Там этот указатель используется — по все правилам COM.
VD>Делать же Release переданного в функцию объекта вообще нельзя (по правилам COM).
Так я и не делаю — это освобождается после OleCreatePictureIndirect, а в функции свой Release есть еще.
VD>И HRESULT проверять немешало бы.
Это не нужно — я проверяю на NULL.
VD>А короче, можно... испльзуем смартпоинтеры и библиотечные реализации стрима над файлом и будет короче.
Я взял чистый API — смартпоинтеры и библиотечные реализации стрима — по колву кода будет длиннее.
VD>PS
VD>Ты ы малость причисал этот код и можно было бы его в журнал (RSDN Mag) сунуть как FAQ.
Здравствуйте Hollander, Вы писали:
VD>>Да, и зачем делать AddRef перед передачей параметра в функцию?
H>Там этот указатель используется — по все правилам COM.
Это не по правилам COM.
VD>>Делать же Release переданного в функцию объекта вообще нельзя (по правилам COM). H>Так я и не делаю — это освобождается после OleCreatePictureIndirect, а в функции свой Release есть еще.
VD>>И HRESULT проверять немешало бы.
H>Это не нужно — я проверяю на NULL.
А вот это не по правилам COM.
По правилам COM будет
IPicture* pPicture = NULL;
HRESULT hRes;
hRes = OleCreatePictureIndirect(&pDesc,&IID_IPicture,FALSE,(void**)&pPicture);
if (SUCCEEDED(hRes))
{
// pPicture->Release из SavePicture убрать!!!
// возвращаемое значение сделать HRESULT
hRes = SavePicture(pPicture,szPath);
pPicture->lpVtbl->Release(pPicture);
}
return hRes;
Здравствуйте Hollander, Вы писали:
H>Можно и так : IPicture_Release(pPicture);
А разве нет универсального макроса?
Да я по началу не въехал, что код на C. Сори. Привычка блин. COM == С++/VB/Delphi. Короче, стереотип.
VD>>Да, и зачем делать AddRef перед передачей параметра в функцию?
H>Там этот указатель используется — по все правилам COM.
Не-аа! Против правил.
По правилам COM-а если указатель на интерфейс передается в функцию как [in, out]-параметр, ArrRef-ов и релизов делать не надо. Можно конечно сделать эдреф и релиз внутри функции, но бес толку.
AddRef делается когда параметр идет как out и когда указатель помещается в некоторую переменную для долговременного хранеия. В C — это может быть только глобальная переменная.
VD>>Делать же Release переданного в функцию объекта вообще нельзя (по правилам COM). H>Так я и не делаю — это освобождается после OleCreatePictureIndirect, а в функции свой Release есть еще.
Вот я и говорю.
BOOL SavePictureIndirect(PICTDESC pDesc,LPCTSTR szPath)
{
IPicture* pPicture = NULL;
BOOL bResult = TRUE;
OleCreatePictureIndirect(&pDesc,&IID_IPicture,FALSE,(void**)&pPicture);
if(pPicture == NULL)
bResult = FALSE;
else
{
// Вот это AddRef ...pPicture->lpVtbl->AddRef(pPicture);
bResult = SavePicture(pPicture,szPath);
}
if(pPicture != NULL)
pPicture->lpVtbl->Release(pPicture);
return bResult;
}
// и вот этот релиз...
// ...while(FALSE);
if(pPicture != NULL)
pPicture->lpVtbl->Release(pPicture);// ...
Лишние. Эти две ошибки друг друга компенсируют.
Если эти функции (по отдельности) начнут использовать другие программисты, с применением правил COM, будут вылезать ошибки подсчета ссылок.
VD>>И HRESULT проверять не мешало бы. :-\
H>Это не нужно — я проверяю на NULL.
Вот на NULL можно и не проверять, а HRESULT желательно. И без этого работать будет, но:
Если произойдет ошибка, но вызвавших твою функцию не сможет узнать в что произошло. Ну, и гипотетически возможен вариант, что произойдет не фатальная ошибка и ты ее проигнорируешь.
Короче, с COM-ом всегда лучше проверять hr-ы. Времени займет не много, а проблемы многие может снять.
VD>>А короче, можно... используем смартпоинтеры и библиотечные реализации стрима над файлом и будет короче.
H>Я взял чистый API — смартпоинтеры и библиотечные реализации стрима — по колву кода будет длиннее.
Я сразу не въехал, что код на C. Но кому нужен сегодня чистый C. Хотя для примера — это хорошо. Только я бы все равно его на C++ писал бы.
Кстати, в любом случае запись стрима в файл лучше вынести в отдельную функцию.
VD>>Ты бы малость причесал этот код и можно было бы его в журнал (RSDN Mag) сунуть как FAQ.
H>А поподробнее можно ?
1. Устранить проблемы с AddRef/Release.
2. Добавить комментарии и введение (в чем сложность?... основание для такого решения...).
3. (Опшонал) Переписать на C++. (кстати, очень приветствуются многоязычные варианты... VB, Delphi, .Net... но только у них у всех есть собственные встроенные средства)
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
H>Привет !
H>Встретил топик похожий, налабал решение попроще. Так можно сохранять хучь битмапы, хучь иконки, хучь метафайлы и вообще все объекты, поддерживающие IPicture. Написал на Cи — так круче.
даешь GDI+ в массы!!!
/// пример не в тему, зато позволяет сохранять в bmp,jpeg,gif,emf,tiff,png
/// содран с PlatformSDK/GDI+/Setting JPEG Compression Level#include <Stdio.h>
#include <Objbase.h>
#include <Windows.h>
#include <Gdiplus.h>
using namespace Gdiplus;
// Helper functionsint GetCodecClsid(const WCHAR*, CLSID*);
int main()
{
CLSID codecClsid;
EncoderParameters encoderParameters;
long quality;
Status stat;
// Get an image from the disk.
Image image(L"Shapes.bmp");
// Get the CLSID of the JPEG codec.
GetCodecClsid(L"image/jpeg", &codecClsid);
// Before we call Image::Save, we must initialize an
// EncoderParameters object. The EncoderParameters object
// has an array of EncoderParameter objects. In this
// case, there is only one EncoderParameter object in the array.
// The one EncoderParameter object has an array of values.
// In this case, there is only one value (of type LONG)
// in the array. We will set this value to 0, 50, and 100.
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = ValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
// Save the image as a JPEG with quality level 0.
quality = 0;
encoderParameters.Parameter[0].Value = &quality;
stat = image.Save(L"Shapes001.jpg", &codecClsid, &encoderParameters);
if(stat == Ok)
wprintf(L"%s saved successfully.\n", L"Shapes001.jpg");
else
wprintf(L"%d Attempt to save %s failed.\n", stat, L"Shapes001.jpg");
// Save the image as a JPEG with quality level 50.
quality = 50;
encoderParameters.Parameter[0].Value = &quality;
stat = image.Save(L"Shapes050.jpg", &codecClsid, &encoderParameters);
if(stat == Ok)
wprintf(L"%s saved successfully.\n", L"Shapes050.jpg");
else
wprintf(L"%d Attempt to save %s failed.\n", stat, L"Shapes050.jpg");
// Save the image as a JPEG with quality level 100.
quality = 100;
encoderParameters.Parameter[0].Value = &quality;
stat = image.Save(L"Shapes100.jpg", &codecClsid, &encoderParameters);
if(stat == Ok)
wprintf(L"%s saved successfully.\n", L"Shapes100.jpg");
else
wprintf(L"%d Attempt to save %s failed.\n", stat, L"Shapes100.jpg");
return 0;
} // main