// CxImage.cpp : Implementation of CCxImage
#include "stdafx.h"
#include "CxImageATL.h"
#include "CxImage.h"
// ------------------ HELPER FUNCTIONS -------------------------------------
#define RGBQUAD2OLE_COLOR(q) ((COLORREF)(((BYTE)(q.rgbRed)|((WORD)((BYTE)(q.rgbGreen))<<8))|(((DWORD)(BYTE)(q.rgbBlue))<<16)))
RGBQUAD OLE_COLOR2RGBQUAD(OLE_COLOR c)
{
RGBQUAD q;
q.rgbBlue=GetBValue(c); q.rgbGreen=GetGValue(c); q.rgbRed = GetRValue(c); q.rgbReserved=0;
return q;
}
VARIANT GetScriptArray(VARIANT scriptvar)
{
VARIANT vArr;
if(scriptvar.vt == (VT_VARIANT|VT_BYREF)) // make by-val
{
vArr = *scriptvar.pvarVal;
}
else
vArr = scriptvar;
if(vArr.vt == (VT_VARIANT|VT_ARRAY|VT_BYREF) )
{
vArr.vt = VT_VARIANT | VT_ARRAY;
vArr.parray = *vArr.pparray;
}
return vArr;
}
CxImage *GetCxImageFromIDispatch(LPDISPATCH lpDisp)
{
CComQIPtr<ICxImage> pICxImage = lpDisp;
CxImage *pImage; pICxImage->GetCxImagePtr((long *)&pImage);
return pImage;
}
// ------------------------------------------------------
STDMETHODIMP CCxImage::Load(BSTR FileName, long ImageType)
{
m_image.Destroy();
m_image.Load(FileName,ImageType);
return S_OK;
}
STDMETHODIMP CCxImage::Save(BSTR FileName, long ImageType)
{
m_image.Save(FileName,ImageType);
return S_OK;
}
STDMETHODIMP CCxImage::Create(long dwWidth, long dwHeight, long wBpp, long imagetype)
{
m_image.Create((DWORD)dwWidth,(DWORD)dwHeight, wBpp, imagetype);
return S_OK;
}
STDMETHODIMP CCxImage::Clear(long val)
{
m_image.Clear(val);
return S_OK;
}
STDMETHODIMP CCxImage::Destroy()
{
m_image.Destroy();
return S_OK;
}
STDMETHODIMP CCxImage::CopyToHandle(long *pHandle)
{
*pHandle = (long)m_image.CopyToHandle();
return S_OK;
}
STDMETHODIMP CCxImage::CreateFromHBITMAP(long hbmp)
{
m_image.CreateFromHBITMAP((HBITMAP)hbmp);
return S_OK;
}
STDMETHODIMP CCxImage::CreateFromHANDLE(long hmem)
{
m_image.CreateFromHANDLE((HANDLE)hmem);
return S_OK;
}
STDMETHODIMP CCxImage::Flip()
{
m_image.Flip();
return S_OK;
}
STDMETHODIMP CCxImage::Mirror()
{
m_image.Mirror();
return S_OK;
}
STDMETHODIMP CCxImage::Copy(LPDISPATCH CxSrc)
{
CxImage *pImage = GetCxImageFromIDispatch(CxSrc);
m_image.Copy(*pImage);
return S_OK;
}
STDMETHODIMP CCxImage::Rotate(float angle)
{
m_image.Rotate(angle);
return S_OK;
}
STDMETHODIMP CCxImage::RotateLeft()
{
m_image.RotateLeft();
return S_OK;
}
STDMETHODIMP CCxImage::RotateRight()
{
m_image.RotateRight();
return S_OK;
}
STDMETHODIMP CCxImage::Rotate180()
{
m_image.Rotate180();
return S_OK;
}
STDMETHODIMP CCxImage::Negative()
{
m_image.Negative();
return S_OK;
}
STDMETHODIMP CCxImage::Resample(long newx, long newy, ResampleMethod rm)
{
m_image.Resample(newx,newy, (int)rm);
return S_OK;
}
STDMETHODIMP CCxImage::IncreaseBpp(long bits)
{
m_image.IncreaseBpp((DWORD)bits);
return S_OK;
}
STDMETHODIMP CCxImage::DecreaseBpp(long nbit, VARIANT_BOOL errordiffusion)
{
m_image.DecreaseBpp((DWORD)nbit, (bool)errordiffusion);
return S_OK;
}
STDMETHODIMP CCxImage::Filter(VARIANT kernel, long Ksize, long Kfactor, long Koffset)
{
SAFEARRAY *arrKernel = GetScriptArray(kernel).parray;
long *values = new long[Ksize*Ksize];
CComVariant t;
for(long ind=0; ind<Ksize*Ksize; ind++) {
SafeArrayGetElement(arrKernel,&ind,&t);
values[ind] = t.lVal;
}
m_image.Filter(values,Ksize,Kfactor,Koffset);
delete [] values;
return S_OK;
}
STDMETHODIMP CCxImage::GrayScale()
{
m_image.GrayScale();
return S_OK;
}
STDMETHODIMP CCxImage::Dither(DitherMethod method)
{
m_image.Dither((long)method);
return S_OK;
}
STDMETHODIMP CCxImage::Crop(long left, long top, long right, long bottom)
{
m_image.Crop(left,top,right,bottom);
return S_OK;
}
STDMETHODIMP CCxImage::Threshold(long level)
{
m_image.Threshold((BYTE)level);
return S_OK;
}
STDMETHODIMP CCxImage::Colorize(long hue, long sat)
{
m_image.Colorize((BYTE)hue,(BYTE)sat);
return S_OK;
}
STDMETHODIMP CCxImage::Light(long level, long contrast)
{
m_image.Light(level,contrast);
return S_OK;
}
STDMETHODIMP CCxImage::Mean(float *value)
{
*value = m_image.Mean();
return S_OK;
}
STDMETHODIMP CCxImage::Erode(long Ksize)
{
m_image.Erode(Ksize);
return S_OK;
}
STDMETHODIMP CCxImage::Dilate(long Ksize)
{
m_image.Dilate(Ksize);
return S_OK;
}
STDMETHODIMP CCxImage::Mix(LPDISPATCH Src2, ImageOpType op, long lXOffset, long lYOffset)
{
CxImage *pSrc = GetCxImageFromIDispatch(Src2);
m_image.Mix(*pSrc,(CxImage::ImageOpType)op,lXOffset,lYOffset);
return S_OK;
}
STDMETHODIMP CCxImage::ShiftRGB(long r, long g, long b)
{
m_image.ShiftRGB(r,g,b);
return S_OK;
}
STDMETHODIMP CCxImage::Gamma(float gamma)
{
m_image.Gamma(gamma);
return S_OK;
}
STDMETHODIMP CCxImage::Median(long Ksize)
{
m_image.Median(Ksize);
return S_OK;
}
STDMETHODIMP CCxImage::Noise(long level)
{
m_image.Noise(level);
return S_OK;
}
STDMETHODIMP CCxImage::Histogram(VARIANT *red, VARIANT *green, VARIANT *blue, VARIANT *gray,ColorSpace colorspace)
{
long Reds[256], Greens[256], Blues[256], Grays[256];
SAFEARRAY *psaRed,*psaGreen,*psaBlue,*psaGray;
SAFEARRAYBOUND rgsabound[1]; CComVariant v;
rgsabound[0].lLbound = 0; rgsabound[0].cElements = 256;
m_image.Histogram(Reds,Greens,Blues,Grays,colorspace);
psaRed = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
psaGreen = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
psaBlue = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
psaGray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
v.vt = VT_I4;
for(long i=0; i<256; i++) {
v.lVal = Reds[i]; SafeArrayPutElement(psaRed,&i,&v);
v.lVal = Greens[i]; SafeArrayPutElement(psaGreen,&i,&v);
v.lVal = Blues[i]; SafeArrayPutElement(psaBlue,&i,&v);
v.lVal = Grays[i]; SafeArrayPutElement(psaGray,&i,&v);
}
// put data in variant
red->vt = green->vt = blue->vt = gray->vt = (VT_ARRAY | VT_VARIANT);
red->parray = psaRed; green->parray = psaGreen; blue->parray = psaBlue; gray->parray = psaGray;
return S_OK;
}
STDMETHODIMP CCxImage::FFT2(LPDISPATCH srcReal, LPDISPATCH srcImag, LPDISPATCH dstReal, LPDISPATCH dstImag, TransformDirection direction, VARIANT_BOOL bForceFFT, VARIANT_BOOL bMagnitude)
{
CxImage *pSrcReal = GetCxImageFromIDispatch(srcReal);
CxImage *pSrcImag = GetCxImageFromIDispatch(srcImag);
CxImage *pDstReal = GetCxImageFromIDispatch(dstReal);
CxImage *pDstImag = GetCxImageFromIDispatch(dstImag);
m_image.FFT2(pSrcReal,pSrcImag,pDstReal,pDstImag,direction,bForceFFT,bMagnitude);
return S_OK;
}
STDMETHODIMP CCxImage::Combine(LPDISPATCH r, LPDISPATCH g, LPDISPATCH b, LPDISPATCH a, ColorSpace colorspace)
{
CxImage *pR = GetCxImageFromIDispatch(r);
CxImage *pG = GetCxImageFromIDispatch(g);
CxImage *pB = GetCxImageFromIDispatch(b);
CxImage *pA = GetCxImageFromIDispatch(a);
m_image.Combine(pR,pG,pB,pA,colorspace);
return S_OK;
}
STDMETHODIMP CCxImage::Repair(float radius, long niterations, ColorSpace colorspace)
{
m_image.Repair(radius,niterations,(long)colorspace);
return S_OK;
}
STDMETHODIMP CCxImage::Draw(long hDC, long xoffset, long yoffset, long xsize, long ysize)
{
m_image.Draw((HDC)hDC, xoffset, yoffset, xsize, ysize);
return S_OK;
}
STDMETHODIMP CCxImage::Draw2(long hDC, long xoffset, long yoffset, long xsize, long ysize)
{
m_image.Draw2((HDC)hDC, xoffset, yoffset, xsize, ysize);
return S_OK;
}
STDMETHODIMP CCxImage::Stretch(long hDC, long xoffset, long yoffset, long xsize, long ysize)
{
m_image.Stretch((HDC)hDC, xoffset, yoffset, xsize, ysize);
return S_OK;
}
STDMETHODIMP CCxImage::Tile(long hDC, long x, long y, long xsize, long ysize)
{
RECT r;
r.left = x; r.top = y; r.right = x+xsize; r.bottom = y+ysize;
m_image.Tile((HDC)hDC, &r);
return S_OK;
}
// Only for CE
STDMETHODIMP CCxImage::Blt(long hDC, long x, long y)
{
// m_image.Blt((HDC)hDC, x, y);
return S_OK;
}
STDMETHODIMP CCxImage::GetTransIndex(long *index)
{
*index = m_image.GetTransIndex();
return S_OK;
}
STDMETHODIMP CCxImage::GetTransColor(OLE_COLOR *color)
{
*color = RGBQUAD2OLE_COLOR(m_image.GetTransColor());
return S_OK;
}
STDMETHODIMP CCxImage::SetTransColor(OLE_COLOR rgb)
{
m_image.SetTransColor(OLE_COLOR2RGBQUAD(rgb));
return S_OK;
}
STDMETHODIMP CCxImage::IsTransparent(VARIANT_BOOL *IsTrans)
{
*IsTrans = m_image.IsTransparent() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::SetTransIndex(long idx)
{
m_image.SetTransIndex(idx);
return S_OK;
}
STDMETHODIMP CCxImage::GetPaletteSize(long *palsize)
{
*palsize = m_image.GetPaletteSize();
return S_OK;
}
STDMETHODIMP CCxImage::GetRGB(long idx, long *r, long *g, long *b)
{
BYTE br,bg,bb;
m_image.GetRGB(idx, &br, &bg, &bb);
*r = br; *g = bg; *b = bb;
return S_OK;
}
STDMETHODIMP CCxImage::GetPaletteColor(long idx, OLE_COLOR *color)
{
*color = RGBQUAD2OLE_COLOR(m_image.GetPaletteColor((BYTE)idx));
return S_OK;
}
STDMETHODIMP CCxImage::SetPaletteIndex(long idx, OLE_COLOR c)
{
m_image.SetPaletteIndex((BYTE)idx,(COLORREF)c);
return S_OK;
}
STDMETHODIMP CCxImage::SetGrayPalette()
{
m_image.SetGrayPalette();
return S_OK;
}
STDMETHODIMP CCxImage::BlendPalette(OLE_COLOR c, long perc)
{
m_image.BlendPalette(c,perc);
return S_OK;
}
STDMETHODIMP CCxImage::IsGrayScale(VARIANT_BOOL *isgray)
{
*isgray = m_image.IsGrayScale() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::IsIndexed(VARIANT_BOOL *isind)
{
*isind = m_image.IsIndexed() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::SwapIndex(long idx1, long idx2)
{
m_image.SwapIndex((BYTE)idx1, (BYTE)idx2);
return S_OK;
}
STDMETHODIMP CCxImage::SetStdPalette()
{
m_image.SetStdPalette();
return S_OK;
}
STDMETHODIMP CCxImage::HuePalette(float correction)
{
m_image.HuePalette(correction);
return S_OK;
}
STDMETHODIMP CCxImage::HSLtoRGB(OLE_COLOR cHSLColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.HSLtoRGB(OLE_COLOR2RGBQUAD(cHSLColor)));
return S_OK;
}
STDMETHODIMP CCxImage::RGBtoHSL(OLE_COLOR cRGBColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.RGBtoHSL(OLE_COLOR2RGBQUAD(cRGBColor)));
return S_OK;
}
STDMETHODIMP CCxImage::YUVtoRGB(OLE_COLOR cYUVColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.YUVtoRGB(OLE_COLOR2RGBQUAD(cYUVColor)));
return S_OK;
}
STDMETHODIMP CCxImage::RGBtoYUV(OLE_COLOR cRGBColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.RGBtoYUV(OLE_COLOR2RGBQUAD(cRGBColor)));
return S_OK;
}
STDMETHODIMP CCxImage::YIQtoRGB(OLE_COLOR cYIQColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.YIQtoRGB(OLE_COLOR2RGBQUAD(cYIQColor)));
return S_OK;
}
STDMETHODIMP CCxImage::RGBtoYIQ(OLE_COLOR cRGBColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.RGBtoYIQ(OLE_COLOR2RGBQUAD(cRGBColor)));
return S_OK;
}
STDMETHODIMP CCxImage::XYZtoRGB(OLE_COLOR cXYZColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.XYZtoRGB(OLE_COLOR2RGBQUAD(cXYZColor)));
return S_OK;
}
STDMETHODIMP CCxImage::RGBtoXYZ(OLE_COLOR cRGBColor, OLE_COLOR *cOutColor)
{
*cOutColor = RGBQUAD2OLE_COLOR(m_image.RGBtoXYZ(OLE_COLOR2RGBQUAD(cRGBColor)));
return S_OK;
}
STDMETHODIMP CCxImage::IsInside(long x,long y,VARIANT_BOOL *isin)
{
*isin = m_image.IsInside(x,y) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::GetPixelColor(long x, long y, OLE_COLOR *cColor)
{
*cColor = RGBQUAD2OLE_COLOR(m_image.GetPixelColor(x,y));
return S_OK;
}
STDMETHODIMP CCxImage::SetPixelIndex(long x, long y, long i)
{
m_image.SetPixelIndex(x,y, (BYTE)i);
return S_OK;
}
STDMETHODIMP CCxImage::SetPixelColor(long x, long y, OLE_COLOR c)
{
m_image.SetPixelColor(x,y,c);
return S_OK;
}
STDMETHODIMP CCxImage::AlphaCreate()
{
m_image.AlphaCreate();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaDelete()
{
m_image.AlphaDelete();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaClear()
{
m_image.AlphaClear();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaInvert()
{
m_image.AlphaInvert();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaMirror()
{
m_image.AlphaMirror();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaFlip()
{
m_image.AlphaFlip();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaCopy(LPDISPATCH from)
{
CxImage *pFrom = GetCxImageFromIDispatch(from);
m_image.AlphaCopy(*pFrom);
return S_OK;
}
STDMETHODIMP CCxImage::AlphaStrip()
{
m_image.AlphaStrip();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaSplit(LPDISPATCH dest)
{
CxImage *pDest = GetCxImageFromIDispatch(dest);
m_image.AlphaSplit(pDest);
return S_OK;
}
STDMETHODIMP CCxImage::AlphaSetAll(long level)
{
m_image.AlphaSet((BYTE)level);
return S_OK;
}
STDMETHODIMP CCxImage::AlphaSet(long x, long y, long level)
{
m_image.AlphaSet(x,y,(BYTE)level);
return S_OK;
}
STDMETHODIMP CCxImage::AlphaGet(long x, long y, long *level)
{
BYTE blevel = m_image.AlphaGet(x,y);
*level = blevel;
return S_OK;
}
STDMETHODIMP CCxImage::AlphaGetMax(long *level)
{
BYTE bmax = m_image.AlphaGetMax();
*level = bmax;
return S_OK;
}
STDMETHODIMP CCxImage::AlphaSetMax(long nAlphaMax)
{
m_image.AlphaSetMax((BYTE)nAlphaMax);
return S_OK;
}
STDMETHODIMP CCxImage::HasAlpha(VARIANT_BOOL *has)
{
*has = m_image.HasAlpha() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::AlphaPaletteClear()
{
m_image.AlphaPaletteClear();
return S_OK;
}
STDMETHODIMP CCxImage::AlphaPaletteEnable(VARIANT_BOOL enable)
{
m_image.AlphaPaletteEnable((bool)enable);
return S_OK;
}
STDMETHODIMP CCxImage::IsAlphaPaletteEnabled(VARIANT_BOOL *isenabled)
{
*isenabled = m_image.IsAlphaPaletteEnabled() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::HasAlphaPalette(VARIANT_BOOL *has)
{
*has = m_image.HasAlphaPalette() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CCxImage::GetSize(long *size)
{
*size = m_image.GetSize();
return S_OK;
}
STDMETHODIMP CCxImage::GetBits(long *pBits)
{
*pBits = (long)m_image.GetBits();
return S_OK;
}
STDMETHODIMP CCxImage::GetHeight(long *height)
{
*height = (long)m_image.GetHeight();
return S_OK;
}
STDMETHODIMP CCxImage::GetWidth(long *width)
{
*width = (long)m_image.GetWidth();
return S_OK;
}
STDMETHODIMP CCxImage::GetEffWidth(long *effw)
{
*effw = (long)m_image.GetEffWidth();
return S_OK;
}
STDMETHODIMP CCxImage::GetNumColors(long *num)
{
*num = (long)m_image.GetNumColors();
return S_OK;
}
STDMETHODIMP CCxImage::GetColorType(long *type)
{
*type = m_image.GetColorType();
return S_OK;
}
STDMETHODIMP CCxImage::GetBpp(long *bpp)
{
*bpp = m_image.GetBpp();
return S_OK;
}
STDMETHODIMP CCxImage::GetType(long *type)
{
*type = m_image.GetType();
return S_OK;
}
STDMETHODIMP CCxImage::GetLastError(BSTR *err)
{
USES_CONVERSION;
*err = ::SysAllocString(T2COLE(m_image.GetLastError()));
return S_OK;
}
STDMETHODIMP CCxImage::GetDIB(long *hDib)
{
*hDib = (long)m_image.GetDIB();
return S_OK;
}
STDMETHODIMP CCxImage::GetJpegQuality(long *level)
{
*level = m_image.GetJpegQuality();
return S_OK;
}
STDMETHODIMP CCxImage::SetJpegQuality(long level)
{
m_image.SetJpegQuality((BYTE)level);
return S_OK;
}
STDMETHODIMP CCxImage::GetXDPI(long *xdpi)
{
*xdpi = m_image.GetXDPI();
return S_OK;
}
STDMETHODIMP CCxImage::SetXDPI(long dpi)
{
m_image.SetXDPI(dpi);
return S_OK;
}
STDMETHODIMP CCxImage::GetYDPI(long *ydpi)
{
*ydpi = m_image.GetYDPI();
return S_OK;
}
STDMETHODIMP CCxImage::SetYDPI(long dpi)
{
m_image.SetYDPI(dpi);
return S_OK;
}
STDMETHODIMP CCxImage::GetOffset(long *x, long *y)
{
m_image.GetOffset(x,y);
return S_OK;
}
STDMETHODIMP CCxImage::SetOffset(long x, long y)
{
m_image.SetOffset(x,y);
return S_OK;
}
STDMETHODIMP CCxImage::MakeBitmap(long hDC, long *hBitmap)
{
*hBitmap = (long)m_image.MakeBitmap((HDC)hDC);
return S_OK;
}
STDMETHODIMP CCxImage::GetProgress(long *prog)
{
*prog = m_image.GetProgress();
return S_OK;
}
STDMETHODIMP CCxImage::GetEscape(long *esc)
{
*esc = m_image.GetEscape();
return S_OK;
}
STDMETHODIMP CCxImage::SetProgress(long nProgress)
{
m_image.SetProgress(nProgress);
return S_OK;
}
STDMETHODIMP CCxImage::SetEscape(long esc)
{
m_image.SetEscape(esc);
return S_OK;
}
STDMETHODIMP CCxImage::GetVersion(BSTR *ver)
{
USES_CONVERSION;
*ver = ::SysAllocString(T2COLE(m_image.GetVersion()));
return S_OK;
}
// hidden method to access wrapped pointer
STDMETHODIMP CCxImage::GetCxImagePtr(long *ptr)
{
*ptr = (long)&m_image;
return S_OK;
}
// our method to display in ASP pages
STDMETHODIMP CCxImage::ImageForASP(long ImageType, long Quality,VARIANT *ImageData)
{
SAFEARRAY *psaData; BYTE *pData,*pBuffer; long size;
SAFEARRAYBOUND rgsabound[1];
m_image.SetJpegQuality((BYTE)Quality);
CxMemFile memfile; memfile.Open();
bool bOk = m_image.Encode(&memfile, ImageType);
if(!bOk) return E_FAIL; // NO-IMAGE
pBuffer=memfile.GetBuffer();
size=memfile.Size();
// create safe array and copy image data
rgsabound[0].lLbound = 0; rgsabound[0].cElements = size;
psaData = SafeArrayCreate(VT_UI1, 1, rgsabound);
SafeArrayAccessData(psaData, (void **)&pData);
memcpy(pData,pBuffer,size);
SafeArrayUnaccessData(psaData);
free(pBuffer);
// put data in variant
ImageData->vt = (VT_ARRAY | VT_UI1);
ImageData->parray = psaData;
return S_OK;
}