正常情况下,GetWindowDC(hwnd);然后BitBlt可以截图。如果这个窗口被其它窗口遮盖,又该如何截图呢?
网上很多资料说使用PrintWindow这个未公开的函数。想找到有没有其它的办法解决这个问题。

解决方案 »

  1.   

    PrintWindow非未公开的函数,参见msdn http://msdn.microsoft.com/en-us/library/dd162869(VS.85).aspx
      

  2.   

    PrintWindow是公开的函数,XP以上系统才有。以下摘自MSDN。PrintWindow
    The PrintWindow function copies a visual window into the specified device context (DC), typically a printer DC.BOOL PrintWindow(
      HWND hwnd,               // Window to copy
      HDC  hdcBlt,             // HDC to print into
      UINT nFlags              // Optional flags
    );Parameters
    hwnd 
    Handle to the window that will be copied. 
    hdcBlt 
    Handle to the device context. 
    nFlags 
    Specifies the drawing options. It can be one of the following values. Value Meaning 
    PW_CLIENTONLY Only the client area of the window is copied to hdcBlt. By default, the entire window is copied. 
    Return Values
    If the function succeeds, it returns a nonzero value.If the function fails, it returns zero.
      

  3.   

    http://www.fengyuan.com/article/wmprint.html
      

  4.   

    一个新的思路是在截屏之前,找到覆盖在被截屏窗口之上的所有窗口,然后给这些诶窗口设置透明属性(通过GWL_EXSTYLE和SetLayeredWindowAttrib之类的办法),截屏之后,再取消这些窗口的透明属性。
    按照这种思路实现时,的确可以成功截图,但是会产生严重的窗口闪烁现象。
    有没有人遇到过这种情况?
      

  5.   

    如LZ所说,可以使 窗口 置最顶(SetForegroundWindow)之后截屏,不过俺没试过,LZ可以试一试!
      

  6.   

    经过试验发现PrintWindow的确对很多窗口可以有效截屏,而且可以截取不在前台显示的窗口,甚至移动到屏幕外的窗口。
    怎么能防止自己的窗口被PrintWindow截取呢?
      

  7.   

    1、pUnknow=pWnd->GetControlUnknown();
    2、pUnknow->QueryInterface(IID_IViewObject2,(void**)&pViewObj);
    3、创建兼容DC dcCompatible,CRect vRt;
    4、pViewObj->Draw(DVASPECT_CONTENT,-1,NULL,NULL,0,m_dcCompatible,&vRt,0,NULL,0);如果IID_IViewObject2 不行就试下 ID_IViewObject
      

  8.   


    不建议,"闪"啊另外LZ"怎么能防止自己的窗口被PrintWindow截取呢",这个要处理得好那就是你的专利了, 现在电子章用到的技术大概就是这个
      

  9.   

    VISTA以前的系统,不好办。当被遮盖之后,被遮盖的部分就已经是clip region之外了,根本不会画出来。要么有什么未公开的API,要么就将窗口置顶,然后再截屏。
    VISTA以后的系统引入了DWM,所有的窗口都是画到了directx的一个surface上,所以VISTA任务栏上可以随时显示窗口缩略图。
      

  10.   

    今天了解了一种基于API HOOK的DirectDraw方式截图。
      

  11.   

    去搜索一下蒋老大的文章,通过HOOK窗口的重绘消息来实现
      

  12.   

    看样子vista还是好,但是为什么我们做程序的时候,一提到vista 老板就摇头呢?
      

  13.   

    我做了一个截图的:
    在启动截图的时候,
    查找所有可视窗口,在截图对话框中LISTBOX显示,
    用户可随意将被挡住窗口设置为顶部(在切换的过程中会闪一下),
    之后就很正常了.
    其原理很简单,就是先调整窗口,然后截图窗口再次截取全屏幕,并在截图窗口重新绘制.
      

  14.   

    Hook window proc 截获 WM_PAINT用自己的HDC代替然后试一试.
      

  15.   

    1.创建目标兼容DC hDC
    2.创建目标兼容BITMAP hBitmap
    3.SelectObject(hDC, hBitmap)
    4.SendMessage(hWndTarget, WM_PAINT, hDc, 0)
    5.ok
      

  16.   

    DirectDraw应用的窗口截图, 偶的方法基本上跟这个帖子中10楼提到的方法相似。
    http://topic.csdn.net/t/20061109/11/5144676.html>>>>>>
    如果在应用层做,你应该先找到DirectDraw的COM对象,比如可以通过  
      Hook   DriectDraw的创建函数xxxCreate(),得到DirectDraw之后,想  
      Hook   DreictDraw的那个函数都很容易。
    <<<<<<
      

  17.   

    自己提供一个DC,向这个窗口发送一个WM_PRINTCLIENT消息即可
      

  18.   

    具体调用关系:
    1>因为Hook了DirectDrawCreate这个API, 因此其它进程调用DirectDrawCreate时转入了咱们的XXXDirectDrawCreate。
    2>在XXXDirectDrawCreate中,通过XXX_get_vfuncaddr_createsurface获得IDirectDraw::CreateSurface方法的函数地址。
    3>此时可以Hook IDirectDraw::CreateSurface这个函数。
    4>在其它进程调用IDirectDraw::CreateSurface时,转入咱们的XXXIDirectDraw_CreateSurface、
    5>此时通过XXX_get_vfuncaddr_blt获得IDirectDrawSurface::Blt的函数地址。
    6>此时Hook IDirectDrawSurface::Blt这个函数。
    7>在咱们的XXXIDirectDrawSurface_Blt()函数中进行截屏。这里Blt是虚函数,没法通过NULL对象获得其函数地址,所以过程搞得复杂了点。
    //获取IDirectDraw接口的CreateSurface方法的实际函数地址。
    long  XXX_get_vfuncaddr_createsurface(LPDIRECTDRAW pDD)
    {
    if( !g_apiinited ) {
     g_apiinited = true;
     memset(&g_apicreatesurface,0,sizeof(XXXHookApi));
     memset(&g_apiblt,0,sizeof(XXXHookApi));
    } if( g_apicreatesurface.name.function) { return 0;}

    long * vtblDD = ( (long *)(* (long*)pDD) );
    memset(&g_apicreatesurface,0,sizeof(g_apicreatesurface));
    g_apicreatesurface.name.function = vtblDD[6];
    strcpy(g_apicreatesurface.name.olddll,"ddraw.dll");
    strcpy(g_apicreatesurface.name.newdll,"XXX.dll");
    strcpy(g_apicreatesurface.name.newname, "XXXIDirectDraw_CreateSurface");

    XXXHook  hook;
    hook.InitApi(&g_apicreatesurface);
    hook.InstallApi(&g_apicreatesurface); return 0;
    }
    //获取IDirectDrawSurface接口的Blt方法的实际函数地址。
    long  XXX_get_vfuncaddr_blt(LPDIRECTDRAWSURFACE pDS)
    {
    if( g_apiblt.name.function) { return 0;}
      
    long * vtbl = ( (long *)(* (long*)pDS) ); memset(&g_apiblt,0,sizeof(g_apiblt));
    g_apiblt.name.function = vtbl[5];
    strcpy(g_apiblt.name.olddll,"ddraw.dll");
    strcpy(g_apiblt.name.newdll,"XXX.dll");
    strcpy(g_apiblt.name.newname, "XXXIDirectDrawSurface_Blt");

    XXXHook  hook;
    hook.InitApi(&g_apiblt);
    hook.InstallApi(&g_apiblt); return 0;
    }
    //被替换的IDirectDraw::CreateSurface方法
    extern "C" HRESULT __stdcall XXXIDirectDraw_CreateSurface( LPDIRECTDRAW  p0,  LPDDSURFACEDESC p1, LPDIRECTDRAWSURFACE FAR * p2, IUnknown FAR * p3) 
    {
        XXXHook  hook;
    hook.UninstallApi(&g_apicreatesurface);
    XXX_log_trace("XXXIDirectDrawSurface_Blt called.\n"); if( ( DDSCAPS_OFFSCREENPLAIN & p1->ddsCaps.dwCaps) == DDSCAPS_OFFSCREENPLAIN ) {
      p1->ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
      p1->ddsCaps.dwCaps &= ~DDSCAPS_WRITEONLY;
      p1->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
    } HRESULT hr = p0->CreateSurface(p1,p2,p3);
    hook.InstallApi(&g_apicreatesurface); XXX_get_vfuncaddr_blt( *p2);
    return hr;
    }
    //被替换的IDirectDrawSurface::Blt方法。
    //窗口截屏在这里进行。
    extern "C" HRESULT __stdcall  XXXIDirectDrawSurface_Blt( LPDIRECTDRAWSURFACE  p0, LPRECT p1,LPDIRECTDRAWSURFACE p2, LPRECT p3,DWORD p4, LPDDBLTFX p5)  
    {
    XXXHook  hook;
    hook.UninstallApi(&g_apiblt);
    //XXX_log_trace("XXXIDirectDrawSurface_Blt called.\n");
    HRESULT hr = p0->Blt(p1,p2,p3,p4,p5);
    hook.InstallApi(&g_apiblt); ///////////COPY BITMAP DATA//////// if( p3->right-p3->left > 800 && p3->bottom-p3->top>600 ) {
    g_sc.CaptureSurface(p0, p2 );
    }
    return hr;}//被替换的DirectDrawCreate函数。
    extern "C" HRESULT WINAPI XXXDirectDrawCreate( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter )
    {

    XXXAutoHook  hook("DirectDrawCreate","ddraw.dll");
    XXX_log_trace("DirectDrawCreate called.\n");

    HRESULT hr = DirectDrawCreate(lpGUID, lplpDD, pUnkOuter);
    if(FAILED(hr)) { return hr;} XXX_get_vfuncaddr_createsurface( *lplpDD );
    return hr;

    }
      

  19.   

    Windows系统变化太大,程序员适应不了怎么办啊
      

  20.   

    拿到窗口句柄,然后发送 PRINT_CLIENT 消息,让它在你给的dc上面绘制,就ok乐。
      

  21.   

    QQ的连连看窗口PrintWindow出来的窗口没东西,难道做了屏蔽
      

  22.   

    本来想研究一下PrintWindow, 结果限于本人目前的水平,没有结果。 跟踪调试PrintWindow时发现反汇编中有一行: syscenter。直接就跳到目标窗口过程中去了。
      

  23.   

    说明以本人目前的水平没法研究PrintWindow这个API了。
      

  24.   

    16 楼的问题,好玩~既然PrintWindow能截图,那什么办法可以阻止截图。
    我有见到过一些数据安全产品防止键盘截图的,但是没见过防止这个API截图的。
    有人提供一些思路么?HOOK?驱动?还是。? 
      

  25.   

    最近需要完成这么一个功能,发现论坛上早已经有高手说出答案了。
    我觉得那些将窗口置前,截图,再置后的做法不可取,这样的变化太明显了,修改其他窗口的属性更是不应该的。LZ和二楼那位大侠说的PrintWindow就能很好的完成功能,学习了
      

  26.   

    HOOK 不知道怎么截取呀!!