![]() |
Multimedia »
Audio and Video »
Multimedia
Intermediate
How to transfer a picture from an MFC client to an ATL ActiveX CtrlBy Braulio DezHow to pass a metafile to an ATL server directly or using streams |
VC6Win2K, WinXP, MFC, ATL, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

Every book, and every single tutorial, teaches you how to use the basic things of COM with very good C samples. That's pretty good to begin with, but the problem comes when you want to pass from your client to your COM server/control something more than one numeric value, or one string, or... for example a Metafile, or a Bitmap... then you start having problems with the Variant type...
That was my nightmare during some days. I wanted to pass a metafile from my MFC client to my ATL ActiveX control. Here I show you how I did it (in the same process space and in different ones).
I have added some basic info about how to make both projects, if are used to it you can skip it, if you need more info about them, you can check out some basic tutorials that you can find in codeproject as well.
The ATL control that we are going to create is a full ActiveX control, with one interface that will allow us assign one metafile to the it ( then that metafile will be shown, in the space of the ActiveX control):
Ok, we will add now a member variable to our brand new object, that will hold the metafile, so go to "PicShower.H", and add this variable:
// Better to use smart pointers, just forget about AddRef, Release, QInterface... CComQIPtr<IPICTURE> _Pict;The "CComQIPtr" thing, it's one of the smart pointers that ATL offers to us. They make it a lot easier to handle COM objects as it makes the code look like Visual Basic (it wraps all the
QueryInterface, AddRef, Release...).
And the IPicture? It�s the interface to a standard component that allows you to
display Metafiles, Bitmaps ( jpg, gif, tiff...). Cool isn�t it ?.
Now let's code a little. Go to the implementation of the method "SetDirectMeta" (the wizard implemented an empty skeleton for us, in the file
"PicShower.cpp", the name of the method is CPicShower::SetDirectMeta(LPUNKNOWN
Picture) and add this code:
/* ------------------------------------------------------------------------- This only works, if it�s in the same space process ------------------------------------------------------------------------- */ STDMETHODIMP CPicShower::SetDirectMeta(LPUNKNOWN Picture) { _Pict = Picture; // Assign the picture FireViewChange(); // Force to redraw the ActiveX return S_OK; }
This method call will allow us to assign the metafile, but this only will work if we use the component in the same space process ( you can not share a DC, between different process spaces), so if you use this code in an EXE server, this method won't work, or if for example you paste the ActiveX in an automated Word instance and you use it from your application.
To solve this we can use this other method: go to the implementation, of the method
"SetMeta", CPicShower::SetMeta(LPUNKNOWN
Picture) and add this code:
/* ------------------------------------------------------------------------- Ok, this method works in all the places ( in proccess, out of process, ...). The Picture is saved in memory in one stream, then we open that stream and load the picture ------------------------------------------------------------------------- */ STDMETHODIMP CPicShower::SetMeta(LPUNKNOWN Stream) { CComQIPtr<ISTREAM> pStream = Stream; if(pStream) { // Using one smart pointer to get the Picture Dispatch CComPtr<IPICTUREDISP> pic; LARGE_INTEGER l; l.QuadPart = 0; pStream->Seek(l, STREAM_SEEK_SET, NULL); OleLoadPicture(pStream, l.LowPart, FALSE, IID_IPictureDisp, (void **) &pic); if(pic) { _Pict = pic; // Ok, QInterface smart pointer... } FireViewChange(); // Force to redraw } return S_OK; }
Here what we receive as a parameter is one stream, then we only have to load that stream ( normally it will be in memory), and load the picture.
Let�s modify the drawing code, in order to check if the picture variable is not
empty and draw it then ( in the file "PicShower.H", the method HRESULT OnDraw(ATL_DRAWINFO& di)),
we set it like this:
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
if(_Pict) {
RECT r = rc;
long lPicWidth = 0;
long lPicHeight = 0;
if(_Pict){
_Pict->get_Width(&lPicWidth);_Pict->get_Height(&lPicHeight);
HRESULT hres = _Pict->Render(di.hdcDraw, 0, 0, rc.right, rc.bottom,
0, lPicHeight, lPicWidth, -(lPicHeight), &r);
}
} else {
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("PicShower: No picture assigned");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
}
return S_OK;
}
In the Render we have to use negative value -(lPicHeight), because we
are working in Himetric coordinates.
Ok, now it seems that we have completed all the code for our ATL ActiveX control, let�s go for the MFC part.
To use our control in our MFC client App, we can do it in several ways, the two that I like best are:
One thing, before try the MFC client, compile the ATL project ( then the ActiveX DLL will be autoregistered and all will work fine).
To write this article I used MSDN to search Info, and one very good article, called "Using Picture Objects in ATL", found on vbpj April 1999.
A lot of people helped me in the message board, to make this, special thanks to: Joao Vaz, Joaqu�n M L�pez Mu�oz, Mazdak, ...
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 12 Mar 2002 Editor: Chris Maunder |
Copyright 2002 by Braulio Dez Everything else Copyright © CodeProject, 1999-2009 Web22 | Advertise on the Code Project |