教你用Windows API 写一个Thread类(不使用static哦)------(2)

22 篇文章 0 订阅
14 篇文章 0 订阅

    这一文章中我们主要分析VS平台对于函数调用的编译处理,首先我们看一个简单的例子,代码如下:

        
void Hello(){
        }

        int main(){
             Hello();
        }

    然后在VS Command Prompt下面用cl -FA main.cpp 编译一下,你会得到一个汇编的文件main.asm,其内容如下:

;
 Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 	include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAXXZ     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
?Hello@@YAXXZ PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 mov ebp, esp
; Line 2
 	pop ebp
 	ret 0
?Hello@@YAXXZ ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 4
 	push ebp
 	mov ebp, esp
; Line 5
 	call ?Hello@@YAXXZ    ; Hello
; Line 6
 	xor eax, eax
	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    别怕,有我给你们解释这些代码,这些代码可以说其实都不用看,只需要看有标记;Line 1、;Line 2……这些行就行了,首先在Lin 4,这是main函数的开始,里面首先保存了栈帧,然后Lin 5那里跳到Hello函数里面去执行Hello里面的代码。也就是说,如果我们写以下的代码也应该是对的。


void Hello(){
}

int main(){
    __asm{
        call Hello
    }
}


 

    可以编译,看到程序正常运行,说明我们的call调用是成功的,在此说明了一点,函数调用最后关键的一步是call调用。

上面只是简单的一个Hello函数,下面我们用难一点的去测试,我们写如下代码:


int Hello(){
    return 100;
}

int main(){
    Hello();
}


 

    这个代码和上面代码的区别在于这个函数Hello 有返回值,同样地用cl -FA main.cpp编译得到main.asm,打开main.asm看到其内容如下:

; 
Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAHXZ     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
?Hello@@YAHXZ PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 	mov ebp, esp
; Line 2
 	mov eax, 100    ; 00000064H
; Line 3
 	pop ebp
 	ret 0
?Hello@@YAHXZ ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 5
 	push ebp
 	mov ebp, esp
; Line 6
 	call ?Hello@@YAHXZ    ; Hello
; Line 7
 	xor eax, eax
 	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    在Line2里面可以看到有一句mov eax, 100,联想到Hello里面返回100,可以猜测VS里面是用eax传递返回值的,其实确实是这样的,可以用下面的代码测试:


#include <iostream>
using namespace std;
int Hello(){
    __asm{
        mov eax, 100
   }
}

int main(){
    cout<<Hello()<<endl;
}



    可以看到输出100,说明我了们的结果是对的,函数的返回值是存放在eax进而的。

下面我们再给Hello传递参数试试,来进一步说明参数传递的原理代码如下


void Hello(int iVA, int iVB){

}

int main(){
    Hello(3, 5);
}


 

    同样的得到汇编的代码如下:

; 
Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAXHH@Z     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
_iVA$ = 8      ; size = 4
_iVB$ = 12      ; size = 4
?Hello@@YAXHH@Z PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 	mov ebp, esp
; Line 3
 	pop ebp
 	ret 0
?Hello@@YAXHH@Z ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 5
 	push ebp
 	mov ebp, esp
; Line 6
 	push 5
 	push 3
 	call ?Hello@@YAXHH@Z    ; Hello
 	add esp, 8
; Line 7
 	xor eax, eax
 	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    可以看到,其实不过是把参数用push传递进了stack里面,然后就是一个call而已,当然是主调函数清除stack(一句add esp而已)

为了测试,我们写下如下的代码


#include <stdio.h>

int main(){
    char *lpstrFormat = "%s %d";
    char *lpStr   = "Hello, this year is: ";
    __asm{
        push 2012
        push lpStr
        push lpstrFormat
        call printf
        add esp, 12
   }
}



    然后在命令行里面运行得到了你想要的结果,呵呵。
当然,参数怎么传递的和谁清除stack这个由调用方式决定的,调用方式一般有三种__stdcall, __cdecl, __fastcall,读都可以在网上baidu一下,或者过几天我自己写文章说明。


    到此,一般函数调用的过程已经完全说完了,如果想知道class的成员函数的调用过程,我在下一文章中说明。

 

在.NET 6.0中,可以使用Windows API来调用摄像头进行拍照和录制视频。具体步骤如下: 1. 引用相关命名空间:需要使用Windows API进行摄像头的调用,需要在代码文件中添加以下命名空间: ```csharp using System.Runtime.InteropServices; using System.Diagnostics; using System.Windows.Forms; ``` 2. 调用摄像头进行拍照:使用Windows API中的SendMessage方法指定命令来调用摄像头,如下所示: ```csharp [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); const uint WM_CAP_START = 0x400; const uint WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10; const uint WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11; const uint WM_CAP_SAVEDIB = WM_CAP_START + 25; const int IDOK = 1; public void TakePhoto() { ProcessStartInfo startInfo = new ProcessStartInfo("C:\\Windows\\System32\\amcap.exe"); // 打开摄像头软件 Process.Start(startInfo); IntPtr hWnd = IntPtr.Zero; while (hWnd.ToInt32() == 0) { hWnd = FindWindow(null, "AMCap"); // 查找摄像头软件的窗口句柄 Thread.Sleep(100); } SendMessage(hWnd.ToInt32(), WM_CAP_DRIVER_CONNECT, 0, 0); // 连接摄像头 SendMessage(hWnd.ToInt32(), WM_CAP_SAVEDIB, 0, 0); // 拍照 SendMessage(hWnd.ToInt32(), WM_CAP_DRIVER_DISCONNECT, 0, 0); // 断开连接摄像头 } ``` 3. 调用摄像头进行录制视频:同样是使用Windows API中的SendMessage方法指定命令来调用摄像头,如下所示: ```csharp [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); const uint WM_CAP_START = 0x400; const uint WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10; const uint WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11; const uint WM_CAP_SET_PREVIEW = WM_CAP_START + 50; const uint WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52; const uint WM_CAP_SAVEDIB = WM_CAP_START + 25; const int IDOK = 1; public void RecordVideo() { ProcessStartInfo startInfo = new ProcessStartInfo("C:\\Windows\\System32\\amcap.exe"); // 打开摄像头软件 Process.Start(startInfo); IntPtr hWnd = IntPtr.Zero; while (hWnd.ToInt32() == 0) { hWnd = FindWindow(null, "AMCap"); // 查找摄像头软件的窗口句柄 Thread.Sleep(100); } SendMessage(hWnd.ToInt32(), WM_CAP_DRIVER_CONNECT, 0, 0); // 连接摄像头 SendMessage(hWnd.ToInt32(), WM_CAP_SET_PREVIEW, 0, 0); // 设置预览 SendMessage(hWnd.ToInt32(), WM_CAP_SET_PREVIEWRATE, 66, 0); // 设置预览帧率 string fileName = "C:\\video.avi"; if (File.Exists(fileName)) File.Delete(fileName); SendMessage(hWnd.ToInt32(), WM_CAP_SAVEDIB, 0, fileName); // 开始录制 MessageBox.Show("按OK停止录制", "提示", MessageBoxButtons.OK); SendMessage(hWnd.ToInt32(), WM_CAP_SAVEDIB, 0, 0); // 停止录制 SendMessage(hWnd.ToInt32(), WM_CAP_DRIVER_DISCONNECT, 0, 0); // 断开连接摄像头 } ``` 需要注意的是,这两个方法都是在Windows环境下调用摄像头软件进行实现的,因此需要保证在调用的计算机上已经安装了能够调用摄像头的摄像头软件。如果想要在跨平台的环境中使用摄像头,可能需要使用其他的第三方库或者API进行实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值