none
Desktop Duplication API - Получение серии скриншотов с экрана

    Вопрос

  • Представляю свой исходник: https://pastebin.com/JCYPtd5j

    К сожалению, не могу его никак отладить. Получается пустая картинка.
    Как зациклить тоже не знаю. По идее, логично было бы начать цикл с вызова AcquireNextFrame, но на второй итерации это приведёт к выбросу исключения.

    Прошу помочь разобраться. Язык - C++ CLI (издержки конечного проекта).

    11 сентября 2017 г. 14:02

Все ответы

  • Не работает, потому что запроса одного кадра недостаточно. Один кадр не обязан содержать всю необходимую информацию: он может содержать только позицию указателя к примеру, а само изображение идет в следующем кадре. См. https://msdn.microsoft.com/en-us/library/windows/desktop/hh404615(v=vs.85).aspx

    Поэтому нужно в цикле сохранять кадры, а потом уже думать, как из них собрать все что нужно. А чтобы получить следующий кадр без исключения, нужно правильно освобождать ресурсы. Как-то так:

    ID3D11Texture2D* AcquiredDesktopImage = nullptr;
    
    IDXGIResource* DesktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo;
    HBITMAP hBmp;
    Int32 num=0;
    
    while(true)
    {
    
    	// If still holding old frame, destroy it.
    	if (AcquiredDesktopImage)
    	{
    		AcquiredDesktopImage->Release();
    		AcquiredDesktopImage = nullptr;
    	}
    
    	// Get new frame.
    	hr = DeskDupl->AcquireNextFrame(5000, &FrameInfo, &DesktopResource);
    	if (FAILED(hr))
        	{
    		if(hr == DXGI_ERROR_ACCESS_LOST)
    		{
    			Console::WriteLine("DXGI_ERROR_ACCESS_LOST");
    		}
    		else if(hr==DXGI_ERROR_WAIT_TIMEOUT)
    		{
    			Console::WriteLine("DXGI_ERROR_WAIT_TIMEOUT");
    		}
                    else
                    {
    			Console::WriteLine("Failed to acquire next frame: 0x"+Convert::ToString(hr,16));
    		}
    		Console::ReadKey();
    		continue;
        	}
    	
    
    	// Query interface for IDXGIResource.
    	hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&AcquiredDesktopImage));
    	DesktopResource->Release();
    	DesktopResource = nullptr;
    	EXIT(hr);
    
    	hBmp = (HBITMAP)ExtractBitmap(AcquiredDesktopImage, pDevice);
    
    	///////////////////////////////////////////////////////////////////////////
    	String ^ str="C:\\Images\\Screenshot";
    	str+=Convert::ToString(num);
    	str+=".bmp";
    	Console::WriteLine(Convert::ToString(num));
    
    	//save image to file
    	System::Drawing::Bitmap ^ bmp;
    	bmp=System::Drawing::Bitmap::FromHbitmap(IntPtr(hBmp));
    	bmp->Save(str);
    	delete bmp;//no longer need bitmap
    
    	hr = DeskDupl->ReleaseFrame();//no longer need the frame
        	if (FAILED(hr))
        	{
    		Console::WriteLine("Failed to release frame");
            	break;
        	}
    	
    	num++;
    	System::Threading::Thread::Sleep(2000);//wait some time for next frame
    		
    }

    Только что вы пытаетесь сделать? Для простого снимания скриншотов не обязательно приплетать DirectX. Можно наверно обойтись средствами GDI, скажем переносом BitBlt из одного DC в другой.


    • Изменено VadimTagil 13 сентября 2017 г. 15:40
    13 сентября 2017 г. 15:15