diff options
Diffstat (limited to 'plugins/pluginWinDD/internals/DuplicationManager.cxx')
-rwxr-xr-x | plugins/pluginWinDD/internals/DuplicationManager.cxx | 393 |
1 files changed, 174 insertions, 219 deletions
diff --git a/plugins/pluginWinDD/internals/DuplicationManager.cxx b/plugins/pluginWinDD/internals/DuplicationManager.cxx index 995c8ec..34ec896 100755 --- a/plugins/pluginWinDD/internals/DuplicationManager.cxx +++ b/plugins/pluginWinDD/internals/DuplicationManager.cxx @@ -12,24 +12,24 @@ #include <Mfapi.h> static inline HRESULT CopyRGBb32DownTop( - BYTE* pDst, - const BYTE* pSrc, - INT dwWidthDstPixels, - INT dwWidthSrcPixels, - INT dwHeightPixels - ); + BYTE* pDst, + const BYTE* pSrc, + INT dwWidthDstPixels, + INT dwWidthSrcPixels, + INT dwHeightPixels +); // // Constructor sets up references / variables // DUPLICATIONMANAGER::DUPLICATIONMANAGER() : m_DeskDupl(nullptr), - m_AcquiredDesktopImage(nullptr), - m_MetaDataBuffer(nullptr), - m_MetaDataSize(0), - m_OutputNumber(0), - m_Device(nullptr), - m_DeviceContext(nullptr), - m_BufferPtr(nullptr), - m_BufferSize(0) + m_AcquiredDesktopImage(nullptr), + m_MetaDataBuffer(nullptr), + m_MetaDataSize(0), + m_OutputNumber(0), + m_Device(nullptr), + m_DeviceContext(nullptr), + m_BufferPtr(nullptr), + m_BufferSize(0) { RtlZeroMemory(&m_OutputDesc, sizeof(m_OutputDesc)); } @@ -39,41 +39,35 @@ DUPLICATIONMANAGER::DUPLICATIONMANAGER() : m_DeskDupl(nullptr), // DUPLICATIONMANAGER::~DUPLICATIONMANAGER() { - if (m_DeskDupl) - { + if (m_DeskDupl) { m_DeskDupl->Release(); m_DeskDupl = nullptr; } - if (m_AcquiredDesktopImage) - { + if (m_AcquiredDesktopImage) { m_AcquiredDesktopImage->Release(); m_AcquiredDesktopImage = nullptr; } - if (m_MetaDataBuffer) - { + if (m_MetaDataBuffer) { delete [] m_MetaDataBuffer; m_MetaDataBuffer = nullptr; } - if (m_DeviceContext) - { - m_DeviceContext->Release(); - m_DeviceContext = nullptr; - } + if (m_DeviceContext) { + m_DeviceContext->Release(); + m_DeviceContext = nullptr; + } - if (m_Device) - { + if (m_Device) { m_Device->Release(); m_Device = nullptr; } - if (m_BufferPtr) - { - VirtualFree(m_BufferPtr, 0, MEM_RELEASE); - m_BufferPtr = nullptr; - } + if (m_BufferPtr) { + VirtualFree(m_BufferPtr, 0, MEM_RELEASE); + m_BufferPtr = nullptr; + } } // @@ -87,14 +81,13 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device m_Device = Device; m_Device->AddRef(); - m_DeviceContext = DeviceContext; - m_DeviceContext->AddRef(); + m_DeviceContext = DeviceContext; + m_DeviceContext->AddRef(); // Get DXGI device IDXGIDevice* DxgiDevice = nullptr; HRESULT hr = m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice)); - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(nullptr, L"Failed to QI for DXGI Device", L"Error", hr); } @@ -103,8 +96,7 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter)); DxgiDevice->Release(); DxgiDevice = nullptr; - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to get parent DXGI Adapter", L"Error", hr, SystemTransitionsExpectedErrors); } @@ -113,8 +105,7 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device hr = DxgiAdapter->EnumOutputs(Output, &DxgiOutput); DxgiAdapter->Release(); DxgiAdapter = nullptr; - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to get specified output in DUPLICATIONMANAGER", L"Error", hr, EnumOutputsExpectedErrors); } @@ -125,8 +116,7 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device hr = DxgiOutput->QueryInterface(__uuidof(DxgiOutput1), reinterpret_cast<void**>(&DxgiOutput1)); DxgiOutput->Release(); DxgiOutput = nullptr; - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(nullptr, L"Failed to QI for DxgiOutput1 in DUPLICATIONMANAGER", L"Error", hr); } @@ -134,10 +124,8 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl); DxgiOutput1->Release(); DxgiOutput1 = nullptr; - if (FAILED(hr)) - { - if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) - { + if (FAILED(hr)) { + if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { MessageBoxW(nullptr, L"There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again.", L"Error", MB_OK); return DUPL_RETURN_ERROR_UNEXPECTED; } @@ -153,8 +141,7 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, ID3D11Device DUPL_RETURN DUPLICATIONMANAGER::GetMouse(_Inout_ PTR_INFO* PtrInfo, _In_ DXGI_OUTDUPL_FRAME_INFO* FrameInfo, INT OffsetX, INT OffsetY) { // A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change - if (FrameInfo->LastMouseUpdateTime.QuadPart == 0) - { + if (FrameInfo->LastMouseUpdateTime.QuadPart == 0) { return DUPL_RETURN_SUCCESS; } @@ -163,20 +150,17 @@ DUPL_RETURN DUPLICATIONMANAGER::GetMouse(_Inout_ PTR_INFO* PtrInfo, _In_ DXGI_OU // Make sure we don't update pointer position wrongly // If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer // was visible, if so, don't set it to invisible or update. - if (!FrameInfo->PointerPosition.Visible && (PtrInfo->WhoUpdatedPositionLast != m_OutputNumber)) - { + if (!FrameInfo->PointerPosition.Visible && (PtrInfo->WhoUpdatedPositionLast != m_OutputNumber)) { UpdatePosition = false; } // If two outputs both say they have a visible, only update if new update has newer timestamp - if (FrameInfo->PointerPosition.Visible && PtrInfo->Visible && (PtrInfo->WhoUpdatedPositionLast != m_OutputNumber) && (PtrInfo->LastTimeStamp.QuadPart > FrameInfo->LastMouseUpdateTime.QuadPart)) - { + if (FrameInfo->PointerPosition.Visible && PtrInfo->Visible && (PtrInfo->WhoUpdatedPositionLast != m_OutputNumber) && (PtrInfo->LastTimeStamp.QuadPart > FrameInfo->LastMouseUpdateTime.QuadPart)) { UpdatePosition = false; } // Update position - if (UpdatePosition) - { + if (UpdatePosition) { PtrInfo->Position.x = FrameInfo->PointerPosition.Position.x + m_OutputDesc.DesktopCoordinates.left - OffsetX; PtrInfo->Position.y = FrameInfo->PointerPosition.Position.y + m_OutputDesc.DesktopCoordinates.top - OffsetY; PtrInfo->WhoUpdatedPositionLast = m_OutputNumber; @@ -185,22 +169,18 @@ DUPL_RETURN DUPLICATIONMANAGER::GetMouse(_Inout_ PTR_INFO* PtrInfo, _In_ DXGI_OU } // No new shape - if (FrameInfo->PointerShapeBufferSize == 0) - { + if (FrameInfo->PointerShapeBufferSize == 0) { return DUPL_RETURN_SUCCESS; } // Old buffer too small - if (FrameInfo->PointerShapeBufferSize > PtrInfo->BufferSize) - { - if (PtrInfo->PtrShapeBuffer) - { + if (FrameInfo->PointerShapeBufferSize > PtrInfo->BufferSize) { + if (PtrInfo->PtrShapeBuffer) { delete [] PtrInfo->PtrShapeBuffer; PtrInfo->PtrShapeBuffer = nullptr; } PtrInfo->PtrShapeBuffer = new (std::nothrow) BYTE[FrameInfo->PointerShapeBufferSize]; - if (!PtrInfo->PtrShapeBuffer) - { + if (!PtrInfo->PtrShapeBuffer) { PtrInfo->BufferSize = 0; return ProcessFailure(nullptr, L"Failed to allocate memory for pointer shape in DUPLICATIONMANAGER", L"Error", E_OUTOFMEMORY); } @@ -212,8 +192,7 @@ DUPL_RETURN DUPLICATIONMANAGER::GetMouse(_Inout_ PTR_INFO* PtrInfo, _In_ DXGI_OU // Get shape UINT BufferSizeRequired; HRESULT hr = m_DeskDupl->GetFramePointerShape(FrameInfo->PointerShapeBufferSize, reinterpret_cast<VOID*>(PtrInfo->PtrShapeBuffer), &BufferSizeRequired, &(PtrInfo->ShapeInfo)); - if (FAILED(hr)) - { + if (FAILED(hr)) { delete [] PtrInfo->PtrShapeBuffer; PtrInfo->PtrShapeBuffer = nullptr; PtrInfo->BufferSize = 0; @@ -235,21 +214,18 @@ DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Tim // Get new frame HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource); - if (hr == DXGI_ERROR_WAIT_TIMEOUT) - { + if (hr == DXGI_ERROR_WAIT_TIMEOUT) { *Timeout = true; return DUPL_RETURN_SUCCESS; } *Timeout = false; - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to acquire next frame in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); } // If still holding old frame, destroy it - if (m_AcquiredDesktopImage) - { + if (m_AcquiredDesktopImage) { m_AcquiredDesktopImage->Release(); m_AcquiredDesktopImage = nullptr; } @@ -258,25 +234,20 @@ DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Tim hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage)); DesktopResource->Release(); DesktopResource = nullptr; - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(nullptr, L"Failed to QI for ID3D11Texture2D from acquired IDXGIResource in DUPLICATIONMANAGER", L"Error", hr); } // Get metadata - if (FrameInfo.TotalMetadataBufferSize) - { + if (FrameInfo.TotalMetadataBufferSize) { // Old buffer too small - if (FrameInfo.TotalMetadataBufferSize > m_MetaDataSize) - { - if (m_MetaDataBuffer) - { + if (FrameInfo.TotalMetadataBufferSize > m_MetaDataSize) { + if (m_MetaDataBuffer) { delete [] m_MetaDataBuffer; m_MetaDataBuffer = nullptr; } m_MetaDataBuffer = new (std::nothrow) BYTE[FrameInfo.TotalMetadataBufferSize]; - if (!m_MetaDataBuffer) - { + if (!m_MetaDataBuffer) { m_MetaDataSize = 0; Data->MoveCount = 0; Data->DirtyCount = 0; @@ -289,8 +260,7 @@ DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Tim // Get move rectangles hr = m_DeskDupl->GetFrameMoveRects(BufSize, reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(m_MetaDataBuffer), &BufSize); - if (FAILED(hr)) - { + if (FAILED(hr)) { Data->MoveCount = 0; Data->DirtyCount = 0; return ProcessFailure(nullptr, L"Failed to get frame move rects in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); @@ -302,8 +272,7 @@ DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Tim // Get dirty rectangles hr = m_DeskDupl->GetFrameDirtyRects(BufSize, reinterpret_cast<RECT*>(DirtyRects), &BufSize); - if (FAILED(hr)) - { + if (FAILED(hr)) { Data->MoveCount = 0; Data->DirtyCount = 0; return ProcessFailure(nullptr, L"Failed to get frame dirty rects in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); @@ -325,13 +294,11 @@ DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Tim DUPL_RETURN DUPLICATIONMANAGER::DoneWithFrame() { HRESULT hr = m_DeskDupl->ReleaseFrame(); - if (FAILED(hr)) - { + if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to release frame in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); } - if (m_AcquiredDesktopImage) - { + if (m_AcquiredDesktopImage) { m_AcquiredDesktopImage->Release(); m_AcquiredDesktopImage = nullptr; } @@ -350,150 +317,138 @@ void DUPLICATIONMANAGER::GetOutputDesc(_Out_ DXGI_OUTPUT_DESC* DescPtr) HRESULT DUPLICATIONMANAGER::SendData(struct tmedia_producer_s* pProducer, FRAME_DATA* FrameData) { - HRESULT hr = E_FAIL; - D3D11_TEXTURE2D_DESC CopyBufferDesc = {0}; - D3D11_TEXTURE2D_DESC FullDesc; - DXGI_MAPPED_RECT MappedSurface; - D3D11_BOX Box; - UINT BuffSize; - - ID3D11Texture2D* CopyBuffer = nullptr; - IDXGISurface* CopySurface = nullptr; - ID3D11Device* Device = nullptr; - - FrameData->Frame->GetDesc(&FullDesc); - - CopyBufferDesc.Width = FullDesc.Width; - CopyBufferDesc.Height = FullDesc.Height; - CopyBufferDesc.MipLevels = 1; - CopyBufferDesc.ArraySize = 1; - CopyBufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - CopyBufferDesc.SampleDesc.Count = 1; - CopyBufferDesc.SampleDesc.Quality = 0; - CopyBufferDesc.Usage = D3D11_USAGE_STAGING; - CopyBufferDesc.BindFlags = 0; - CopyBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - CopyBufferDesc.MiscFlags = 0; - - FrameData->Frame->GetDevice(&Device); - if (!Device) - { - hr = E_POINTER; - ProcessFailure(m_Device, L"Failed to get device", L"Error", hr, SystemTransitionsExpectedErrors); - goto bail; - } - - hr = Device->CreateTexture2D(&CopyBufferDesc, nullptr, &CopyBuffer); - if (FAILED(hr)) - { - ProcessFailure(m_Device, L"Failed creating staging texture for pointer", L"Error", hr, SystemTransitionsExpectedErrors); - goto bail; - } - - Box.left = 0; - Box.top = 0; - Box.right = CopyBufferDesc.Width; - Box.bottom = CopyBufferDesc.Height; - Box.front = 0; - Box.back = 1; - m_DeviceContext->CopySubresourceRegion(CopyBuffer, 0, 0, 0, 0, FrameData->Frame, 0, &Box); - - hr = CopyBuffer->QueryInterface(__uuidof(IDXGISurface), (void **)&CopySurface); - if (FAILED(hr)) - { - ProcessFailure(nullptr, L"Failed to QI staging texture into IDXGISurface for pointer", L"Error", hr, SystemTransitionsExpectedErrors); - goto bail; - } - - BuffSize = CopyBufferDesc.Width * CopyBufferDesc.Height * 4; - if (m_BufferSize < BuffSize) - { - if (m_BufferPtr) - { - VirtualFree(m_BufferPtr, 0, MEM_RELEASE); - m_BufferSize = 0; - } - if (!(m_BufferPtr = (BYTE*)VirtualAlloc(NULL, BuffSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) - { - ProcessFailure(Device, L"Failed to allocate memory", L"Error", hr, SystemTransitionsExpectedErrors); - goto bail; - } - m_BufferSize = BuffSize; - } - - hr = CopySurface->Map(&MappedSurface, DXGI_MAP_READ); // *** MAP *** // - if (FAILED(hr)) - { - ProcessFailure(Device, L"Failed to map surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors); - goto bail; - } - - pProducer->video.width = CopyBufferDesc.Width; - pProducer->video.height = CopyBufferDesc.Height; + HRESULT hr = E_FAIL; + D3D11_TEXTURE2D_DESC CopyBufferDesc = {0}; + D3D11_TEXTURE2D_DESC FullDesc; + DXGI_MAPPED_RECT MappedSurface; + D3D11_BOX Box; + UINT BuffSize; + + ID3D11Texture2D* CopyBuffer = nullptr; + IDXGISurface* CopySurface = nullptr; + ID3D11Device* Device = nullptr; + + FrameData->Frame->GetDesc(&FullDesc); + + CopyBufferDesc.Width = FullDesc.Width; + CopyBufferDesc.Height = FullDesc.Height; + CopyBufferDesc.MipLevels = 1; + CopyBufferDesc.ArraySize = 1; + CopyBufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + CopyBufferDesc.SampleDesc.Count = 1; + CopyBufferDesc.SampleDesc.Quality = 0; + CopyBufferDesc.Usage = D3D11_USAGE_STAGING; + CopyBufferDesc.BindFlags = 0; + CopyBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + CopyBufferDesc.MiscFlags = 0; + + FrameData->Frame->GetDevice(&Device); + if (!Device) { + hr = E_POINTER; + ProcessFailure(m_Device, L"Failed to get device", L"Error", hr, SystemTransitionsExpectedErrors); + goto bail; + } + + hr = Device->CreateTexture2D(&CopyBufferDesc, nullptr, &CopyBuffer); + if (FAILED(hr)) { + ProcessFailure(m_Device, L"Failed creating staging texture for pointer", L"Error", hr, SystemTransitionsExpectedErrors); + goto bail; + } + + Box.left = 0; + Box.top = 0; + Box.right = CopyBufferDesc.Width; + Box.bottom = CopyBufferDesc.Height; + Box.front = 0; + Box.back = 1; + m_DeviceContext->CopySubresourceRegion(CopyBuffer, 0, 0, 0, 0, FrameData->Frame, 0, &Box); + + hr = CopyBuffer->QueryInterface(__uuidof(IDXGISurface), (void **)&CopySurface); + if (FAILED(hr)) { + ProcessFailure(nullptr, L"Failed to QI staging texture into IDXGISurface for pointer", L"Error", hr, SystemTransitionsExpectedErrors); + goto bail; + } + + BuffSize = CopyBufferDesc.Width * CopyBufferDesc.Height * 4; + if (m_BufferSize < BuffSize) { + if (m_BufferPtr) { + VirtualFree(m_BufferPtr, 0, MEM_RELEASE); + m_BufferSize = 0; + } + if (!(m_BufferPtr = (BYTE*)VirtualAlloc(NULL, BuffSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) { + ProcessFailure(Device, L"Failed to allocate memory", L"Error", hr, SystemTransitionsExpectedErrors); + goto bail; + } + m_BufferSize = BuffSize; + } + + hr = CopySurface->Map(&MappedSurface, DXGI_MAP_READ); // *** MAP *** // + if (FAILED(hr)) { + ProcessFailure(Device, L"Failed to map surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors); + goto bail; + } + + pProducer->video.width = CopyBufferDesc.Width; + pProducer->video.height = CopyBufferDesc.Height; #if 0 - hr = MFCopyImage( - m_BufferPtr, - (LONG)(CopyBufferDesc.Width << 2), - (BYTE*)MappedSurface.pBits, - (LONG)MappedSurface.Pitch, - (DWORD)(CopyBufferDesc.Width << 2), - (DWORD)CopyBufferDesc.Height - ); + hr = MFCopyImage( + m_BufferPtr, + (LONG)(CopyBufferDesc.Width << 2), + (BYTE*)MappedSurface.pBits, + (LONG)MappedSurface.Pitch, + (DWORD)(CopyBufferDesc.Width << 2), + (DWORD)CopyBufferDesc.Height + ); #else; - hr = CopyRGBb32DownTop( - m_BufferPtr, - MappedSurface.pBits, - CopyBufferDesc.Width, - (MappedSurface.Pitch >> 2), // Bytes -> Pixels - CopyBufferDesc.Height); + hr = CopyRGBb32DownTop( + m_BufferPtr, + MappedSurface.pBits, + CopyBufferDesc.Width, + (MappedSurface.Pitch >> 2), // Bytes -> Pixels + CopyBufferDesc.Height); #endif - pProducer->enc_cb.callback(pProducer->enc_cb.callback_data, m_BufferPtr, BuffSize); + pProducer->enc_cb.callback(pProducer->enc_cb.callback_data, m_BufferPtr, BuffSize); - CopySurface->Unmap(); // *** UNMAP *** // + CopySurface->Unmap(); // *** UNMAP *** // bail: - if (CopyBuffer) - { - CopyBuffer->Release(); - } - if (CopySurface) - { - CopySurface->Release(); - } - if (Device) - { - Device->Release(); - } - return hr; + if (CopyBuffer) { + CopyBuffer->Release(); + } + if (CopySurface) { + CopySurface->Release(); + } + if (Device) { + Device->Release(); + } + return hr; } // For RGB32: // Direct3D -> Top-Down // Video Processor -> Down-Top static inline HRESULT CopyRGBb32DownTop( - BYTE* pDst, - const BYTE* pSrc, - INT dwWidthDstPixels, - INT dwWidthSrcPixels, - INT dwHeightPixels - ) + BYTE* pDst, + const BYTE* pSrc, + INT dwWidthDstPixels, + INT dwWidthSrcPixels, + INT dwHeightPixels +) { - RGBQUAD *pSrcPixel = &((RGBQUAD*)pSrc)[(dwWidthSrcPixels * dwHeightPixels) - dwWidthSrcPixels]; - RGBQUAD *pDestPixel = &((RGBQUAD*)pDst)[0]; - - register INT x; - register INT y; - - for (y = dwHeightPixels; y > 0; --y) - { - for (x = 0; x < dwWidthDstPixels; ++x) - { - pDestPixel[x] = pSrcPixel[x]; - } - pDestPixel += dwWidthDstPixels; - pSrcPixel -= dwWidthSrcPixels; - } - return S_OK; + RGBQUAD *pSrcPixel = &((RGBQUAD*)pSrc)[(dwWidthSrcPixels * dwHeightPixels) - dwWidthSrcPixels]; + RGBQUAD *pDestPixel = &((RGBQUAD*)pDst)[0]; + + register INT x; + register INT y; + + for (y = dwHeightPixels; y > 0; --y) { + for (x = 0; x < dwWidthDstPixels; ++x) { + pDestPixel[x] = pSrcPixel[x]; + } + pDestPixel += dwWidthDstPixels; + pSrcPixel -= dwWidthSrcPixels; + } + return S_OK; }
\ No newline at end of file |