ListView Drag Image

The place for threads about TimoSoft ExplorerListView.
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Post by TiKu »

Okay, here we go...

1) Start the drag'n'drop operation:

Code: Select all

	IDataObject* pDataObject = NULL;
	// TODO: Create an IDataObject instance here and don't forget to tell it the item count number to display.
	// TODO: Set a flag 'useItemCountLabelHack' if the item count number you want to display is >1. See step 3 for the hack.

	IDragSourceHelper* pDragSourceHelper = NULL;
	CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_ALL, IID_IDragSourceHelper, reinterpret_cast<LPVOID*>(&pDragSourceHelper));
	if(pDragSourceHelper) {
		if(flags.usingThemes && IsWindowsVistaOrNewer()) {
			IDragSourceHelper2* pDragSourceHelper2 = NULL;
			pDragSourceHelper->QueryInterface(IID_IDragSourceHelper2, reinterpret_cast<LPVOID*>(&pDragSourceHelper2));
			if(pDragSourceHelper2) {
				pDragSourceHelper2->SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT);
				// this was the only place we actually use IDragSourceHelper2
				pDragSourceHelper->Release();
				pDragSourceHelper = static_cast<IDragSourceHelper*>(pDragSourceHelper2);
			}
		}

		HRESULT hr = pDragSourceHelper->InitializeFromWindow(hWnd, &mousePosition, pDataObject);
		if(FAILED(hr)) {
			/* This happens if full window dragging is deactivated. Actually, InitializeFromWindow() contains a
			   fallback mechanism for this case. This mechanism retrieves the passed window's class name and
			   builds the drag image using TVM_CREATEDRAGIMAGE if it's SysTreeView32, LVM_CREATEDRAGIMAGE if
			   it's SysListView32 and so on. Our class name is ExplorerListView[U|A], so we're doomed.
			   So how can we have drag images anyway? Well, we use a very ugly hack: We temporarily activate
			   full window dragging. */
			BOOL fullWindowDragging;
			SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &fullWindowDragging, 0);
			if(!fullWindowDragging) {
				SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
				pDragSourceHelper->InitializeFromWindow(hWnd, &mousePosition, pDataObject);
				SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, FALSE, NULL, 0);
			}
		}

		if(pDragSourceHelper) {
			pDragSourceHelper->Release();
		}
	}

	HRESULT hr = DoDragDrop(pDataObject, pDragSource, supportedEffects, reinterpret_cast<LPDWORD>(pPerformedEffects));
2) Add this to your implementation of IDataObject::SetData(). It draws the item count label on top of the drag image.

Code: Select all

	// of course this must be done before storing the data internally
	if(properties.numberOfItemsToDisplay > 1) {
		if(pFormat->cfFormat == static_cast<CLIPFORMAT>(RegisterClipboardFormat(TEXT("DragImageBits")))) {
			if(pData->hGlobal) {
				LPTSTR pBuffer = ConvertIntegerToString(properties.numberOfItemsToDisplay);
				if(pBuffer) {
					CT2W converter(pBuffer);
					LPWSTR pLabelText = converter;
					if(pLabelText) {
						LPVOID pDragStuff = GlobalLock(pData->hGlobal);
						SHDRAGIMAGE dragImage = {0};
						CopyMemory(&dragImage, pDragStuff, sizeof(SHDRAGIMAGE));
						LPRGBQUAD pDragImageBits = reinterpret_cast<LPRGBQUAD>(reinterpret_cast<LPBYTE>(pDragStuff) + sizeof(SHDRAGIMAGE));

						CTheme themingEngine;
						themingEngine.OpenThemeData(NULL, VSCLASS_DRAGDROP);
						if(!themingEngine.IsThemeNull()) {
							CDC memoryDC;
							memoryDC.CreateCompatibleDC();

							// calculate size and position
							DWORD textDrawStyle = DT_SINGLELINE;
							WTL::CRect textRectangle;
							themingEngine.GetThemeTextExtent(memoryDC, DD_TEXTBG, 1, pLabelText, -1, textDrawStyle | DT_CALCRECT, NULL, &textRectangle);
							MARGINS margins = {0};
							themingEngine.GetThemeMargins(memoryDC, DD_TEXTBG, 1, TMT_CONTENTMARGINS, &textRectangle, &margins);
							WTL::CRect labelRectangle = textRectangle;
							labelRectangle.left -= margins.cxLeftWidth;
							labelRectangle.right += margins.cxRightWidth;
							labelRectangle.top -= margins.cyTopHeight;
							labelRectangle.bottom += margins.cyBottomHeight;
							labelRectangle.OffsetRect(-labelRectangle.left, -labelRectangle.top);
							int xLabelStart = (dragImage.sizeDragImage.cx - labelRectangle.Width()) / 2;
							int yLabelStart = (dragImage.sizeDragImage.cy - labelRectangle.Height()) / 2;

							BITMAPINFO bitmapInfo = {0};
							bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
							bitmapInfo.bmiHeader.biWidth = labelRectangle.Width();
							bitmapInfo.bmiHeader.biHeight = labelRectangle.Height();
							bitmapInfo.bmiHeader.biPlanes = 1;
							bitmapInfo.bmiHeader.biBitCount = 32;
							bitmapInfo.bmiHeader.biCompression = BI_RGB;
							LPRGBQUAD pLabelBits = NULL;
							CBitmap dragImageBMP;
							dragImageBMP.CreateDIBSection(memoryDC, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<LPVOID*>(&pLabelBits), NULL, NULL);
							ATLASSERT(pLabelBits);
							if(pLabelBits) {
								// for correct alpha-blending the label bitmap must have the correct background
								LPRGBQUAD pLabelPixel = pLabelBits;
								LPRGBQUAD pDragImagePixel = pDragImageBits;
								pDragImagePixel += yLabelStart * dragImage.sizeDragImage.cx;
								for(int y = 0; y < labelRectangle.Height(); ++y, pDragImagePixel += dragImage.sizeDragImage.cx, pLabelPixel += labelRectangle.Width()) {
									CopyMemory(pLabelPixel, pDragImagePixel + xLabelStart, labelRectangle.Width() * sizeof(RGBQUAD));
								}
								HBITMAP hPreviousBitmap = memoryDC.SelectBitmap(dragImageBMP);

								// draw the background
								themingEngine.DrawThemeBackground(memoryDC, DD_TEXTBG, 1, &labelRectangle, NULL);

								// draw the text
								textRectangle.left = labelRectangle.left + margins.cxLeftWidth;
								textRectangle.right = labelRectangle.right - margins.cxRightWidth;
								textRectangle.top = labelRectangle.top + margins.cyTopHeight;
								textRectangle.bottom = labelRectangle.bottom - margins.cyBottomHeight;
								themingEngine.DrawThemeText(memoryDC, DD_TEXTBG, 1, pLabelText, -1, textDrawStyle, 0, &textRectangle);

								// insert the label with the drag image
								pLabelPixel = pLabelBits;
								pDragImagePixel = pDragImageBits;
								pDragImagePixel += yLabelStart * dragImage.sizeDragImage.cx;
								POINT pt = {0};
								for(pt.y = 0; pt.y < labelRectangle.Height(); ++pt.y, pDragImagePixel += dragImage.sizeDragImage.cx, pLabelPixel += labelRectangle.Width()) {
									LPRGBQUAD pDst = pDragImagePixel + xLabelStart;
									LPRGBQUAD pSrc = pLabelPixel;
									for(pt.x = 0; pt.x < labelRectangle.Width(); ++pt.x, ++pDst, ++pSrc) {
										if(pSrc->rgbReserved == 0x00) {
											// TODO: Why do we need to correct the alpha channel here?
											if(textRectangle.PtInRect(pt)) {
												pSrc->rgbReserved = 0xFF;
											}
										}
										*pDst = *pSrc;
									}
								}

								memoryDC.SelectBitmap(hPreviousBitmap);
							}
						}
						GlobalUnlock(pData->hGlobal);
					}
					SECUREFREE(pBuffer);
				}
			}
		}
	}
3) Add this small hack to your implementation of IDropTarget::DragEnter():

Code: Select all

	pDropTargetHelper->DragEnter(*this, pDataObject, &mousePosition, *pEffect);
	if(useItemCountLabelHack) {
		pDropTargetHelper->DragLeave();
		pDropTargetHelper->DragEnter(*this, pDataObject, &mousePosition, *pEffect);
		useItemCountLabelHack = FALSE;
	}
4) Add this to your implementation of IDropSource::GiveFeedback(). It makes drop descriptions work.

Code: Select all

	BOOL useDefaultCursors = TRUE;
	if(flags.usingThemes && IsWindowsVistaOrNewer()) {
		// pDataObject is the IDataObject passed to DoDragDrop
		ATLASSUME(pDataObject);

		BOOL useDropDescriptionHack = FALSE;
		FORMATETC format = {0};
		format.cfFormat = static_cast<CLIPFORMAT>(RegisterClipboardFormat(TEXT("UsingDefaultDragImage")));
		format.dwAspect = DVASPECT_CONTENT;
		format.lindex = -1;
		format.tymed = TYMED_HGLOBAL;
		STGMEDIUM medium = {0};
		if(SUCCEEDED(pDataObject->GetData(&format, &medium))) {
			if(medium.hGlobal) {
				useDropDescriptionHack = *reinterpret_cast<LPBOOL>(GlobalLock(medium.hGlobal));
				GlobalUnlock(medium.hGlobal);
			}
			ReleaseStgMedium(&medium);
		}

		if(useDropDescriptionHack) {
			// this will make drop descriptions work
			format.cfFormat = static_cast<CLIPFORMAT>(RegisterClipboardFormat(TEXT("DragWindow")));
			format.dwAspect = DVASPECT_CONTENT;
			format.lindex = -1;
			format.tymed = TYMED_HGLOBAL;
			if(SUCCEEDED(pDataObject->GetData(&format, &medium))) {
				if(medium.hGlobal) {
					// WM_USER + 1 (with wParam = 0 and lParam = 0) hides the drag image
					#define WM_SETDROPEFFECT				WM_USER + 2     // (wParam = DCID_*, lParam = 0)
					#define WM_INVALIDATEDRAGIMAGE	WM_USER + 3     // (wParam = 0, lParam = 0)
					typedef enum DROPEFFECTS
					{
						DCID_NULL = 0,
						DCID_NO = 1,
						DCID_MOVE = 2,
						DCID_COPY = 3,
						DCID_LINK = 4,
						DCID_MAX = 5
					} DROPEFFECTS;

					HWND hWndDragWindow = *reinterpret_cast<HWND*>(GlobalLock(medium.hGlobal));
					GlobalUnlock(medium.hGlobal);

					DROPEFFECTS dropEffect = DCID_NULL;
					switch(effect) {
						case DROPEFFECT_NONE:
							dropEffect = DCID_NO;
							break;
						case DROPEFFECT_COPY:
							dropEffect = DCID_COPY;
							break;
						case DROPEFFECT_MOVE:
							dropEffect = DCID_MOVE;
							break;
						case DROPEFFECT_LINK:
							dropEffect = DCID_LINK;
							break;
					}
					SendMessage(hWndDragWindow, WM_SETDROPEFFECT, dropEffect, 0);
				}
				ReleaseStgMedium(&medium);
			}
			SetCursor(static_cast<HCURSOR>(LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED)));
			useDefaultCursors = FALSE;
		}
	}
	return (useDefaultCursors ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK);
5) Do this in your DI_GETDRAGIMAGE message handler:

Code: Select all

	BOOL succeeded = FALSE;
	BOOL useVistaDragImage = FALSE;
	if(flags.usingThemes && IsWindowsVistaOrNewer()) {
		succeeded = CreateVistaOLEDragImage(pDraggedItems, reinterpret_cast<LPSHDRAGIMAGE>(lParam));
		useVistaDragImage = succeeded;
	}
	if(!succeeded) {
		// use a legacy drag image as fallback
		succeeded = CreateLegacyOLEDragImage(pDraggedItems, reinterpret_cast<LPSHDRAGIMAGE>(lParam));
	}

	if(succeeded && IsWindowsVistaOrNewer()) {
		FORMATETC format = {0};
		format.cfFormat = static_cast<CLIPFORMAT>(RegisterClipboardFormat(TEXT("UsingDefaultDragImage")));
		format.dwAspect = DVASPECT_CONTENT;
		format.lindex = -1;
		format.tymed = TYMED_HGLOBAL;
		STGMEDIUM medium = {0};
		medium.tymed = TYMED_HGLOBAL;
		medium.hGlobal = GlobalAlloc(GHND, sizeof(BOOL));
		if(medium.hGlobal) {
			LPBOOL pUseVistaDragImage = reinterpret_cast<LPBOOL>(GlobalLock(medium.hGlobal));
			*pUseVistaDragImage = useVistaDragImage;
			GlobalUnlock(medium.hGlobal);

			// pDataObject is the IDataObject passed to DoDragDrop
			pDataObject->SetData(&format, &medium, TRUE);
		}
	}

	// TODO: Why do we have to return FALSE to have the set offset not ignored if a Vista drag image is used?
	return succeeded && !useVistaDragImage;
6) CreateVistaOLEDragImage():

Code: Select all

	BOOL succeeded = FALSE;

	CTheme themingEngine;
	themingEngine.OpenThemeData(NULL, VSCLASS_DRAGDROP);
	if(themingEngine.IsThemeNull()) {
		// FIXME: What should we do here?
		ATLASSERT(FALSE && "Current theme does not define the \"DragDrop\" class.");
	} else {
		// retrieve the drag image's size
		CDC memoryDC;
		memoryDC.CreateCompatibleDC();

		themingEngine.GetThemePartSize(memoryDC, DD_IMAGEBG, 1, NULL, TS_TRUE, &pDragImage->sizeDragImage);
		MARGINS margins = {0};
		themingEngine.GetThemeMargins(memoryDC, DD_IMAGEBG, 1, TMT_CONTENTMARGINS, NULL, &margins);
		pDragImage->sizeDragImage.cx -= margins.cxLeftWidth + margins.cxRightWidth;
		pDragImage->sizeDragImage.cy -= margins.cyTopHeight + margins.cyBottomHeight;
	}

	ATLASSERT(pDragImage->sizeDragImage.cx > 0);
	ATLASSERT(pDragImage->sizeDragImage.cy > 0);

	// create target bitmap
	BITMAPINFO bitmapInfo = {0};
	bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitmapInfo.bmiHeader.biWidth = pDragImage->sizeDragImage.cx;
	bitmapInfo.bmiHeader.biHeight = -pDragImage->sizeDragImage.cy;
	bitmapInfo.bmiHeader.biPlanes = 1;
	bitmapInfo.bmiHeader.biBitCount = 32;
	bitmapInfo.bmiHeader.biCompression = BI_RGB;
	LPRGBQUAD pDragImageBits = NULL;
	pDragImage->hbmpDragImage = CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<LPVOID*>(&pDragImageBits), NULL, 0);

	HIMAGELIST hSourceImageList = (cachedSettings.hHighResImageList ? cachedSettings.hHighResImageList : cachedSettings.hImageList);
	if(!hSourceImageList) {
		// report success, although we've an empty drag image
		return TRUE;
	}

	IImageList2* pImgLst = NULL;
	HMODULE hMod = LoadLibrary(TEXT("comctl32.dll"));
	if(hMod) {
		typedef HRESULT WINAPI HIMAGELIST_QueryInterfaceFn(HIMAGELIST, REFIID, LPVOID*);
		HIMAGELIST_QueryInterfaceFn* pfnHIMAGELIST_QueryInterface = reinterpret_cast<HIMAGELIST_QueryInterfaceFn*>(GetProcAddress(hMod, "HIMAGELIST_QueryInterface"));
		if(pfnHIMAGELIST_QueryInterface) {
			pfnHIMAGELIST_QueryInterface(hSourceImageList, IID_IImageList2, reinterpret_cast<LPVOID*>(&pImgLst));
		}
		FreeLibrary(hMod);
	}
	if(!pImgLst) {
		IImageList* p = reinterpret_cast<IImageList*>(hSourceImageList);
		p->QueryInterface(IID_IImageList2, reinterpret_cast<LPVOID*>(&pImgLst));
	}
	ATLASSUME(pImgLst);

	if(pImgLst) {
		// set this to the number of dragged items
		int numberOfItems = ...;
		ATLASSERT(numberOfItems > 0);
		// don't display more than 5 (10) thumbnails
		numberOfItems = min(numberOfItems, (hSourceImageList == cachedSettings.hHighResImageList ? 5 : 10));

		int cx = 0;
		int cy = 0;
		pImgLst->GetIconSize(&cx, &cy);
		SIZE thumbnailSize;
		thumbnailSize.cy = pDragImage->sizeDragImage.cy - 3 * (numberOfItems - 1);
		if(thumbnailSize.cy < 8) {
			// don't get smaller than 8x8 thumbnails
			numberOfItems = (pDragImage->sizeDragImage.cy - 8) / 3 + 1;
			thumbnailSize.cy = pDragImage->sizeDragImage.cy - 3 * (numberOfItems - 1);
		}
		thumbnailSize.cx = thumbnailSize.cy;
		int thumbnailBufferSize = thumbnailSize.cx * thumbnailSize.cy * sizeof(RGBQUAD);
		LPRGBQUAD pThumbnailBits = reinterpret_cast<LPRGBQUAD>(HeapAlloc(GetProcessHeap(), 0, thumbnailBufferSize));
		ATLASSERT(pThumbnailBits);
		if(pThumbnailBits) {
			for each dragged item until 'numberOfItems' is reached:
			{
				// get the item's icon
				int icon = ...;
				pImgLst->ForceImagePresent(icon, ILFIP_ALWAYS);
				HICON hIcon = NULL;
				pImgLst->GetIcon(icon, ILD_TRANSPARENT, &hIcon);
				ATLASSERT(hIcon);
				if(hIcon) {
					// finally create the thumbnail
					ZeroMemory(pThumbnailBits, thumbnailBufferSize);
					HRESULT hr = CreateThumbnail(hIcon, thumbnailSize, pThumbnailBits, TRUE);
					DestroyIcon(hIcon);
					if(FAILED(hr)) {
						break;
					}

					// add the thumbail to the drag image keeping the alpha channel intact
					if(i == 0) {
						LPRGBQUAD pDragImagePixel = pDragImageBits;
						LPRGBQUAD pThumbnailPixel = pThumbnailBits;
						for(int scanline = 0; scanline < thumbnailSize.cy; ++scanline, pDragImagePixel += pDragImage->sizeDragImage.cx, pThumbnailPixel += thumbnailSize.cx) {
							CopyMemory(pDragImagePixel, pThumbnailPixel, thumbnailSize.cx * sizeof(RGBQUAD));
						}
					} else {
						LPRGBQUAD pDragImagePixel = pDragImageBits;
						LPRGBQUAD pThumbnailPixel = pThumbnailBits;
						pDragImagePixel += 3 * i * pDragImage->sizeDragImage.cx;
						for(int scanline = 0; scanline < thumbnailSize.cy; ++scanline, pDragImagePixel += pDragImage->sizeDragImage.cx) {
							LPRGBQUAD p = pDragImagePixel + 2 * i;
							for(int x = 0; x < thumbnailSize.cx; ++x, ++p, ++pThumbnailPixel) {
								// merge the pixels
								p->rgbRed = pThumbnailPixel->rgbRed * pThumbnailPixel->rgbReserved / 0xFF + (0xFF - pThumbnailPixel->rgbReserved) * p->rgbRed / 0xFF;
								p->rgbGreen = pThumbnailPixel->rgbGreen * pThumbnailPixel->rgbReserved / 0xFF + (0xFF - pThumbnailPixel->rgbReserved) * p->rgbGreen / 0xFF;
								p->rgbBlue = pThumbnailPixel->rgbBlue * pThumbnailPixel->rgbReserved / 0xFF + (0xFF - pThumbnailPixel->rgbReserved) * p->rgbBlue / 0xFF;
								p->rgbReserved = pThumbnailPixel->rgbReserved + (0xFF - pThumbnailPixel->rgbReserved) * p->rgbReserved / 0xFF;
							}
						}
					}
				}
			}

			HeapFree(GetProcessHeap(), 0, pThumbnailBits);
			succeeded = TRUE;
		}

		pImgLst->Release();
	}

	return succeeded;
7) CreateThumbnail():

Code: Select all

HRESULT CreateThumbnail(HICON hIcon, SIZE& size, LPRGBQUAD pBits, BOOL doAlphaChannelPostProcessing)
{

	if(!hIcon || !pBits || !pWICImagingFactory) {
		return E_FAIL;
	}

	ICONINFO iconInfo;
	GetIconInfo(hIcon, &iconInfo);
	ATLASSERT(iconInfo.hbmColor);
	BITMAP bitmapInfo = {0};
	if(iconInfo.hbmColor) {
		GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmapInfo);
	} else if(iconInfo.hbmMask) {
		GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bitmapInfo);
	}
	bitmapInfo.bmHeight = abs(bitmapInfo.bmHeight);
	BOOL needsFrame = ((bitmapInfo.bmWidth < size.cx) || (bitmapInfo.bmHeight < size.cy));
	if(iconInfo.hbmColor) {
		DeleteObject(iconInfo.hbmColor);
	}
	if(iconInfo.hbmMask) {
		DeleteObject(iconInfo.hbmMask);
	}

	HRESULT hr = E_FAIL;

	CComPtr<IWICBitmapScaler> pWICBitmapScaler = NULL;
	if(!needsFrame) {
		hr = pWICImagingFactory->CreateBitmapScaler(&pWICBitmapScaler);
		ATLASSERT(SUCCEEDED(hr));
		ATLASSUME(pWICBitmapScaler);
	}
	if(needsFrame || SUCCEEDED(hr)) {
		CComPtr<IWICBitmap> pWICBitmapSource = NULL;
		hr = pWICImagingFactory->CreateBitmapFromHICON(hIcon, &pWICBitmapSource);
		ATLASSERT(SUCCEEDED(hr));
		ATLASSUME(pWICBitmapSource);
		if(SUCCEEDED(hr)) {
			if(!needsFrame) {
				hr = pWICBitmapScaler->Initialize(pWICBitmapSource, size.cx, size.cy, WICBitmapInterpolationModeFant);
			}
			if(SUCCEEDED(hr)) {
				WICRect rc = {0};
				if(needsFrame) {
					rc.Height = bitmapInfo.bmHeight;
					rc.Width = bitmapInfo.bmWidth;
					UINT stride = rc.Width * sizeof(RGBQUAD);
					LPRGBQUAD pIconBits = reinterpret_cast<LPRGBQUAD>(HeapAlloc(GetProcessHeap(), 0, rc.Width * rc.Height * sizeof(RGBQUAD)));
					hr = pWICBitmapSource->CopyPixels(&rc, stride, rc.Height * stride, reinterpret_cast<LPBYTE>(pIconBits));
					ATLASSERT(SUCCEEDED(hr));
					if(SUCCEEDED(hr)) {
						// center the icon
						int xIconStart = (size.cx - bitmapInfo.bmWidth) / 2;
						int yIconStart = (size.cy - bitmapInfo.bmHeight) / 2;
						LPRGBQUAD pIconPixel = pIconBits;
						LPRGBQUAD pPixel = pBits;
						pPixel += yIconStart * size.cx;
						for(int y = yIconStart; y < yIconStart + bitmapInfo.bmHeight; ++y, pPixel += size.cx, pIconPixel += bitmapInfo.bmWidth) {
							CopyMemory(pPixel + xIconStart, pIconPixel, bitmapInfo.bmWidth * sizeof(RGBQUAD));
						}
						HeapFree(GetProcessHeap(), 0, pIconBits);

						rc.Height = size.cy;
						rc.Width = size.cx;

						// TODO: now draw a frame around it
					}
				} else {
					rc.Height = size.cy;
					rc.Width = size.cx;
					UINT stride = rc.Width * sizeof(RGBQUAD);
					hr = pWICBitmapScaler->CopyPixels(&rc, stride, rc.Height * stride, reinterpret_cast<LPBYTE>(pBits));
					ATLASSERT(SUCCEEDED(hr));

					if(SUCCEEDED(hr) && doAlphaChannelPostProcessing) {
						for(int i = 0; i < rc.Width * rc.Height; ++i, ++pBits) {
							if(pBits->rgbReserved == 0x00) {
								ZeroMemory(pBits, sizeof(RGBQUAD));
							}
						}
					}
				}
			} else {
				ATLASSERT(FALSE && "Bitmap scaler failed");
			}
		}
	}
	return hr;
}
8) Instanciate the IWICImagingFactory. I do this in the constructor of my control class.

Code: Select all

	CComPtr<IWICImagingFactory> pWICImagingFactory;
	if(IsWindowsVistaOrNewer()) {
		CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<LPVOID*>(&pWICImagingFactory));
		ATLASSUME(pWICImagingFactory);
	}
That's it. Easy, isn't it? :buck:
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
Post Reply