win32 api-第二十章
win32API for 易语言
.参数 进程句柄, 整数型, , 进程句柄;
.DLL命令 GetThreadPriority, 整数型, "kernel32", "GetThreadPriority", 公开, GetThreadPriority
.参数 数据1, 文本型, 传址 数组, lpString1
.参数 数据2, 文本型, 传址 数组, lpString2
.参数 数据长度, 整数型, , iMaxLength
.DLL命令 取整数数据地址_, 整数型, "kernel32.dll", "lstrcpyn", 公开, lstrcpyn
.参数 数据1, 字节集, 传址, lpString1
.参数 数据2, 字节集, 传址, lpString2
.参数 数据长度, 整数型, , iMaxLength
.DLL命令 取文本数据地址_, 整数型, "kernel32.dll", "lstrcpyn", 公开, lstrcpyn
.参数 线程句柄, 整数型, , hThread
.参数 优先权, 整数型, , nPriority 例如:-2 更过自己去搜索下
.DLL命令 置进程优先级_, 整数型, "kernel32", "SetPriorityClass", 公开, $(b)设置一个进程的优先级别 进程的优先级,零表示失败。会设置GetLastError
win32bluetoothapi函数
win32bluetoothapi函数一、简介w i n32b lu et oo th api函数是用于在W ind o ws操作系统上进行蓝牙交互的一组功能接口。
通过使用这些函数,开发人员可以实现蓝牙设备的发现、配对、连接和数据传输等操作。
本文将介绍w in32bl ue to o th ap i函数的各种功能和用法,以帮助读者更好地理解和应用这些函数。
二、函数列表下面是一些常用的wi n32bl ue to ot ha pi函数:1.`B lu et oo th Fi ndF i rs tD ev ic e`:用于查找第一个可用的蓝牙设备。
2.`B lu et oo th Fi ndN e xt De vi ce`:用于查找下一个可用的蓝牙设备。
3.`B lu et oo th Fi ndD e vi ce Cl os e`:用于关闭蓝牙设备的查找。
4.`B lu et oo th Ge tDe v ic eI nf o`:用于获取蓝牙设备的详细信息。
5.`B lu et oo th Se tSe r vi ce St at e`:用于设置蓝牙设备的服务状态。
6.`B lu et oo th Au the n ti ca te De vi ce`:用于验证蓝牙设备的身份。
7.`B lu et oo th Au the n ti ca te De vi ce Ex`:用于对蓝牙设备进行高级身份验证。
8.`B lu et oo th Re gis t er Fo rA ut he nt ica t io n`:用于注册蓝牙设备身份验证的回调函数。
三、函数用法举例1.`B l u e t o o t h F i n d F i r s t D e v i c e`该函数用于查找第一个可用的蓝牙设备,并返回一个句柄,用于后续的设备操作。
以下是该函数的用法示例:H A ND LE hD ev ic e;B L UE TO OT H_DE VI CE_S EA RC H_PA RA MS sea r ch Pa ra ms;s e ar ch Pa ra ms.d wSi z e=si ze of(B LU ETO O TH_D E V IC E_SE ARC H_P AR AM S);s e ar ch Pa ra ms.c Tim e ou tM ul ti pl ie r=10;h D ev ic e=Bl ue to oth F in dF ir st De vi ce(&se ar ch Pa ra ms);i f(h De vi ce!=NU LL){//从h De vi ce中获取设备信息//...}2.`B l u e t o o t h G e t D e v i c e I n f o`该函数用于获取指定蓝牙设备的详细信息。
Win32 API编程入门
欢迎阅读theForger's Win32 API教程第二版(简体中文)作者:Brooks Miles译者:湛宗儒 本教程试图使用尽可能快和尽可能清晰的方法教你开始Win32 API开发.它是以一个整体来组织的,所以在你提问之前请从头到尾看一遍...你的大多数问题很可能在文字中已被回答.每个章节以之前的章节为基础.我也在附錄A中附上了一些常见的错误的解決方法.如果你问一些在教程中已被回答的问题的话,看起来就有点不聪明了.·下载完整的范例源代码,在整个教程都有对代码的引用.·或是下载整个教程( 包括源代码)至你自己的计算机上慢慢看.下到硬盘的版本可能不包括网络版本具有的一些如拼写更正之类的小规模修改. 如果你在一个別的站点上看此教程,请访问#winprog 站点看最新的官方版本. · ·目錄·基础1.开始 学习2.一个简单的窗口3.处理消息4.理解消息循环5.使用资源6.菜单和图标7.对话框 , 图形界面设计者的好朋友8.非模态 对话框9.标準控件: 按钮 , 编辑框 , 列表框 , 靜态 控件10.等等 , 我还想问 ...( 对话框常见问题)·创建一个简单应用1.应用第一部分 : 在运行时创建控件2.应用第二部分 : 使用文件与常用对话框3.应用第三部分 : 工具栏与状态栏4.应用第四部分 : 多文档界面·图形设备界面1.位图 , 设备上下文与BitBlt2.透明位图3.定时器与动画4.文本 , 字体与顏色·工具与文档1.推荐的书与参考2.免费的Visual C++ 命令行工具3.免费的Borland C++ 命令行工具·附表附表A:常见错误的解決方法附表B:为什要在学习MFC 编程之前学习API附表C:关于资源文件 我听某些读者说教材中的源代码在一些很旧的Netscape浏览器中不能正确地換行,如果你遇到此问题请参考zip打包下载的源代码.想做点什么?你可以绝对免费地使用此文档,但是把在它放在互联网上的确是有些费用..如果你感觉它对你有帮助,也想回馈一些,我将很感谢你能捐赠任何数目的款项来协助支撐此网站.此页面每月大約有15,000个点击,并且在一直增加:) 再说一次,你完全沒有义务支付,你也不会因为支付而得到除了在此处之外的任何东西,但是你想协助的话,是很好的...就点那个PayPal图片就行.但愿你能享受閱读,Brook 我想对如下几个人做出的贡献表示感谢:Yih Horng,Todd Troxell,T FrankZvovushe,Suzanne Lorrin, Seth McCarus,Crispina Chong,John Crutchfield,Scott Johnstone,Patrick Sears,Juan Demerutis,Richard Anthony,Alex Fox,Bob Rudis,Eric Wadsworth,Chris Blume.还有那些写信告诉我觉得此文档有用的那些读者.我很高兴!需要进一步的帮助? 一般地话我会免费回复求助邮件,或指出在哪里可以找到可供参考的资源. 现在我正忙于几个大项目,所沒有时间跟你写一些特定的范例或一定规模的软件项目.但是我愿意接项目:)尽管联系我 .Copyright © 1998-2003, Brook Miles (theForger). All rights reserved.开始学习这篇教程讲什么 这篇教程试图向你展现使用Win32 API写程序的一些基础知识(还有常见的扩展知识).使用C语言,大多数的C++工具也可以编译.事实上从大多数语言的介绍文章可知,大多数语言皆可调用API,包括Java,汇编语言以及Visual Basic.但是我将不会提到这些语言的代码例子,你想使用其它语言的话,请自己参考相关资料,不过有好几个使用过此教程的人都对我说用上面的这些语言都是可行的. 本教程不会教你C语言,也不会教你怎么使用你喜欢的编译器(Borland C++,Visual C ++,LCC-Win32,等等).但是我将在附表中就我对编译器的所知提供一些说明. 如果你不知道macro或typedef是什么,或switch()语句如何工作,那你要先回去找一本好的C语言的教程学习一下.重要说明 在此文档的某些部分我将指出某些地方很重要.因为很多人在不閱读它们情況下造成理解困难,你如果不閱读,你很可能也陷入困难. 第一个就是: 以zip打包的源代码范例不是可选可不选的!我沒有把所有的代码放在教程中,只放了那些与我正在讨论问题相关的.要想知道这里的代码怎么与其它部分配合,就必须去看zip文件中的源代码. 好!第二个: 把整个文档看完.如果你在读某章节遇到了问题,请耐心一点,很可能在后面一点就可以找到答案.如果你实在不能忍受这种无知的状态,请在到IRC频道上去提问或发出求助邮件之前至少跳过一点或在余下的文档中搜一下(是的,计算机可以搜索). 另外一点就是一个关于话题A的问题很可能在关于话题B或C的讨论中得到解答,也有可能是话题L.所以多看看,找一下. 好,东扯西拉暂时告一段落,我们来试些实际代码.最简单的Win32程序 如果你是一个完全的新手,就让我们来确认一下你可以编译一个基本的windows程序.把下面这些代码弄到你的编译器中去编译一下,如果一切正常你就得到有史以来最简易的程序之一. 记得以C来编译,不是以C++.可能沒有关系,但这里的代码都是C,在正确的轨道,行驶还是好些.大多数情況,你要做的就是把文件的扩展名写成.c而不是.cpp..如果这些话伤了你的脑筋的话,就把文件名写成test.c并用它就行了.#include <windows.h>int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){MessageBox(NULL, "Goodbye, cruel world!", "Note", MB_OK);return 0;} 如果不行,首先閱读得到的任何错误提示,并在帮助文档或任何其它跟你编译器配套的文档中查找它们.确定你是以一个Win32 GUI(不是Console)的工程/makefile/目标来编译的.不幸的是,这一点上我也帮不了什么,对于不同的编译器(不同的人),解決方法不同. 你可能得到一些警告说你沒有使用WinMain()传递的那些参数.这沒关系.现在我们确定你能编译一个程序了,我们来看一下代码...int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow) WinMain()是Windows中与DOS或UNIX的main()的等价物.这是你的程开始执行的入口.参数如下:HINSTANCE hInstance程序可执行模块的句柄(內存中的.exe文件).HINSTANCE hPrevInstance在Win32程序中总是为NULL.LPSTR lpCmdLine命令行参数组成的一个单字符串.不包括程序名字.int nCmdShow一个将要传递给ShowWindow()的整数,我们在后面进行讨论. hInstance用作装入资源或其它的以模块为单位的任务.一个模块是一个装入到你程序的exe或dll.对于本教程的大多数部分(如果不是全部的话),我们只关心一种模块,就是exe 模块. hPrevInstance在Win16时代曾经用作你程序的前面已经运行的实例(如果有的话).现在已经不用了,在Win32中你忽略它就行了.调用规则 WINAPI指定调用规则并被定义为_stdcall.要是你不知道它是干什么用的,先不管它,在我们的这个教程中它对我们沒有影响.记住在这个位置我们需要它就是了.Win32数据类型 你会发现很多普通的关键字或类型在windows中有特定的定义.UINT是unsigned int,LPSTR是char*等等...你怎么用完全取決于你自己.你要是喜欢char*超过了LPSTR,那就用就是了.当然在你替換一个数据类型前你要确定你知道它是什么. 就记住一些容易记住的东西就夠了.LP前缀代表Long Pointer.在Win32中,Long这个部分已经是过时的概念,不要管它.要是不知道指针是什么的话,你可以1)去找一本好的C语言教程,或2)直接往下读,弄得头脑混乱.我是推荐第一种方案的,但很多人使用第二种(我也是:).到时候別说我沒有提醒你. 接下来,一个C接在LP后面表示是常量指针.LPCSTR表示一个指向不会也不能被修改的常量字符串的指针.LPSTR指向的就不是常量的,可以被修改. 你可能还会看到一个T混在里面.现在不要管它,除非你打算与Unicode打交道,它沒有其它的意义.Copyright © 1998-2003, Brook Miles (theForger). All rights reserved.一个简单的窗口范例:simple_window 有时候有人在IRC上问:”我怎么才实现一个窗口?”...我觉得不是一句两句能说得清楚.虽然一旦你搞清楚你要做什么后并不难,但是你的确需要做一些事情来使显示一个窗口;这些事情不是在聊天室中一下子说得清楚的.我总是喜欢先做一件事情然后来理解它...所以先给出一个简单窗口的代码稍后再做解释.#include <windows.h>const char g_szClassName[] = "myWindowClass";// Step 4: the Window ProcedureLRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){WNDCLASSEX wc;HWND hwnd;MSG Msg;//Step 1: Registering the Window Classwc.cbSize = sizeof(WNDCLASSEX);wc.style = 0;wc.lpfnWndProc = WndProc;wc.cbClsExtra = 0;wc.cbWndExtra = 0;wc.hInstance = hInstance;wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wc.lpszMenuName = NULL;wc.lpszClassName = g_szClassName;wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if(!RegisterClassEx(&wc)){MessageBox(NULL, "Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);return 0;}// Step 2: Creating the Windowhwnd = CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"The title of my window",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,NULL, NULL, hInstance, NULL);if(hwnd == NULL){MessageBox(NULL, "Window Creation Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);return 0;}ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);// Step 3: The Message Loopwhile(GetMessage(&Msg, NULL, 0, 0) > 0){TranslateMessage(&Msg);DispatchMessage(&Msg);}return Msg.wParam;} 简单来说这是你想创建一个窗口能写的最简单的程序,大致上70行左右的代码.如果第一个范例你通过了编译,这个也应该不成问题.第一步:注冊窗口类 一个窗口类存储关于一个窗口的消息,包括控制窗口的窗口过程,窗口的大小图标,以及背景顏色.用这种方式,你可以先注冊一个窗口类,然后从它创建任意数目的窗口,而不需要一次次的指定这些参数.如果需要,大多数属性能针对单个的窗口来攺变. 这里说的窗口类与C++中的类是完全不同的概念.const char g_szClassName[] = "myWindowClass"; 上面的变量存储了我们窗口类的名字,马上会用来向系统注冊窗口类. WNDCLASSEX wc;wc.cbSize = sizeof(WNDCLASSEX);wc.style = 0;wc.lpfnWndProc = WndProc;wc.cbClsExtra = 0;wc.cbWndExtra = 0;wc.hInstance = hInstance;wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wc.lpszMenuName = NULL;wc.lpszClassName = g_szClassName;wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if(!RegisterClassEx(&wc)){MessageBox(NULL, "Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);return 0;} 这是我们在WinMain()中注冊我们的窗口类的代码.我们填写一个WNDCLASSEX结构体的成员并调用RegisterClassEx(). 结构体的成员对窗口类的影响如下:cbSize 结构体的大小.style 类的式样(CS_*),不要跟窗口式样(WS_*)混淆了.这个一般设置为0.lpfnWndProc 指向这个窗口类的窗口过程的指针.cbClsExtra 配置给这个类的额外內存.一般为0.cbWndExtra 配置给这个类的每个窗口的额外內存.一般为0.hInstance 应用程序实例的句柄.(从WinMain()第一个参数传递来.)hIcon 当用戶按下Alt+Tab组合时候显示的大图标(一般为32*32).hCursor 在我们的窗口上显示的光标.hbrBackground 设置我们窗口背景顏色的背景刷子.lpszMenuName 这个类的窗口所用的菜单资源的名字.lpszClassName 类的名字.hIconSm 在任务栏和窗口的左上角显示的小图标(一般为16*16). 如果看得不很明白先不要担心,马上会有讲解.另外要记住的一件事情是不要试图去记下这些东西.我基本上不(从来不)记结构体或函数的参数,这样做是浪费精力和更重要的时间.如果你知道要调用的函数你就去花几秒钟在你的帮助文档中查一下.要是沒有帮助文档,就是想法弄到.沒有它们是很郁闷的.随著你使用多次后也许你会记住那些最常用的函数的参数. 然后我们调用RegisterClassEx()并检查是否成功,如果失败我们弹出一条提示消息并从WinMain()函数退出程序.第二步:创建窗口 一旦类注冊完,我们即可从它创建一个窗口.你应该去查一下CreateWindowEx()的参数列表(在你要用一个新API的时候你总是要这样做),但是我会在这里做个简单的介绍.HWND hwnd;hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"The title of my window",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,NULL, NULL, hInstance, NULL); 第一个参数(WS_EX_CLIENTEDGE)是扩展的窗口式样,这里我设置它想得到一个內部下陷的边框效果.你可以设成0看看效果.要习惯于试不同的值看效果. 接下来我设置了类的名字(g_szClassName),告诉系统我们要创建什么样的窗口.因为我们要从刚刚注冊的类创建窗口,我们使用了该类的名字.之后我们指定了我们窗口的名字或是标题,用来显示在我们窗口的外观或是标题栏上. 我们设置的WS_OVERLAPPEDWINDOW是一个窗口式样参数.这里有很多东西你可以查找并做试验.在下文中将详加说明. 接下来的四个参数(CW_USEDEFAULT,CW_USEDEFAULT,320,240)是我们窗口的左上角的X,Y坐标和其宽度和高度.我把X,Y坐标设为CW_USEDEFAULT来让系统自己选择在屏幕的哪个地方来放置窗口.记住屏幕的最左边的X坐标为0并向右加;屏幕的顶部的Y坐标为0并向底加.单位是像素,这是屏幕在特定的分辨率下能显示的最小单位. 再接下来的四个(NULL,NULL,g_hInst,NULL)分別是父窗口的句柄,菜单句柄,应用程序实例句柄,和窗口创建数据的指针.在windows系统中,你屏幕上的窗口是以分层次的父窗口,子窗口的形式来组织的.当你看到一个窗口中有一个按钮时候,按钮就是子窗口,包含它的窗口就是父窗口.我们的例子中,父窗口的句柄为NULL,因为这里沒有父窗口,这个是是我们的主窗口或是顶层窗口.菜单也是NULL,因为我们现在也沒有菜单.实例句柄设为我们从WinMain()得到的第一个参数.窗口的创建数据(我们几乎沒有使用)可以用来向创建的窗口发送额外数据在这里也设为NULL. 如果你想知道神奇的NULL是什么,它实际上被定义为0(零).而且在C中,它是被定义为((void*)0)的,因为是用来作指针用的.所以你有可能在把NULL当整数使用时会得到警告,跟你的编译器的警告级別设置有关.你可以忽略这个警告,也可以用0来代替. 不检查调用是否成功几乎是程序员为找不来程序究竟错在哪里而烦恼的最常发生的情況.CreateWindow()可能会调用失败,即使你是一个用经验的程序员,原因就是可能犯错误的地方实在太多了.除非你学会了如何快速查出错误,最少你应该给自己一个机会知道是哪里出了错,一定记住检查返回值!if(hwnd == NULL){MessageBox(NULL, "Window Creation Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);return 0;} 在我们创建了窗口并作检查以确定我们有一个正确的句柄后,我们使用WinMain()最后的参数来显示窗口,再更新它以确认它在屏幕上正确地重画了自己.ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd); nCmdShow是可选的参数,你可以简单地传递SW_SHOWNORMAL即可.但是用从WinMain()传来的参数可给予运行此程序的用戶选择以可视,最大化,最小化等选项...来引导程序的自由.你可以在windows快捷方式的属性中看到这些选项,参数由选项来決定.第三步:消息循环 这是整个程序的心臟,程序中几乎所有的控制都从这个点传递. while(GetMessage(&Msg, NULL, 0, 0) > 0){TranslateMessage(&Msg);DispatchMessage(&Msg);}return Msg.wParam; GetMessage()从你应用的消息队列中取一个消息.任何时候用戶移动鼠标,敲击键盘,点击你窗口的菜单,或做別的什么事,系统会产生消息并输入到你的程序的消息队列中去.调用GetMessage()时你请求将下一个可用的消息从队列中删除并返回给你来处理.如果队列为空,GetMessage()阻塞.如果你不熟悉这个术语,它意味著一直等待直到得到一个消息,才返回给你. TranslateMessage()为键盘事件做一些额外的处理,如随著WM_KEYDOWN消息产生WM_CHAR消息.最后DispatchMessage()将消息送到消息应该被送到的窗口. 可能是我们的主窗口或另外一个,或一个控件,有些情況下是一个被系统或其它程序创建的窗口.这不是你需要担心的,因为我们主要关心我们得到消息并送出,系统来做后面的事以确认它到达正确的窗口.第四步:窗口过程 如果说消息循环是程序的心臟,那个窗口过程就是程序的大脑.这里所有送到窗口的消息被处理.LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;} 窗口过程在每个消息到来时被调用一次,HWND参数是消息相应的窗口的句柄.这很重要因为你可能用相同的类创建了两个或多个窗口并且它们用相同的窗口过程(WndProc()).不同点就在不同的窗口有不同的hwnd参数.比如我们得到WM_CLOSE消息我们就要销毀那个窗口.我们使用了窗口句柄作为我们得到的第一个参数,其它的窗口都不会受影响,除了那个我们想要操作的之外. WM_CLOSE是在我们按下关闭按钮或按下Alt+F4组合时产生的.这默认会使窗口销毀,但我喜欢显式处理它,因为这是在程序退出之前做清除检查,或询问用戶是否保存文件等事情的绝佳的位置. 当我们调用DestoryWindow()系统向要销毀的窗口送出WM_DESTORY消息,这里是我们的窗口,并在从系统移除我们的窗口之前删除它剩下的所有的子窗口.因为这是我们的程序中唯一的窗口,我们準备好了并希望程序退出,所以我们调用了PostQuitMessage().这样会向消息循环发出WM_QUIT消息.我们不永远收不到这个消息,因为它使GetMessage()返回FALSE,而且你也可以看到我们的消息循环代码中,这时候我们停止处理消息并返回最终的结果码,我们传递给PostQuitMessage()的WM_QUIT中的wParam部分.这个返回值只有在你的编程为被別的程序调用并且你需要一个确定的返回值时候才有真正有用.第五步:沒有第五步Phew(喘一口气),到这先告一段落.如果上面还沒有解释清楚的话,还是先放下,也许我们在讲解更有用的程序时这些东西会变得清晰起来.Copyright © 1998-2003, Brook Miles (theForger). All rights reserved.处理消息范例:window_click 不错,我们有个窗口了,不过除了DefWindowProc()允许它做的,如拉抻,最大化等等之外沒有別的什的功能了,并不是很令人激动. 下一章节我将演示如何修改你已有的代码来加点新东西.现在我只来告诉你”处理这个消息,在这里处理...”你就知道我的意思,知道怎样做且不用看一整个例子.希望如此,所以注意看:P 对于初学者,请把我们最后那个窗口编译好并确信它能工作.然后你要么就在这个例子上修改要么拷到另外一个新工程中来修改. 我们準备加个使用戶点击我们的窗口时候能夠显示出我们程序的名称的功能.不是很酷,就是基本的一个消息的处理.让我们看看我们的WndProc()中有些什么:LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;} 如果我们想处理鼠标的点击,我们需要添加一个WM_LBUTTONDOWN的处理部分(对于右键与中间键,分別是WM_RBUTTONDOWN与WM_MBUTTONDOWN). 如果你听到我或其它人提到处理消息,就是说在窗口的类的WndProc()中加上如下代码:LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_LBUTTONDOWN: // <-// <- 这就是我们加的break; // <-case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;} 不同消息处理的代码的顺序基本上沒有什么关系.要记住的是一定不要忘了在每个消息处理代码后写上break语句.你可以看到我们在我们的switch()中加了另外一个case.现在我们想要在我们的程序执行至此时发生点什么. 首先我们把我们要加的代码写出来(显示我们程序的文件名)然后整合到我们的程序中去.后面的章节中我将只写出代码让你自己整合到程序中去.对我来说不用打那么多字了,对你来说也更灵活,不只是这里的程序还可以加到任何程序中去.如果你不知道怎么办,请参考样例zip文档中对应此章的部分.GetModuleFileName(hInstance, szFileName, MAX_PATH);MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION); 这段代码不是自解释的,你不能把它随便敲到你原来的代码中去.我们只想在用戶用鼠标点击的时候运行这段代码,所以我们把它加到我们的消息处理框架中去:LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_LBUTTONDOWN:// BEGIN NEW CODE{char szFileName[MAX_PATH];HINSTANCE hInstance = GetModuleHandle(NULL);GetModuleFileName(hInstance, szFileName, MAX_PATH);MessageBox(hwnd, szFileName, "This program is:", MB_OK |MB_ICONINFORMATION);}// END NEW CODEbreak;case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;} 注意那对新的花括号{}.当你在switch()中定义变量时需要它.这本来是基础的C语言知识,但我认为我应该在此指出来,为那些理解有困难的读者著想. 如果你已经加进了代码,现在就编译它.如果正常的话,你点击窗口你就应该看到一个有.exe字样的对话框弹出来. 你可能已经注意到我们加了两个变量,hInstance与szFileName.查一下GetModuleFileName()你就会看到第一个参数是HINSTANCE.指向可执行文件(我们的程序,.exe文件).我们哪里得到这样一个东西?GetModuleHandle()给出了答案.GetModuleHandle()的说明指出传给它一个NULL会返回一个创建发出调用进程的文件句柄,正是我们刚刚提到的HINSTANCE,是我们需要的.把这些消息集中起来我们就会得到如下的定义:HINSTANCE hInstance = GetModuleHandle(NULL); 对于第二个参数,我们再次转向我们可以信赖的参考文档,我们看到它是”一个用来接收那个模块的文件名和路径的缓冲区的指针”而且数据类型是LPTSTR(要是你的文档是比较旧的话就是LPSTR).因为LPSTR等价于char*,我们就定义一个字符串:char szFileName[MAX_PATH]; MAX_PATH是在<windows.h>中定义的一个宏,用来定义Win32中文件名缓冲区的最大长度.我们也将MAX_PATH传给GetModuleFileName()以使它知道缓冲区的大小. GetModuleFileName()被调用后,szFileName将包括一个我们的.exe文件名的字符串,以null结尾.我们把它传递给MessageBox()以一个简单的方法向用戶显示. 所以如果你加了代码,编译了.如果正常,点击窗口你就会看到一个有.exe文件名的对话框弹出来. 如果不是这样,这里是完整的代码.跟你的比较一下,看错误在哪里.#include <windows.h>const char g_szClassName[] = "myWindowClass";LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_LBUTTONDOWN:{char szFileName[MAX_PATH];HINSTANCE hInstance = GetModuleHandle(NULL);GetModuleFileName(hInstance, szFileName, MAX_PATH);MessageBox(hwnd, szFileName, "This program is:", MB_OK |MB_ICONINFORMATION);}break;case WM_CLOSE:DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){WNDCLASSEX wc;HWND hwnd;MSG Msg;wc.cbSize = sizeof(WNDCLASSEX);wc.style = 0;wc.lpfnWndProc = WndProc;wc.cbClsExtra = 0; wc.cbWndExtra = 0;wc.hInstance = hInstance;wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wc.lpszMenuName = NULL;wc.lpszClassName = g_szClassName;wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if(!RegisterClassEx(&wc)){MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);return 0;}hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"The title of my window",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,NULL, NULL, hInstance, NULL); if(hwnd == NULL){MessageBox(NULL, "Window Creation Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);return 0;}ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);while(GetMessage(&Msg, NULL, 0, 0) > 0){TranslateMessage(&Msg);DispatchMessage(&Msg);}return Msg.wParam;}Copyright © 1998-2003, Brook Miles (theForger). All rights reserved.理解消息循环 在写任何有实际价值的程序之前,都要理解整个消息循环和windows程序传递消息的结构.当前为止我们已经试了一些消息的处理,我还应该更进一步的看一下这个过程, 因为你如果不理解它们的话,后面的內容将会对你很难.什么是消息 一个消息就是一个整数.如果你到头文件中看一下(了解API的好地方)你就会发现这样的內容:#define WM_INITDIALOG 0x0110#define WM_COMMAND 0x0111#define WM_LBUTTONDOWN 0x0201...等等..消息用来进行windows系统中的所有通信,至少在基本方面是这样的.如果你想要你的窗口或是控件(其实就一种特別的窗口)做点什么你就给它发个消息. 如果另外一个窗口要你做点什么它也发给你一个消息..如果发生了用戶按动了键盘,移动了鼠标,点击了一个按钮之类的事件,系统就向相关的窗口发送消息.你要是就是那个被传至消息的窗口,你就要处理这些消息. 每个windows消息可能拥有至多两个参数,wParam和lParam.最初wParam是16bit,lParam是32bit,但在Win32平台下两者都是32bit.不是每个消息使用了这些参数,而且每个消息以不同的方式来使用.比如,WM_CLOSE不使用它们任一个,所以你应该忽略它们.WM_COMMAND消息两个都使用,wParam有两个部分,HIWORD(wParam)中含有提示消息(如果有的话),LOWORD(wParam)含有发送消息的控件或菜单的标识号.lParam含有发送消息的控件的HWND(窗口的句柄)或者为NULL,当消息不是由控件发送. HIWORD()和LOWORD()是windows定义的两个宏,用来从一个32bit值中分离出高字(0xffff0000)和低字(0x0000ffff)的两字节.在Win32中,一个WORD是16bit,所以一个DWORD为32bit. 可以用PostMessage()或SendMessage()来发送消息.PostMessage()把消息放入消息队列再立即返回.就是说你调用了PostMessage()后消息可能被处理了,也可能还沒有被处理. SendMessage()则真接把消息送往窗口并且在窗口沒有结束处理消息之前不返回.如果我们想关闭一个窗口我们可以发送一个WM_CLOSE消息:PostMessage(hwnd,WM_CLOSE,0,0);这跟我们点击窗口顶部的按钮一样的效果.注意wParam和lParam都为0.这是因为我们刚才说了WM_CLOSE并不用它们.对话框 一旦你开始使用对话框,你将需要向此控件发送消息以与它们通信.你可以先使用GetDlgItem()来用ID得到控件的句柄然后用SendMessage(),也可以直接用SendDlgItemMessage()这个一步到位的函数.你给它一个窗口的句柄和一个子窗口的ID,它就会得到字窗口的句柄并向它发送消息.SendDlgItemMessage()和类似的API,如。
win32api的使用方法
win32api的使用方法
win32api的使用方法主要包括以下几种:
1. 调用win32api函数,如GetCursorPos()函数获取光标位置。
具体地,需要在代码中声明一个POINT结构体,然后使用DllImport属性导入动态链接库,最后调用GetCursorPos()函数并将返回的光标位置赋值给POINT 结构体中的X和Y属性。
2. 使用invoke语句调用API函数。
在MASM汇编语言中,可以使用invoke语句来调用API函数,并指定函数的参数。
编译器会检查参数的数量和类型是否正确,如果参数少了或者类型不匹配,会报错。
3. 在调用API函数之前,需要先声明该函数。
声明的格式包括函数名、原型、距离、语言和参数列表,其中参数列表包括每个参数的名称、数据类型和修饰符。
需要注意的是,win32api的使用需要一定的编程基础和经验,因此在学习使用win32api之前,建议先学习相关的编程语言和基础知识。
同时,win32api的使用也需要考虑到操作系统的版本和位数,不同的操作系统版本和位数可能会对API函数的可用性和行为产生影响。
因此,在使用
win32api时,需要注意选择正确的API函数并了解其用法和限制。
windows_api_帮助文档
编者目录第一章Win32 API概论 (1)1.1 为什么使用Win32 API (1)1.2 Win32 API简介 (1)1.3 综述 (11)第二章窗口管理函数(Windows Control Function) (13)2.1 易用特性函数(Accessibility Features) (13)2.2 按钮函数(Button) (20)2.3 插入标记(^)函数(Caret) (21)2.4 组合框函数(Combo box) (24)2.5 通用对话框函数(Common Dialog Box) (25)2.6 标函数(Cursor) (36)2.7 对话框函数(Dialog Box) (40)2.8 编辑控制函数(Edit Control) (54)2.9 图标函数(Icon) (54)2.10 键盘加速器函数(Keyboard Accelerator) (61)2.11 键盘输入函数(Keyboard InPut) (63)2.12 列表框函数(List box) (75)2.13 菜单函数(Menu) (76)2.14 消息和消息队列函数(Message and Message Queue) (90)2.15 鼠标输入函数(Mouse Input) (100)2.16 多文档接口函数(Multiple Document Interface) (103)2.17 资源函数(Resource) (105)2.18 滚动条函数(Scroll Bar) (113)2.19 窗口函数(Window) (119)2.20 窗口类函数(Window Class) (144)2.21 窗口过程函数(Window Procedure) (150)2.22 窗口属性函数(Window Property) (152)第三章图形设备接口函数(Graphic Device Interface Function) (155)3.1 位图函数(Bitmap) (155)3.2 笔刷函数(Brush) (171)3.3 剪切函数(Clipping) (176)3.4 颜色函数(Color) (179)3.5 坐标空间与变换函数(Coordinate Space Transformation) (186)3.6 设备环境函数(Device Context) (195)3.7 填充形态函数(Filled shape) (211)3.8 字体和正文函数(Font and Text) (215)3.9 ICM 2.0函数 (238)3.10 线段和曲线函数(Line and Curve) (295)3.11 图元文件函数(Metafile) (300)3.12 多显示器函数(Multiple Display Monitors) (311)3.13 绘图函数和画图函数(Painting and Drawing) (313)3.14 路径函数(Path) (328)3.15 画笔函数(Pen) (332)3.16 打印及打印假脱机程序函数(Printing and Print Spooler) (334)3.17 矩形函数(Rectangle) (371)3.18 区域函数(Region) (374)第四章系统服务函数(System Service Function) (383)4.1 访问控制函数(Access Control) (383)4.2 原子函数(Atom) (406)4.3 客户/服务器访问控制函数(Client/Server Access Control) (409)4.4 剪贴板函数(Clipboard) (431)4.5 通信函数(Communication) (436)4.6 控制台函数(Console) (444)4.7 数据解压库函数(Data Decompression Library) (463)4.8 调试函数(Debugging) (466)4.9 设备输入输出函数(Device Input and Output) (472)4.10 动态数据交换函数(Dynamic Data Exchange) (474)4.11 动态数据交换管理函数(Dynamic Data Exchange Management) (476)4.12 动态链接库函数(Dynamic-Link Library) (489)4.13 错误函数(Error) (496)4.14 事件日志函数(Event Logging) (499)4.15 文件函数(File) (503)4.16 文件安装库函数(File Installation Library) (542)4.17 文件映射函数(File Mapping) (546)4.18 文件系统函数File System) (551)4.19 句柄和对象函数(Handle and Object) (556)4.20 挂钩函数(Hook) (560)4.21 ImageHlp函数 (572)4.22 大整数操作函数(Iarge Integer Operations) (594)4.23 低层访问控制函数(Low-Level Access Control) (596)4.24 LSAPI函数 (617)4.25 邮槽函数(Mailslot) (622)4.26 内存管理函数(Memory Management) (623)4.27 管道函数(Pipe) (655)4.28 电源管理函数(Power Management) (663)4.29 进程和线程函数(Process and Thread) (666)4.30 注册表函数(Registry) (700)4.31 字符串操作函数(String Manipulation) (724)4.32 结构化异常处理函数(Structured Exception Handling) (742)4.33 同步函数(Synchronization) (745)4.34 系统信息函数(System Information) (766)4.35 系统消息函数(System Message) (780)4.36 系统关机函数(System Shutdown) (781)4.37 磁带备份函数(Tape Backup) (783)4.38 时间函数(Time) (789)4.39 计时器函数(Timer) (795)4.40 工具帮助函数(Tool Help) (796)4.41 窗口站和桌面函数(Window Station and Desktop) (799)4.42 Windows NT 4.0访问控制函数(Window NT 4.0 Access-Control) (808)4.43 WinTrust函数(WinTrust) (814)第五章国际特性函数(International Peatures Punction)时性 (815)5.1 输入方法编辑函数(Input Method Editor) (815)5.2 国家语言支持函数(National Language Support) (828)5.3 Unicode和字符集函数(Unicode and Character Set) (843)第六章网络服务函数(Networding Service Function) (849)6.1 数据链路控制函数(DLC) (849)6.2 网络函数(Net) (849)6.3 NetBIOS函数 (896)6.4 网络DDE函数(Networking DDE) (897)6.5 RAS服务器管理函数(RAS Server Administration) (901)6.6 远程访问服务函数(Remote Access Administration) (910)6.7 服务函数(Service) (929)6.8 Windows网络函数(Windows Networking) (930)附录1 如何在VB中调用DLL API (945)1 DLL API的声明 (945)2 DLL API的调用 (947)附录2 在Delphi中直接调用Windows API (953)第一章Win32 API概论1.1为什么使用Wu32 API在Windows程序设计领域处于发展初期时,Windows程序员可使用的编程工具唯有API 函数。
Win32API函数大全
目录API函数大全1.API之网络函数2. API之消息函数3. API之文件处理函数4. API之打印函数5. API之文本和字体函数6. API之菜单函数7. API之位图、图标和光栅运算函数8. API之绘图函数9. API之设备场景函数10. API之硬件与系统函数11. API之进程和线程函数API函数大全1.API之网络函数WNetAddConnection 创建同一个网络资源的永久性连接WNetAddConnection2 创建同一个网络资源的连接WNetAddConnection3 创建同一个网络资源的连接WNetCancelConnection 结束一个网络连接WNetCancelConnection2 结束一个网络连接WNetCloseEnum 结束一次枚举操作WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接WNetEnumResource 枚举网络资源WNetGetConnection 获取本地或已连接的一个资源的网络名称WNetGetLastError 获取网络错误的扩展错误信息WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称WNetGetUser 获取一个网络资源用以连接的名字WNetOpenEnum 启动对网络资源进行枚举的过程2. API之消息函数BroadcastSystemMessage 将一条系统消息广播给系统中所有的顶级窗口GetMessagePos 取得消息队列中上一条消息处理完毕时的鼠标指针屏幕位置GetMessageTime 取得消息队列中上一条消息处理完毕时的时间PostMessage 将一条消息投递到指定窗口的消息队列PostThreadMessage 将一条消息投递给应用程序RegisterWindowMessage 获取分配给一个字串标识符的消息编号ReplyMessage 答复一个消息SendMessage 调用一个窗口的窗口函数,将一条消息发给那个窗口SendMessageCallback 将一条消息发给窗口SendMessageTimeout 向窗口发送一条消息SendNotifyMessage 向窗口发送一条消息3. API之文件处理函数CloseHandle 关闭一个内核对象。
windows api 用法
windows api 用法
Windows API是指Windows操作系统开发的接口,用于控制系统内的各种应用。
以下是Windows API的用法示例:
```vb
Private Declare Sub Sleep Lib "kernel32" (ByVal dw Milliseconds As Long) ```
上述代码中的关键字和参数含义如下:
- Private:声明在窗体的通用部分,表示这个窗体的任何地方都可以调用。
- Declare:表示要声明API。
- Sub:是一个过程,没有返回值。
- Sleep:是API的名称,相当于过程的名字,从字面上来看是“睡眠”的意思,在这里是让系统延时。
- dw Milliseconds:参数为毫秒,即暂停运行的时间,1秒=1000毫秒。
通过调用Windows API,开发人员可以在编程中实现更强大的功能和更复杂的操作,如果你想了解更多关于Windows API的用法,可以继续向我提问。
C#中win32API大全一览-程序开发-红黑联盟
C#中win32API大全一览-程序开发-红黑联盟C# 中 win32 API大全一览文章录入:王子责任编辑: 23【字体:小大】在C#中做很多应用需要使用win32 API,但发现原型函数的一些数据类型看起来非常费劲,甚至在C#中“没有”这种数据类型,查阅了一下资料,数据类型对应关系整理如下,希望对大家有用:BOOL=System.Int32BOOLEAN=System.Int32BYTE=System.UInt16CHAR=System.Int16COLORREF=System.UInt32DWORD=System.UInt32DWORD32=System.UInt32DWORD64=System.UInt64FLOAT=System.FloatHACCEL=System.IntPtrHANDLE=System.IntPtrHBITMAP=System.IntPtrHBRUSH=System.IntPtrHCONV=System.IntPtrHCONVLIST=System.IntPtrHCURSOR=System.IntPtrHDC=System.IntPtrHDDEDATA=System.IntPtrHDESK=System.IntPtrHDROP=System.IntPtrHDWP=System.IntPtrHENHMETAFILE=System.IntPtrHFILE=System.IntPtrHFONT=System.IntPtrHGDIOBJ=System.IntPtrHGLOBAL=System.IntPtrHHOOK=System.IntPtrHICON=System.IntPtrHIMAGELIST=System.IntPtrHIMC=System.IntPtrHINSTANCE=System.IntPtrHKEY=System.IntPtrHLOCAL=System.IntPtrHMENU=System.IntPtrHMETAFILE=System.IntPtrHMONITOR=System.IntPtr HPALETTE=System.IntPtr HPEN=System.IntPtrHRGN=System.IntPtr HRSRC=System.IntPtrHSZ=System.IntPtr HWINSTA=System.IntPtr HWND=System.IntPtrINT=System.Int32INT32=System.Int32INT64=System.Int64LONG=System.Int32LONG32=System.Int32LONG64=System.Int64 LONGLONG=System.Int64 LPARAM=System.IntPtr LPBOOL=System.Int16[] LPBYTE=System.UInt16[] LPCOLORREF=System.UInt32[] LPCSTR=System.String LPCTSTR=System.String LPCVOID=System.UInt32 LPCWSTR=System.String LPDWORD=System.UInt32[] LPHANDLE=System.UInt32 LPINT=System.Int32[] LPLONG=System.Int32[] LPSTR=System.String LPTSTR=System.String LPVOID=System.UInt32 LPWORD=System.Int32[] LPWSTR=System.String LRESULT=System.IntPtr PBOOL=System.Int16[] PBOOLEAN=System.Int16[] PBYTE=System.UInt16[] PCHAR=System.Char[] PCSTR=System.String PCTSTR=System.String PCWCH=System.UInt32 PCWSTR=System.UInt32 PDWORD=System.Int32[] PFLOAT=System.Float[]PHKEY=System.UInt32 PINT=System.Int32[] PLCID=System.UInt32 PLONG=System.Int32[] PLUID=System.UInt32 PSHORT=System.Int16[] PSTR=System.String PTBYTE=System.Char[] PTCHAR=System.Char[] PTSTR=System.String PUCHAR=System.Char[] PUINT=System.UInt32[] PULONG=System.UInt32[] PUSHORT=System.UInt16[] PVOID=System.UInt32 PWCHAR=System.Char[] PWORD=System.Int16[] PWSTR=System.String REGSAM=System.UInt32 SC_HANDLE=System.IntPtr SC_LOCK=System.IntPtr SHORT=System.Int16 SIZE_T=System.UInt32 SSIZE_=System.UInt32 TBYTE=System.Char TCHAR=System.Char UCHAR=System.ByteUINT=System.UInt32 UINT32=System.UInt32 UINT64=System.UInt64 ULONG=System.UInt32 ULONG32=System.UInt32 ULONG64=System.UInt64 ULONGLONG=System.UInt64 USHORT=System.UInt16 WORD=System.UInt16 WPARAM=System.IntPtr。
史上最强---win32 API函数大全文档
Win32 API函数大全1. API之网络函数WNetAddConnection 创建同一个网络资源的永久性连接WNetAddConnection2 创建同一个网络资源的连接WNetAddConnection3 创建同一个网络资源的连接WNetCancelConnection 结束一个网络连接WNetCancelConnection2 结束一个网络连接WNetCloseEnum 结束一次枚举操作WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接WNetEnumResource 枚举网络资源WNetGetConnection 获取本地或已连接的一个资源的网络名称WNetGetLastError 获取网络错误的扩展错误信息WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称WNetGetUser 获取一个网络资源用以连接的名字WNetOpenEnum 启动对网络资源进行枚举的过程2. API之消息函数BroadcastSystemMessage 将一条系统消息广播给系统中所有的顶级窗口GetMessagePos 取得消息队列中上一条消息处理完毕时的鼠标指针屏幕位置GetMessageTime 取得消息队列中上一条消息处理完毕时的时间PostMessage 将一条消息投递到指定窗口的消息队列PostThreadMessage 将一条消息投递给应用程序RegisterWindowMessage 获取分配给一个字串标识符的消息编号ReplyMessage 答复一个消息SendMessage 调用一个窗口的窗口函数,将一条消息发给那个窗口SendMessageCallback 将一条消息发给窗口SendMessageTimeout 向窗口发送一条消息SendNotifyMessage 向窗口发送一条消息3. API之文件处理函数CloseHandle 关闭一个内核对象。
win32路径操作API
路径转换函数 PathRelativePathTo PathResolve
PathCanonicalize PathBuildRoot CreateDirectory
创建一个路径到另一个路径的相对路径。 将一个相对路径或绝对路径转换为一个合格的路径,这个理解 起来比较拗口。 规范化路径。将格式比较乱的路径整理成规范的路径格式。 根据给定的磁盘序号创建根目录路径 创建目录
去除路径的参数 去除路径最后的反斜杠“\” 在路径最后加上反斜杠“\” 去除路径前后的空格 在文件路径后面加上扩展名 去除文件路径扩展名 更改文件路径扩展名 去除文件名,得到目录 去除路径中的首尾空格 判断路径中是否有空格,有的话,就是用“”引号把整个路径包 含起来
PathAppend PathCombine
验证路径是否一个文件名(有可能是一个路径)
PathIsExe
验证路径是否是可执行文件。注意:不仅仅是.exe,还 有.bat,.com,.src 等
PathIsRoot
路径是否为根路径
PathIsRelativContentType
检测文件是否为制定类型。 例如:PathIsContentType( “hello.txt” , “text/plain” ) 返回TRUE
一个朋友整理的放在他网站上 ,用的时候看的也方便,就贴过 来,表示感谢...
路径截断与合并函数
PathRemoveArgs PathRemoveBackslash PathAddBackslash PathRemoveBlanks PathAddExtension PathRemoveExtension PathRenameExtension PathRemoveFileSpec PathUnquoteSpaces PathQuoteSpaces
用win32API监听U盘插拔并取得其盘符取得当前插入U盘的盘符
⽤win32API监听U盘插拔并取得其盘符取得当前插⼊U盘的盘符版权声明:本⽂为博主原创⽂章,未经博主允许不得转载。
⽤win32 API监听U盘插拔并取得其盘符1.使⽤RegisterDeviceNotification()函数注册[cpp]01. static const GUID GUID_DEVINTERFACE_USB_DEVICE =02. {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}};03.04. void RegisterDeviceNotify()05. {06. HDEVNOTIFY hDevNotify;07. DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;08. ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );09. NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);10. NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;11. NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;12. hDevNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);13. }2.在WndProc()函数中接收WM_DEVICECHANGE消息[cpp]01. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)02. {03. switch(message)04. {05. case WM_DEVICECHANGE:06. return DeviceChange(message, wParam, lParam);07. }08.09. return DefWindowProc(hWnd, message, wParam, lParam);10. }3.处理接收到的WM_DEVICECHANGE消息01. char FirstDriveFromMask(ULONG unitmask)02. {03. char i;04.05. for (i = 0; i < 26; ++i)06. {07. if (unitmask & 0x1)08. break;09. unitmask >>= 1;10. }11.12. return (i + 'A');13. }14.15. LRESULT DeviceChange(UINT message, WPARAM wParam, LPARAM lParam)16. {17. if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam )18. {19. PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;20. if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME)21. {22. PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)lParam;23. char driverLabel = FirstDriveFromMask(pDevVolume->dbcv_unitmask);24. if (wParam == DBT_DEVICEARRIVAL) {25. printf("add %c\r\n", driverLabel);26. } else {27. printf("remove %c\r\n", driverLabel);28. }29. }30. }31. return 0;32. }⽤win32 API取得当前插⼊U盘的盘符1.使⽤取得代表各分区的掩码[cpp]01. DWORD mask = GetLogicalDrives();2.遍历掩码的每⼀位,判断对应的分区是否是U盘01. bool IsUsbDevice(wchar_t letter)02. {03. wchar_t volumeAccessPath[] = L"\\\\.\\X:";04. volumeAccessPath[4] = letter;05.06. HANDLE deviceHandle = CreateFile(07. volumeAccessPath,08. 0, // no access to the drive09. FILE_SHARE_READ | // share mode10. FILE_SHARE_WRITE,11. NULL, // default security attributes12. OPEN_EXISTING, // disposition13. 0, // file attributes14. NULL); // do not copy file attributes15.16. // setup query17. STORAGE_PROPERTY_QUERY query;18. memset(&query, 0, sizeof(query));19. query.PropertyId = StorageDeviceProperty;20. query.QueryType = PropertyStandardQuery;21.22. // issue query23. DWORD bytes;24. STORAGE_DEVICE_DESCRIPTOR devd;25. STORAGE_BUS_TYPE busType = BusTypeUnknown;26.27. if (DeviceIoControl(deviceHandle,28. IOCTL_STORAGE_QUERY_PROPERTY,29. &query, sizeof(query),30. &devd, sizeof(devd),31. &bytes, NULL))32. {33. busType = devd.BusType;34. }35.36. CloseHandle(deviceHandle);37.38. return BusTypeUsb == busType;39. }40.41. // 查找U盘42. // 参数: _letter 存储U盘盘符43. // 返回值:true 当前有U盘44. // false 当前⽆U盘45. bool findUSBStorage(char* _letter)46. {47. DWORD mask = GetLogicalDrives();48. int count = 0;49. while (mask != 0)50. {51. if ((mask & 0x01) == 1)52. {53. wchar_t letter = L'A' + count;54.55. // 判断取得的盘符是否是U盘56. if (IsUsbDevice(letter))57. {58. wcstombs(_letter, &letter, 1);59. return true;60. }61. }62. count++;63. mask = mask >> 1;64. }65. return false;66. }。
c语言获取当前屏幕画面数据方法
方案一:使用Win32 API获取当前屏幕画面数据1. 背景介绍C语言作为一种经典的编程语言,其强大的功能和灵活的特性使得它在图像处理和屏幕画面数据获取方面有着独特的优势。
在Windows 操作系统中,可以通过Win32 API来获取当前屏幕画面数据,为后续的图像处理和分析提供了基础数据支持。
2. Win32 API简介Win32 API是Windows操作系统的核心API之一,它提供了丰富的函数和数据结构,可以用于控制窗口、处理消息、管理文件和目录等各种操作。
其中,针对屏幕画面数据获取,主要可以利用GDI(图形设备接口)和DirectX等技术来实现。
3. 获取屏幕画面数据的基本步骤在使用C语言获取当前屏幕画面数据时,需要经过以下基本步骤:- 初始化相关环境:包括初始化GDI或DirectX环境,并创建用于存储画面数据的缓冲区。
- 获取屏幕画面数据:通过调用相应的API函数,将屏幕上的图像数据读取到缓冲区中。
- 处理和分析画面数据:对获取到的画面数据进行处理和分析,可以进行图像识别、分析、处理等操作。
4. 具体实现方法在C语言中,可以使用相关的Win32 API函数来实现获取当前屏幕画面数据的功能。
可以通过以下步骤来获取屏幕画面数据:1. 初始化GDI环境,包括创建设备上下文(DC)和位图对象。
2. 调用BitBlt函数将屏幕上的图像数据复制到位图对象中。
3. 将位图对象中的像素数据读取到缓冲区中,即可获得当前屏幕的画面数据。
5. 个人观点和总结C语言作为一种强大的编程语言,在图像处理和屏幕画面数据获取方面具有一定的优势,尤其是在Windows评台下,可以充分利用Win32 API来实现相关功能。
通过对Win32 API的调用,可以较为便利地获取当前屏幕的画面数据,并为后续的图像处理和分析提供基础支持。
然而,需要注意的是,在使用Win32 API时,需要关注相关的权限和安全性问题,以确保程序的稳定性和安全性。
Win32系统API讲义
WaitForSingleObject (hchild, INFINITE); }
void Child() { printf(“Child is quiting.\n”); Sleep(5000); //暂停5秒
}
26
void StartClone() { //创建当前进程的克隆进程 GetModuleFileName(NULL, szFilename, MAX_PATH); //获得当前可执行文件名 STARTUPINFO si; si.cb=sizeof(si);//存子进程启 动信息,P234有说明,新进程主窗口外观 sprintf(szCmdLine, “\”%s\”Child”, szFilename); bCreateOK=CreateProcess(szFilename, szCmdLine,...,CREATE_NEW_CONSOLE,...,&si, &pi); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return pi.hProcess;
20
2. 获得当前进程标识符的函数 DWORD GetCurrentProcessId(void); 3. 以指定时间间隔挂起当前执行线程 VOID Sleep(DWORD dwMilliseconds); 以毫秒为单位
21
4. 检索含有给定模块的可执行文件路径名 DWORD GetModuleFileName(
NULL,
//or“c:\\windows\\system32\\notepad.exe”
szCmdLine, // szCmdLine=“notepad”
python win32api message用法
`win32api` 模块是Python 中用于调用Windows API 函数的扩展模块,它提供了许多函数,其中包括用于发送消息(message)的功能。
在Windows 操作系统中,消息是窗口之间进行通信的基本方式,通过消息,窗口可以接收和处理用户输入、系统事件等。
以下是关于在Python 中使用`win32api` 模块发送消息的基本用法和一些常见的消息类型:### 安装`pywin32`首先,确保你已经安装了`pywin32` 模块。
如果没有安装,可以通过以下命令安装:```bashpip install pywin32```### 使用`win32api` 发送消息`win32api` 模块中的`SendMessage` 函数用于向窗口发送消息。
以下是基本的用法:```pythonimport win32api# 获取窗口句柄hwnd = win32api.FindWindow(None, "窗口标题")# 定义消息和参数message = 0x100 # WM_KEYDOWN,此处可以根据需要修改为其他消息类型w_param = 0x41 # 与消息类型相关的参数,此处以按下键盘上的'A' 键为例# 发送消息win32api.SendMessage(hwnd, message, w_param, 0)```在上述代码中:- `FindWindow` 用于根据窗口标题查找窗口句柄,如果你知道窗口类名,也可以将第一个参数设为类名。
- `SendMessage` 是发送消息的函数,第一个参数是窗口句柄,第二个参数是消息类型,第三个和第四个参数是消息相关的参数,具体参数含义取决于消息类型。
### 示例:模拟按键操作以下是一个示例,演示如何使用`win32api` 模拟按键操作:```pythonimport win32apiimport timedef send_key_event(hwnd, key_code):# 发送按键按下事件win32api.SendMessage(hwnd, win32api.WM_KEYDOWN, key_code, 0)# 等待一段时间,模拟按键按下的效果time.sleep(0.1)# 发送按键释放事件win32api.SendMessage(hwnd, win32api.WM_KEYUP, key_code, 0)# 获取窗口句柄hwnd = win32api.FindWindow(None, "窗口标题")# 模拟按下和释放'A' 键send_key_event(hwnd, ord('A'))```在这个示例中,我们使用`ord('A')` 获取'A' 键的ASCII 码,然后通过`send_key_event` 函数发送按键按下和释放事件。
win32api.shellexecute参数说明
win32api.shellexecute参数说明Win32 API是一种基于Windows操作系统的编程接口。
在开发Windows应用程序时,我们经常需要使用不同的API函数。
其中之一是shellexecute函数,用于启动或打开文件或应用程序。
本文将重点讨论shellexecute函数的参数介绍和使用方法。
概述shellexecute函数用于在Windows操作系统中执行一个指定的文件或应用程序。
该函数有五个参数,每个参数都具有不同的功能。
下面我们将对每个参数进行详细介绍。
参数解析参数1:窗口句柄第一个参数是窗口句柄,它指定了用于交互的窗口。
传递一个有效的窗口句柄将在指定的窗口中运行应用程序。
如果不需要任何交互,则可以将其设置为NULL。
参数2:操作第二个参数是操作,它指定了需要执行的操作。
通常我们会使用“open”操作来打开文件或应用程序,可以使用其他操作执行不同的功能。
以下是一些操作的示例:- "open":默认操作,用于打开文件或应用程序。
- "print":打印指定的文件。
- "explore":在资源管理器中打开指定的目录。
- "edit":编辑指定的文件。
参数3:文件名第三个参数是文件名,它指定了需要执行的文件或应用程序的路径。
可以是带有完全路径的文件名,也可以是在当前工作目录中搜索的文件名。
如果指定的操作不是“open”,则可以为空。
参数4:参数第四个参数是参数,它包含了启动应用程序时要使用的参数。
如果没有参数,则可以为空。
参数5:显示方式最后一个参数是显示方式,它指定了用于显示窗口的方式。
以下是几个显示方式的示例:- SW_HIDE:隐藏窗口并在后台运行。
-SW_MAXIMIZE:将窗口最大化。
- SW_MINIMIZE:将窗口最小化。
- SW_RESTORE:还原窗口大小和位置。
-SW_SHOW:显示窗口。
C++通过WIN32API获取逻辑磁盘详细信息
C++通过WIN32API获取逻辑磁盘详细信息众所周知,在微软的操作系统下编写应用程序,最主要的还是通过Windows所提供的api函数来实现各种操作的,这些函数通常是可以直接使用的,只要包含windows.h这个头文件。
今天我们主要介绍的是几个常用的api函数,通过它我们可以获取用户磁盘的相关信息。
示例程序:请点击附件下载。
其主要函数原型说明如下:1.获取系统中逻辑驱动器的数量The GetLogicalDrives function retrieves a bitmask representing the currently available disk drives.DWORD GetLogicalDrives(void);2.获取所有驱动器字符串信息The GetLogicalDriveStrings function fills a buffer with strings that specify valid drives in the system.DWORD GetLogicalDriveStrings(DWORD nBufferLength,LPTSTR lPBuffer);3.获取驱动器类型The GetDriveType function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive.UINT GetDriveType(LPCTSTR lpRootPathName);4. 获取驱动器磁盘的空间状态,函数返回的是个BOOL类型数据The GetDiskFreeSpaceEx function retrieves information about the amount of space available on a disk volume: the total amount of space, the total amount of free space, and the total amount of free space available to the user associated with the calling thread.BOOL GetDiskFreeSpaceEx(LPCTSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailable,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes);以下是完整的示例程序代码:#include#includeusing namespace std;int main(){int DiskCount = 0;DWORD DiskInfo = GetLogicalDrives();//利用GetLogicalDrives()函数可以获取系统中逻辑驱动器的数量,函数返回的是一个32位无符号整型数据。
Win32 Api编程指南
MessageBox( NULL, "Goodbye, cruel world!", "Note", _OK ); return 0; }
实际上是发送给窗口的窗口过程函数处理这个窗口也许是我们的主窗口也许是别的窗口或者仅仅是一个操作很多情况下窗口的创建是不显示在屏幕上的可能由系统隐式的创建或者由另一个程序创建而这些都不需要我们操心因为我们通信的途径就是通过发送和接受消息其余的事情操作系统会为我们打理
Win32 API 编程指南( 1 )
其实只要记住几个要点也就很容易理解了。LP 前缀代表指向长整形的指针( long pointer )。在 Win32 中,long 是一种古老的类型了,这里不用细说。如果您不知道指针是什么,您有两种选择:1 )去找本 C 的书
读一读。 2 )继续读下去,可能会弄得一团糟。我强烈建议您选择第一种,但还是有很多人坚持选择第二种( 我 已经给了您建议哦: ) 别怪我没提醒您! )
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL ); if ( hwnd == NULL ) { MessageBox( NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK ); return 0; }
最简单的 Win32 程序
pythonwin32apiwin32guiwin32con窗口句柄发送消息常用方法键盘输入
pythonwin32apiwin32guiwin32con窗⼝句柄发送消息常⽤⽅法键盘输⼊import win32guiimport win32conimport win32api# 从顶层窗⼝向下搜索主窗⼝,⽆法搜索⼦窗⼝# FindWindow(lpClassName=None, lpWindowName=None) 窗⼝类名窗⼝标题名handle = win32gui.FindWindow("Notepad", None)# 获取窗⼝位置left, top, right, bottom = win32gui.GetWindowRect(handle)#获取某个句柄的类名和标题title = win32gui.GetWindowText(handle)clsname = win32gui.GetClassName(handle)# 打印句柄# ⼗进制print(handle)# ⼗六进制print("%x" %(handle) )# 搜索⼦窗⼝# 枚举⼦窗⼝hwndChildList = []win32gui.EnumChildWindows(handle, lambda hwnd, param: param.append(hwnd), hwndChildList)# FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None) ⽗窗⼝句柄若不为0,则按照z-index的顺序从hwndChildAfter向后开始搜索⼦窗体,否则从第⼀个⼦窗体开始搜索。
⼦窗⼝类名⼦窗⼝标题subHandle = win32gui.FindWindowEx(handle, 0, "EDIT", None)# 获得窗⼝的菜单句柄menuHandle = win32gui.GetMenu(subHandle)# 获得⼦菜单或下拉菜单句柄# 参数:菜单句柄⼦菜单索引号subMenuHandle = win32gui.GetSubMenu(menuHandle, 0)# 获得菜单项中的的标志符,注意,分隔符是被编⼊索引的# 参数:⼦菜单句柄项⽬索引号menuItemHandle = win32gui.GetMenuItemID(subMenuHandle, 0)# 发送消息,加⼊消息队列,⽆返回# 参数:句柄消息类型 WParam IParamwin32gui.postMessage(subHandle, win32con.WM_COMMAND, menuItemHandle, 0)# wParam的定义是32位整型,high word就是他的31⾄16位,low word是它的15⾄0位。
Win32api设置窗口全屏的方法-电脑资料
Win32api设置窗口全屏的方法-电脑资料首先是考虑全屏处理的时机,是在创建窗口时还是显示窗口时进行,若是前者,则可以:BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {HWND hWnd;hInst = hInstance; // 将实例句柄存储在全局变量中UINT width = GetSystemMetrics(SM_CXSCREEN);UINT height = GetSystemMetrics(SM_CYSCREEN);//创建窗口hWnd=CreateWindow(szWindowClass,szTitle,WS_POPUP,0,0,width,height,NULL,NULL,hInstance,NULL);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;}若是在显示窗口时进行处理:BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){HWND hWnd;hInst = hInstance; // 将实例句柄存储在全局变量中hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){return FALSE;}HWND hDesk;RECT rc;hDesk = GetDesktopWindow();GetWindowRect( hDesk, &rc );SetWindowLong( hWnd, GWL_STYLE, WS_BORDER );SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, rc.right, rc.bottom, SWP_SHOWWINDOW);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;}也可以让用户控制全屏的时机,比如按下”ESC“键后进入全屏BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){HWND hWnd;hInst = hInstance; // 将实例句柄存储在全局变量中hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL,hInstance, NULL);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd)return TRUE;}在窗口处理函数中对ESC键进行处理:switch (message){case WM_KEYDOWN:switch(wParam){case VK_ESCAPE:{HWND hDesk;RECT rc;hDesk = GetDesktopWindow();GetWindowRect( hDesk, &rc );SetWindowLong( hWnd, GWL_STYLE, WS_BORDER );SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, rc.right, rc.bottom, SWP_SHOWWINDOW);}break;}return 0;}。
WIN32 API串口通信
WIN32 API串口通信掌握串行通信API函数的用法是掌握串行通信编程技术的关键。
在Win32中,系统将串行口与文件统一了起来,对它们的打开、读写、关闭等操作都使用相同的API函数,但是它们之间又有差别,这些差别主要体现在API函数中部分参数的设置上。
有关通信的API主要包括打开串口、关闭串口、配置串口、设置缓冲区、设置超时、事件驱动、读串口、写串口等。
串口的打开和关闭1:串口的打开。
由于在Windows环境中,串口作为一种文件来使用,打开串口用打开文件同样的API函数CreateFile()。
函数原型为:HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 其中几个参数的含义分别为:lpFileName指定文件名或设备名,串口通讯时,它必须是“COMx”,其中的“x”为串口编号,如第一个串口则为“COM1”;dwDesiredAccess为串口读写属性;dwShareMode指定该端口的共享属性,串行口不能作为共享设备,故参数值必须为0;lpSecurityAttributes为安全属性,对于串口应该为0 ;dwCreationDisposition指文件的创建模式,对于串口必须为OPEN—EXISTING;dwFlagsAndAttributes描述了创建文件的其它属性,对于串行口,有效的设置只能是FILE-FLAG-OVERLAPPED 或者0,分别表示异步或同步读写;参数hTemplateFile必须为NULL。
返回值:若成功,返回创建的句柄;否则返回INVALID—HANDLE—VALUE。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
切换控制权的方法非常类似。
在OS/2的Presentation Manager中,每个线程可以建立一个消息队列,也可以不建立。
如果希望从线程建立窗口,那么一个PM线程必须建立消息队列。否则,如果只是进行许多
的数据处理或者图形输出,那么线程不需要建立消息队列。因为无消息队列的程序不处理消
作(有时这也许不是人们所希望的,不过这种时候去冲冲凉或者到冰箱去看看总是很不错
的)!但是,即使在计算机繁忙的时候,使用者也应该能够使用它。
多任务的各种模式
在PC的早期,有人曾经提倡未来应该朝多任务的方向前进,但是大多数的人还是很迷惑:
在一个单使用者的个人计算机上,多任务有什么用呢?好了,最后事实表示即使是不知道这
的32位版本支持真正的多任务,而且,还多了一种额外的优点,多线程。
多线程是在一个程序内部实作多任务的能力。程序可以把它自己分隔为各自独立的「线程」,
这些线程似乎也同时在执行着。这一概念初看起来似乎没有什么用处,但是它可以让程序使
用多执行绪在背景执行冗长作业,从而让使用者不必长时间地无法使用其计算机进行其它工
一概念的使用者也都需要多任务的。
DOS下的多任务
在最初PC上的Intel 8088微处理器并不是为多任务而设计的。部分原因(我在上一章中讨
论过)是内存管理不够强。当启动和结束多个程序时,多任务的操作系统通常需要移动内存
块以收集空闲内存。在8088上是不可能透明于应用系统来做到这一点的。
这是多任务的前提,虽然移动的方法尚未完全透明于应用程序,但是几乎可以忍受了。
在图形窗口环境中,多任务比在一种命令列单使用者操作系统中显得更有意义。例如,在传
统的命令列UNIX中,可以在命令列之外执行程序,让它们在背景执行。然而,程序的所有
显示输出必须被重新转向到一个文件中,否则输出将和使用者正在做的事情混在一起。
鼠标进行菜单选择的结果。在处理菜单命令消息时,键盘或者鼠标消息并未完全被处理。
序列化消息队列的主要原因是允许使用者的预先「键入」键盘按键和预先「按入」鼠标按钮。
如果一个键盘或者鼠标消息导致输入焦点从一个窗口切换到另一个窗口,那么接下来的键盘
消息应该进入拥有新的输入焦点的窗口中去。因此,系统不知道将下一个使用者输入消息发
Quarterdeck的DesqView),但是在这些环境中,仅有其中一个占据了大部分市场,当然,
这就是Windows。
非优先权式的多任务
当Microsoft在1985年发表Windows 1.0时,它是最成熟的解决方案,目的是突破DOS的
局限。Windows在实际模式下执行。但是即使这样,它已可以在物理内存中移动内存块。
线程间的「争吵」
正确地设计、写作和测试一个复杂的多线程应用程序显然是Windows程序写作者可能遇到
的最困难的工作之一。因为优先权式多任务系统可以在任何时刻中断一个线程,并将控制权
切换到另一个线程中,在两个线程之间可能有无法预料的随机交互作用的情况。
多线程程序中的一个常见的错误被称为「竞争状态(race condition)」,这发生在程序写作
工作。定时器通常用于时钟应用和动画。
针对非优先权式多任务的另一种解决方案是PeekMessage函数呼叫,我们曾在第五章中的
RANDRECT程序里看到过。一个程序通常使用GetMessage呼叫从它的消息队列中找寻下
一个消息,不过,如果在消息队列中没有消息,那么GetMessage不会传回,一直到出现一
窗口环境允许多个程序在相同屏幕上一起执行,前后切换非常容易,并且还可以快速地将数
据从一个程序移动到另一个程序中。例如,将绘图程序中建立的图片嵌入由文书处理程序编
辑的文本文件中。在Windows中,以多种方式支持数据转移,首先是使用剪贴簿,后来又
使用动态数据交换(DDE),而现在则是透过对象连结和嵌入(OLE)。
Microsoft在一种半DOS/半Windows的环境下实作多任务的第一个尝试(和IBM合作)是
OS/2和Presentation Manager(缩写成PM )。虽然OS/2明确地支持优先权式多任务,
但是这种多任务方式似乎并未在Presentation Manager中得以落实。问题在于PM序列化
时。这种非优先权式的多任务也被称为「合作式的多任务」,因为它要求来自应用程序方面
的一些合作。一个Windows程序可以占用整个系统,如果它要花很长一段时间来处理消息
的话。
虽然非优先权式的多任务是16位Windows的一般规则,但仍然出现了某些形式的优先权式
多任务。Windows使用优先权式多任务来执行DOS程序,而且,为了实作多媒体,还允许
者假设一个线程在另一个线程需要某资料之前已经完成了某些处理(如准备数据)的时候。
为了帮助协调线程的活动,操作系统要求各种形式的同步。一种是同步信号(semaphore),
个消息为止。而另一方面,PeekMessage将控制权传回程序,即使没有等待的消息。这样,
一个程序可以执行一个冗长作业,并在程序代码中混入PeekMessage呼叫。只要没有这个
程序或其它任何程序的消息要处理,那么这个冗长作业将继续执行。
Presentation Manager和序列化的消息队列
程序等,透过拦截硬件时钟中断来执行真正的背景处理。其它的TSR,诸如SideKick等弹
出式工具,可以执行某种型态的工作切换-暂停目前的应用程序,执行弹出式工具。DOS
也逐渐有所增强以便提供对TSR的支持。
一些软件厂商试图在DOS之上架构出工作切换或者多任务的外壳程序(shell)(诸如
一个程序中的线程是同一程序的不同部分,因此他们共享程序的资源,如内存和打开的文件。
因为线程共享程序的内存,所以他们还共享静态变量。然而,每个线程都有他们自己的堆栈,
因此动态变量对每个线程是唯一的。每个线程还有各自的处理器状态(和数学协处理器状
态),这个状态在进行线程切换期间被储存和恢复。
提供了必要的线索。因此在这里我将为您的程序建议一种架构:您的主执行绪建立您程序所
需要的所有窗口,并在其中包含所有的窗口消息处理程序,以便处理这些窗口的所有消息;
所有其它执行绪只进行一些背景处理,除了和主执行绪通讯,它们不和使用者进行交流。
可以把这种架构想象成:主线程处理使用者输入(和其它消息),并建立程序中的其它线程,
者(比如我自己)介绍多线程的环境。有趣的是,PM实作多线程的局限为程序写作者提供
了应该如何架构多线程程序的必要线索。即使这些限制在32位的Windows中已经大幅减
少,但是从更有限的环境中学到的经验仍然是非常有效的。因此,让我们继续讨论下去。
在一个多线程环境中,程序可以将它们自己分隔为同时执行的片段(叫做执行绪)。对执行
息,所以它们将不会当住系统。唯一的限制是一个无消息队列线程无法向一个消息队列线程
中的窗口发送消息,或者呼叫任何发送消息的函数(不过,它们可以将消息递送给消息队列
线程)。
这样,PM程序写作者学会了如何将它们的程序分隔为一个消息队列线程(在其中建立所有
的窗口并处理传送给窗口的消息)和一个或者多个无消息队列线程,在其中执行冗长的背景
第二十章 多任务和多线程
多任务是一个操作系统可以同时执行多个程序的能力。基本上,操作系统使用一个硬件时钟
为同时执行的每个程序配置「时间片段」。如果时间片段够小,并且机器也没有由于太多的
程序而超出负荷时,那么在使用者看来,所有的这些程序似乎在同时执行着。
多任务并不是什么新的东西。在大型计算机上,多任务是必然的。这些大型主机通常有几十
动态链接库接收硬件时钟中断。
16位Windows包括几个功能特性来帮助程序写作者解决(或者,至少可以说是对付)非优
先权式多任务中的局限,最显著的当然是时钟式鼠标光标。当然,这并非一种解决方案,而
仅仅是让使用者知道一个程序正在忙于处理一件冗长作业,因而让使用者在一段时间内无法
使用系统。另一种解决方案是Windows定时器,它允许程序周期性地接收消息并完成一些
到一个消息为止。这些消息通常是使用者的键盘或鼠标输入的直接或间接结果。当处理完消
息之后,程序将控制权返回给Windows。
Windows的16位版本不会绝对地依据一个timer tick将控制权从一个Windows程序切换
到另一个,任何的工作切换都发生在当程序完成对消息的处理后将控制权返回给Windows
来自键盘和鼠标的使用者输入消息。这意味着,在前一个使用者输入消息被完全处理以前,
PM不会将一个键盘或者鼠标消息传送给程序。
尽管键盘和鼠标消息只是一个PM(或者Windows)程序可以接收的许多消息中的几个,大
多数的其它消息都是键盘或者鼠标事件的结果。例如,菜单命令消息是使用者使用键盘或者
送到何处,直到前一个消息被处理完为止。
目前的共识是不应该让一个应用系统有可能占用整个系统,而这需要非序列化的消息队列,
32位版本的Windows支持这种消息队列。如果一个程序正在忙着处理一项冗长作业,那么
您可以将输入焦点切换到另一个程序中。
多线程解决方案
我讨论OS/2的Presentation Manager,只是因为它是第一个为早期的Windows程序写作
甚至几百个终端机和它连结,而每个终端机使用者都应该感觉到他或者她独占了整个计算
机。另外,大型主机的操作系统通常允许使用者「提交工作到背景」,这些背景作业可以在
使用者进行其它工作时,由机器执行完成。