C#如何截取当前程序窗口的截图

C#如何截取当前程序窗口的截图,第1张

Bitmap bit = new Bitmap(thisWidth, thisHeight);

Graphics g = GraphicsFromImage(bit);

gCopyFromScreen(new Point(thisLocationX,thisLocationY), new Point(0, 0), bitSize);

SaveFileDialog saveFileDialog = new SaveFileDialog();

saveFileDialogFilter = "bmp|bmp|jpg|jpg|gif|gif";

if (saveFileDialogShowDialog() != DialogResultCancel)

{

bitSave(saveFileDialogFileName);

}

gDispose();

}

编程思路(API 编程):先调用 GetForegroundWindow 获取当前活动程序窗口句柄,然后调用 GetWindowDC 获取窗口的设备句柄(或 GetDC 函数),调用 BitBlt 位图传输函数将位图拷贝到兼容的设备场景中(拷贝时可以指定位置和大小),最后保存位图文件。

=============================

以下源代码内容转自 CSDN 论坛。

要想完成这个功能,首先要了解一下在C#中如何调用API(应用程序接口)函数。虽然在Net框架中已经提供了许多类库,这些类库的功能也十分强大,但对于一些Windows底层编程来说,还是要通过调用这些API函数才可以实现。所有API都在"Kernel"、"User "和"GDI"三个库中得以运行:其中"Kernel",他的库名为 "KERNEL32DLL", 他主要用于产生与 *** 作系统之间的关联,譬如:程序加载,上下文选择,文件输入输出,内存管理等等。"User "这个类库在Win32中名叫 "USER32DLL"。 它允许管理全部的用户接口。譬如:窗口 、菜单 、对话框 、图标等等。"GDI"(图象设备接口),它在Win32中的库名为:"GDI32dll",它是图形输出库。使用GDI Windows"画"出窗口、菜单以及对话框等;它能创建图形输出;它也能保存图形文件。由于本文所涉及到是图象问题,所有调用的类库是"GDI32dll"。在本文程序中我们使用的API函数是"BitBlt",这个函数对于广大程序员来说,一定不感觉到陌生,因为在图象处理方面他的用途是相对广的,在用其他程序语言编程中,时常也要和他打交道。在Net FrameWork SDK中有一个名字空间"SystemRuntimeInteropServices",此名字空间提供了一系列的类来访问COM对象,和调用本地的API函数。下面是在C#中声明此函数:

[ SystemRuntimeInteropServicesDllImportAttribute ( "gdi32dll" ) ]

private static extern bool BitBlt (

IntPtr hdcDest , // 目标 DC的句柄

int nXDest ,

int nYDest ,

int nWidth ,

int nHeight ,

IntPtr hdcSrc , // 源DC的句柄

int nXSrc ,

int nYSrc ,

SystemInt32 dwRop // 光栅的处理数值

) ;

通过上面这个声明,就可以在下面的代码中使用此函数了。

下面是用C#做屏幕捕获程序的具体实现步骤:

(1)首先要获得当前屏幕的graphic对象,通过以下代码可以实现:

Graphics g1 = thisCreateGraphics ( ) ;

(2)创建一个Bitmap对象,并且这个Bitmap对象的大小是当前屏幕:

首先要获得当前屏幕的大小,通过名字空间"SystemWindowsForms"中的"Screen"类的GetWorkingArea()方法,可以实现。下面是得到当前屏幕的长(Height)和宽(Width):

Rectangle rect = new Rectangle ( ) ;

rect = ScreenGetWorkingArea ( this ) ;

"屏幕宽"= rectWidth ;

"屏幕长"= rectHeight ;

至此就可以得到我们想要的Bitmap了,通过下列语句可以实现:

Image MyImage = new Bitmap ( rectWidth , rectHeight , g1 ) ;

//创建以屏幕大小为标准的位图

(3)获得当前屏幕和此Bitmap对象的DC,这可以通过下列语句实现:

//得到屏幕的DC

IntPtr dc1 = g1GetHdc ( ) ;

//得到Bitmap的DC

IntPtr dc2 = g2GetHdc ( ) ;

(4)调用API函数,把当前屏幕拷贝到创建的Bitmap中:

BitBlt ( dc2 , 0 , 0 , rectWidth , rectHeight , dc1 , 0 , 0 , 13369376 ) ;

(5)释放当前屏幕和此Bitmap对象的DC,通过下面代码可以实现:

//释放掉屏幕的DC

g1ReleaseHdc ( dc1 ) ;

//释放掉Bitmap的DC

g2ReleaseHdc ( dc2 ) ;

(6)保存Bitmap对象,形成jpg:

MyImageSave ( @"c:\Capturejpg" , ImageFormatJpeg );

当然你也可以根据自己的需要,把屏幕以其他的格式来保存,如果你想把保存为位图文件,可以把"ImageFormatJpeg"改换成"ImageFormatBmp";想把保存为Gif文件,就把"ImageFormatJpeg"改换成"ImageFormatGif"。你可以保存的文件类型大概有十多种,这里就不一一介绍了,当然你也要相应改变保存文件的后缀。

用C#来捕获屏幕的源程序代码(Capturecs):

了解上面的这些步骤的实现方法,就可以得到用C#捕获屏幕的源程序,如下:

using System ;

using SystemDrawing ;

using SystemCollections ;

using SystemComponentModel ;

using SystemWindowsForms ;

using SystemData ;

using SystemDrawingImaging ;

public class Form1 : Form

{

private Button button1 ;

private SystemComponentModelContainer components = null ;

public Form1 ( )

{

//初始化窗体中的各个组件

InitializeComponent ( ) ;

}

// 清除程序中使用过的资源

protected override void Dispose ( bool disposing )

{

if ( disposing )

{

if ( components != null )

{

componentsDispose ( ) ;

}

}

baseDispose ( disposing ) ;

}

private void InitializeComponent ( )

{

button1 = new Button ( );

SuspendLayout ( ) ;

button1Location = new SystemDrawingPoint ( 64 , 40 ) ;

button1Name = "button1" ;

button1Size = new SystemDrawingSize ( 80 , 32 ) ;

button1TabIndex = 0 ;

button1Text = "捕获" ;

button1Click += new SystemEventHandler ( button1_Click ) ;

AutoScaleBaseSize = new SystemDrawingSize ( 6 , 14 ) ;

ClientSize = new SystemDrawingSize ( 216 , 125 ) ;

ControlsAdd ( button1 ) ;

MaximizeBox = false ;

MinimizeBox = false ;

Name = "Form1" ;

Text = "C#捕获当前屏幕!" ;

ResumeLayout ( false ) ;

}

//声明一个API函数

[ SystemRuntimeInteropServicesDllImportAttribute ( "gdi32dll" ) ]

private static extern bool BitBlt (

IntPtr hdcDest , // 目标 DC的句柄

int nXDest ,

int nYDest ,

int nWidth ,

int nHeight ,

IntPtr hdcSrc , // 源DC的句柄

int nXSrc ,

int nYSrc ,

SystemInt32 dwRop // 光栅的处理数值

) ;

static void Main ( )

{

ApplicationRun ( new Form1 ( ) ) ;

}

private void button1_Click ( object sender , SystemEventArgs e )

{

//获得当前屏幕的大小

Rectangle rect = new Rectangle ( ) ;

rect = ScreenGetWorkingArea ( this ) ;

//创建一个以当前屏幕为模板的图象

Graphics g1 = thisCreateGraphics ( ) ;

//创建以屏幕大小为标准的位图

Image MyImage = new Bitmap ( rectWidth , rectHeight , g1 ) ;

Graphics g2 = GraphicsFromImage ( MyImage ) ;

//得到屏幕的DC

IntPtr dc1 = g1GetHdc ( ) ;

//得到Bitmap的DC

IntPtr dc2 = g2GetHdc ( ) ;

//调用此API函数,实现屏幕捕获

BitBlt ( dc2 , 0 , 0 , rectWidth , rectHeight , dc1 , 0 , 0 , 13369376 ) ;

//释放掉屏幕的DC

g1ReleaseHdc ( dc1 ) ;

//释放掉Bitmap的DC

g2ReleaseHdc ( dc2 ) ;

//以JPG文件格式来保存

MyImageSave ( @"c:\Capturejpg" , ImageFormatJpeg );

MessageBoxShow ( "当前屏幕已经保存为C盘的capturejpg文件!" ) ;

}

}

这个参数应该是你调用SetWindowsHookEx的DLL的模块实例句柄,它可以经由DllMain入口的第一个参数得到。HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);至于SetWindowsHookEx的第四个参数dwThreadId,才是你需要借由窗口句柄得到的窗口线程ID,你可以通过下面的代码获得:DWORD dwThreadID = GetWindowThreadProcessId(hwnd, NULL);选择相应的消息钩子,比如WH_CALLWNDPROC(用来监视窗口过程)、WH_GETMESSAGE(用来监视消息队列的消息)、WH_KEYBOARD(键盘消息)、WH_MOUSE(鼠标消息)等等。

在PreTranslateMessage中判断消息是否为WM_SYSCOMMAND消息,如果是,则判断附加参数是否为最大化或者最小化。

if (pMsg->message==WM_SYSCOMMAND)

{

    if (pMsg->lParam==SC_MINIMIZE)

    {

        //TODO:在此添加你的处理代码

    }else if (pMsg->lParam==SC_MAXIMIZE)

    {

        //TODO:在此添加你的处理代码

    }

}

来源:网络精英

在关机或Logff前信息的拦截

如果我们关机或Logoff时,我们的程序有时会因而无法按正常程序结束,一般我们会在Form的Unload中一段程序结束时要做什么事,但是,如果使用者直接用开始功能菜单的关机,会使UnLoad的部份没有做到,我们现在就想办法来拦截关机(或Logoff)时的信息。

一般来说,关机或Logff后,Windows会传依序送出WM_QUERYENDSESSION的信息给每个Process,如果中间有一个Process不能顺利结束(例如:Word修改后未存档,而出现是否存档,但我们按取消),这时该信息执行的结果会传回False(0),这时Windows也就不再继续送WM_QUERYENDSESSION给下一个Proccess。反之,如果所有的Process都可以顺利结束(也就是每个送出的WM_QUERYENDSESSION都传回True),那才代表以以顺利结束。

不管WM_QUERYENDSESSION最后的结果是可以顺利结束或不能顺利结束,Windows会再送一个WM_ENDSESSION的信息给所有的Process,而wParam的内容便是指出是否可以顺利结束(True菜单可以,False菜单不行,在vb中则CheckwParam = 0 菜单False ,0菜单True),说到这里大概就知道该如何做啦,程序如下:

’以下在Form

Private Sub Form_Load()

Dim ret As Long

’记录原来的Window Procedure的位址

preWinProc = GetWindowLong(Mehwnd, GWL_WNDPROC)

’设定form的window Procedure到wndproc

ret = SetWindowLong(Mehwnd, GWL_WNDPROC, AddressOf wndproc)

End Sub

Private Sub Form_Unload(Cancel As Integer)

Dim ret As Long

Dim fno As Long

’取消Message的截取,而使之又只送往原来的Window Procedure

ret = SetWindowLong(Mehwnd, GWL_WNDPROC, preWinProc)

’这里只是要看看用关机的方式结束程序时,会不会执行到这里

fno = FreeFile

Open "c:\tt2" For Append As fno

Print #fno, "ccc" + vbCrLf

Close #fno

End Sub

’以下在Bas

Option Explicit

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Const GWL_WNDPROC = (-4)

Public Const WM_ENDSESSION = &H16

Public Const WM_QUERYENDSESSION = &H11

Public preWinProc As Long

Public Function wndproc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

If Msg = WM_QUERYENDSESSION Then

DebugPrint "QryEnd", wParam, lParam

Else

If Msg = WM_ENDSESSION Then

If wParam 0 Then ’代表将顺利关机或LogOff,这时便得做正常结束程序的 *** 作

Dim fno As Long

Open "c:\ttt" For Output As #1

Print #1, "hahcccc5"

Close #1

End If

End If

End If

’将之送往原来的Window Procedure

wndproc = CallWindowProc(preWinProc, hwnd, Msg, wParam, lParam)

End Function

别处找到的,很详细了

如何禁止Windows关机呢?换句话说,如何得到Windows关机的通知呢?

原理:Windows在关机的时候会想所有顶层窗口广播一个消息WM_QUERYENDSESSION,其lParam参数可以区分是关机还是注销用户(注销用户时lParam是ENDSESSION_LOGOFF)。然后Windows会等到所有的应用程序都对这个消息返回TRUE才会关机,因此,只要我们的应用程序对这个消息的处理返回FALSE,Windows就不会关机了。而且通过这个例子,大家也应该可以区分系统关机和注销用户了吧(本例子不能区分)。下面看例子,例子的源程序在这里。

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

switch (iMsg)

{

case WM_DESTROY :

PostQuitMessage (0) ;

return 0 ;

case WM_QUERYENDSESSION:

::MessageBox(hwnd,"未经本程序许可,你不能关机!","禁止关机",MB_OK|MB_SYSTEMMODAL);

return 0;//此处返回0则不能关机,返回1就能关机。

}

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

}

为了节省篇幅,这里之列出了消息处理过程。为了更清楚的看到消息处理,这个例子没有用VCL,而是直接使用了SDK。

另外,这个程序也不是绝对能阻止Windows关机,因为如果某个应用程序调用ExitWindowsEx(EWX_POWEROFF|EWX_FORCE,0);来关机,我这个程序就阻止不了,应为那样调用ExitWindowsEx,系统不会发出WM_QUERYENDSESSION消息,我那个程序也就没有用了,呵呵。

在进程空间在找到你要截获的线程句柄,setwindowhook设置特定消息的hook,编写钩子dll,映射进需要获取消息的进程空间。(中间涉及到很多技术问题,比如提升权限,dll的数据共享,内存的读写,你去看看windows核心编程吧),初学者是比较难掌握的

笔记本电脑截屏可以通过以下方式:

1、通过WINDOWS系统本身来实现,找到键盘上的RPTSC键,这个就是截屏键,使用方法:

⑴按 PrtSc键,截取全屏的图像,打开windows程序——附件——画图——粘贴(ctrl+v),绘图界面就出现刚才截取的图像;

⑵按组合键Alt + PrtSc键,截取当前窗口(就是最上面的窗口),再打开windows的“画图”程序,按ctrl+v就可以看到截取的图或用于word文档粘贴等。

2、通过QQ等聊天程序截屏:

如果当前系统开启QQ,那么使用快捷键CTRL+ALT+A调出截屏功能,鼠标左键点住拖动截屏范围,选好后松开,然后点击窗口中的存盘按钮,按提示保存至本地硬盘,如图:

3、通过一些专业的截屏软件实现截屏,比如PICPICK、红蜻蜓抓图精灵等。

以上就是关于C#如何截取当前程序窗口的截图全部的内容,包括:C#如何截取当前程序窗口的截图、C# 如何截取当前程序窗口指定位置的截图、关于HOOK,如何通过钩子截获指定窗口的所有消息等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/10217828.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存