C#根据句柄获取窗口截图

陈擎z 2017-04-07 12:07:59
项目中我使用office2013的com组件进行编程
在对powerpoint的放映窗口进行截图时,我通过com提供的SlideShowWindow.HWND获取句柄
然后使用user32的PrintWindow进行截图,本来是可用的,但是,当客户安装上office2016时,得到的图片是黑屏,
然后我安装了个office2016进行引用com,发现并没有16.0的powerpoint组件,同样也是15.0,SlideShowWindow.HWND得到的句柄也不为zero,求教如何解决截图?
这是PrintWindow的代码:

/// <summary>
/// 得到窗口截图
/// </summary>
/// <param name="hWnd"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static Bitmap GetImageFromWindow(IntPtr hWnd, int width, int height)
{
IntPtr hscrdc = user32DLL.GetWindowDC(hWnd);
IntPtr hbitmap = gdi32DLL.CreateCompatibleBitmap(hscrdc, width, height);
IntPtr hmemdc = gdi32DLL.CreateCompatibleDC(hscrdc);
gdi32DLL.SelectObject(hmemdc, hbitmap);
user32DLL.PrintWindow(hWnd, hmemdc, 0);
Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
gdi32DLL.DeleteDC(hscrdc);//删除用过的对象
gdi32DLL.DeleteObject(hbitmap);//删除用过的对象
gdi32DLL.DeleteDC(hmemdc);//删除用过的对象
return bmp;
}

100分求快速解决,在线等
...全文
3143 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
橘子皮... 2017-09-03
  • 打赏
  • 举报
回复

public Bitmap GetWindowCapture(int hWnd)
        {
            IntPtr intp; Bitmap bmp = null;

            if (hWnd == 0) { intp = Win32API.GetDesktopWindow(); } else { intp = (IntPtr)hWnd; }
            IntPtr hscrdc = Win32API.GetWindowDC(intp);IntPtr hmemdc = Win32API.CreateCompatibleDC(hscrdc);
            try
            {
                Win32API.RECT rect = new Win32API.RECT();
                Win32API.GetClientRect(intp, ref rect);
                int width = rect.right - rect.left; int height = rect.bottom - rect.top;
                MessageBox.Show(width.ToString() + "/" + height.ToString());
                this.pictureBox1.Width = width; this.pictureBox1.Height = height;
                IntPtr hbitmap = Win32API.CreateCompatibleBitmap(hscrdc, width, height);
                Win32API.SelectObject(hmemdc, hbitmap);
                Win32API.PrintWindow(intp, hmemdc, 0);
                bmp = Bitmap.FromHbitmap(hbitmap);
                //Clipboard.SetImage(bmp);
            }
            catch { }
            finally { Win32API.DeleteDC(hmemdc); Win32API.DeleteDC(hscrdc); }

            return bmp;
        }
这个可以,不过我也发现问题了,这个窗体尺寸貌似捕获的大小不对,偏小了一点,不知道为什么,请大侠指点下下这是为什么呢
橘子皮... 2017-09-03
  • 打赏
  • 举报
回复
关键是要用到 PrintWindow 这个api
橘子皮... 2017-09-03
  • 打赏
  • 举报
回复
引用 9 楼 u010229498 的回复:
需求:通过句柄获取窗口截图,要完整,不要有覆盖在前面的窗口的截图 目前的两条路: 1.通过PrintWindow进行截图:
/// <summary>
        /// 得到窗口截图
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public Bitmap GetImageFromWindow(IntPtr hWnd, int width, int height)
        {
            Bitmap bitmap = null;
            IntPtr hscrdc = user32DLL.GetWindowDC(hWnd);
            IntPtr hbitmap = gdi32DLL.CreateCompatibleBitmap(hscrdc, width, height);
            IntPtr hmemdc = gdi32DLL.CreateCompatibleDC(hscrdc);
            try
            {
                DateTime dtStart = DateTime.Now;
                gdi32DLL.SelectObject(hmemdc, hbitmap);
                user32DLL.PrintWindow(hWnd, hmemdc, 0);
                bitmap = Bitmap.FromHbitmap(hbitmap);
                bool not = notAllBlack(bitmap, 500);
                int count = 0;
                while (!not)
                {
                    user32DLL.PrintWindow(hWnd, hmemdc, 0);
                    bitmap = Bitmap.FromHbitmap(hbitmap);
                    not = notAllBlack(bitmap, 500);
                    if (!not)
                    {
                        bitmap.Dispose();
                        GC.Collect();
                        Application.DoEvents();
                    }
                    count++;
                }
                DateTime dtEnd = DateTime.Now;
                TimeSpan jianju = dtEnd - dtStart;
                richTextBox1.Text += "全部都是黑" + count + ",用时:" + jianju.TotalSeconds + "秒\r\n";
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                //gdi32DLL.DeleteDC(hscrdc);//删除用过的对象
                gdi32DLL.DeleteObject(hbitmap);//删除用过的对象
                gdi32DLL.DeleteDC(hmemdc);//删除用过的对象
                gdi32DLL.ReleaseDC(hWnd, hscrdc);
            }
            return bitmap;
        }
结果:不能一次拿到正常的截图,要拿很多次,平均用时一两秒 2.使用BitBlt获取截图:
public Bitmap GetBitmapFromDC(IntPtr hwnd, int width,int height)
        {
            IntPtr windc = user32DLL.GetDC(hwnd);//获取窗口DC
            IntPtr hDCMem = gdi32DLL.CreateCompatibleDC(windc);//为设备描述表创建兼容的内存设备描述表
            IntPtr hbitmap = gdi32DLL.CreateCompatibleBitmap(windc, width, height);
            IntPtr hOldBitmap = (IntPtr)gdi32DLL.SelectObject(hDCMem, hbitmap);
            gdi32DLL.BitBlt(hDCMem, 0, 0, width, height, windc, 0, 0, gdi32DLL.SRCCOPY);
            hbitmap = (IntPtr)gdi32DLL.SelectObject(hDCMem, hOldBitmap);
            Bitmap bitmap = Bitmap.FromHbitmap(hbitmap);
            gdi32DLL.DeleteObject(hbitmap);//删除用过的对象
            gdi32DLL.DeleteObject(hOldBitmap);//删除用过的对象
            gdi32DLL.DeleteDC(hDCMem);//删除用过的对象
            user32DLL.ReleaseDC(hwnd, windc);
            return bitmap;
        }
这里百分百能拿到截图,但是在win7的情况下会拿到排在前面的窗口的截图,求解决
我测试了,你这个不只是在win7下有问题,就是在xp下也只能抓到前端的窗口,我有一段vb6代码可以在xp下抓到所有的,除了最小化(最小化的窗体windows默认就是没窗体加载的)
陈擎z 2017-05-04
  • 打赏
  • 举报
回复
需求:通过句柄获取窗口截图,要完整,不要有覆盖在前面的窗口的截图
目前的两条路:
1.通过PrintWindow进行截图:
/// <summary>
/// 得到窗口截图
/// </summary>
/// <param name="hWnd"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public Bitmap GetImageFromWindow(IntPtr hWnd, int width, int height)
{
Bitmap bitmap = null;
IntPtr hscrdc = user32DLL.GetWindowDC(hWnd);
IntPtr hbitmap = gdi32DLL.CreateCompatibleBitmap(hscrdc, width, height);
IntPtr hmemdc = gdi32DLL.CreateCompatibleDC(hscrdc);
try
{
DateTime dtStart = DateTime.Now;
gdi32DLL.SelectObject(hmemdc, hbitmap);
user32DLL.PrintWindow(hWnd, hmemdc, 0);
bitmap = Bitmap.FromHbitmap(hbitmap);
bool not = notAllBlack(bitmap, 500);
int count = 0;
while (!not)
{
user32DLL.PrintWindow(hWnd, hmemdc, 0);
bitmap = Bitmap.FromHbitmap(hbitmap);
not = notAllBlack(bitmap, 500);
if (!not)
{
bitmap.Dispose();
GC.Collect();
Application.DoEvents();
}
count++;
}
DateTime dtEnd = DateTime.Now;
TimeSpan jianju = dtEnd - dtStart;
richTextBox1.Text += "全部都是黑" + count + ",用时:" + jianju.TotalSeconds + "秒\r\n";
}
catch (Exception ex)
{
throw ex;
}
finally
{
//gdi32DLL.DeleteDC(hscrdc);//删除用过的对象
gdi32DLL.DeleteObject(hbitmap);//删除用过的对象
gdi32DLL.DeleteDC(hmemdc);//删除用过的对象
gdi32DLL.ReleaseDC(hWnd, hscrdc);
}
return bitmap;
}

结果:不能一次拿到正常的截图,要拿很多次,平均用时一两秒
2.使用BitBlt获取截图:
public Bitmap GetBitmapFromDC(IntPtr hwnd, int width,int height)
{
IntPtr windc = user32DLL.GetDC(hwnd);//获取窗口DC
IntPtr hDCMem = gdi32DLL.CreateCompatibleDC(windc);//为设备描述表创建兼容的内存设备描述表
IntPtr hbitmap = gdi32DLL.CreateCompatibleBitmap(windc, width, height);
IntPtr hOldBitmap = (IntPtr)gdi32DLL.SelectObject(hDCMem, hbitmap);
gdi32DLL.BitBlt(hDCMem, 0, 0, width, height, windc, 0, 0, gdi32DLL.SRCCOPY);
hbitmap = (IntPtr)gdi32DLL.SelectObject(hDCMem, hOldBitmap);
Bitmap bitmap = Bitmap.FromHbitmap(hbitmap);
gdi32DLL.DeleteObject(hbitmap);//删除用过的对象
gdi32DLL.DeleteObject(hOldBitmap);//删除用过的对象
gdi32DLL.DeleteDC(hDCMem);//删除用过的对象
user32DLL.ReleaseDC(hwnd, windc);
return bitmap;
}

这里百分百能拿到截图,但是在win7的情况下会拿到排在前面的窗口的截图,求解决
仗剑逗二哈 2017-04-10
  • 打赏
  • 举报
回复
小胸弟,你可以了解一下大漠插件,肯定是达到你心目中的效果,还支持后台截图呢!
陈擎z 2017-04-08
  • 打赏
  • 举报
回复
快来个大佬帮下忙啦
陈擎z 2017-04-07
  • 打赏
  • 举报
回复
引用 5 楼 xuggzu 的回复:
如果说同样的方法2013能用,2016不能,那只能说明新版的核心发生了变化,slideshowwindow.hwnd已经不能提供你需要的目标句柄了。

我更怀疑的是2016的放映窗口结构改了,导致PrintWindow不能截图,使用PrintWindow得到黑屏百度上也不是一个两个了
xuggzu 2017-04-07
  • 打赏
  • 举报
回复
如果说同样的方法2013能用,2016不能,那只能说明新版的核心发生了变化,slideshowwindow.hwnd已经不能提供你需要的目标句柄了。
crystal_lz 2017-04-07
  • 打赏
  • 举报
回复
引用 3 楼 u010229498 的回复:
[quote=引用 2 楼 crystal_lz 的回复:] 没装过 不知道 不过你说Print建 截出来的都是黑屏的话 那估计你的换一个方式了 这很正常 因为不是所有东西都是通过gdi渲染出来的 比如一些游戏和视频播放器之类的 而你的代码调用的那些都是处理gdi对象的 但是想一想也不应该啊 office应该是可以截取的啊
我说的都是用windowsapi进行截图的,不是键盘按键[/quote] 哦 windowsapi啊。。。
陈擎z 2017-04-07
  • 打赏
  • 举报
回复
引用 2 楼 crystal_lz 的回复:
没装过 不知道 不过你说Print建 截出来的都是黑屏的话 那估计你的换一个方式了 这很正常 因为不是所有东西都是通过gdi渲染出来的 比如一些游戏和视频播放器之类的 而你的代码调用的那些都是处理gdi对象的 但是想一想也不应该啊 office应该是可以截取的啊
我说的都是用windowsapi进行截图的,不是键盘按键
crystal_lz 2017-04-07
  • 打赏
  • 举报
回复
没装过 不知道 不过你说Print建 截出来的都是黑屏的话 那估计你的换一个方式了 这很正常 因为不是所有东西都是通过gdi渲染出来的 比如一些游戏和视频播放器之类的 而你的代码调用的那些都是处理gdi对象的 但是想一想也不应该啊 office应该是可以截取的啊
陈擎z 2017-04-07
  • 打赏
  • 举报
回复
来人回答一下啦

111,094

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧