测量Win32的SetEvent函数及等待函数WaitForSingleObject的延时数据

本文详细解析了在实时性操作中,SetEvent和WaitForSingleObject函数的执行效率,通过实际测试证明其执行速度极快,几乎达到了纳秒级别,从而在确保实时性的同时减少了不必要的延时。

因为经常用到SetEvent和WaitForSingleObject函数组合,来实现事件触发,觉得非常好用,但一直很好奇,这些函数的执行效率如何?或者说,当执行了一个SetEvent触发,大概需要多长时间,WaitForSingleObject才会响应,因为这些数据在实时性操作时是需要明确回答出的。


(2015-01-17补充:测量延时,还可以使用高性能计数器函数QueryPerformanceFrequency、QueryPerformanceCounter。使用说明见文档:http://blog.youkuaiyun.com/dijkstar/article/details/23092747


测试程序:

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Test.h"
#include <afxmt.h>
#include <Mmsystem.h>


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;
//链接库
#pragma comment(lib, "Winmm.lib")



int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		//
		//	使用MFC的事件类,才能等待函数循环转起来
		//
		CEvent evt;
		evt.SetEvent();	//默认的是“触发完毕自动清除,需要再次手动触发”

		//
		//	创建一个高精度计时器
		//
		::timeBeginPeriod(1);
		Sleep(100);
		DWORD s = timeGetTime();//开始时间(毫秒级)

		//
		//	循环10个百万
		// 
		for (int i=0; i<10000000; i++)
		{
			WaitForSingleObject((HANDLE)evt, INFINITE);
			//........
			evt.SetEvent();	//如果将该句注释,那么循环就不转了
		}

		//
		//	结束
		//
		DWORD e = ::timeGetTime();//结束时间(毫秒级)
		printf("%d\n", e-s);//



	}

	return nRetCode;
}

① MFC类的CEvent的类成员函数SetEvent只是薄薄的包装了一层Win32的 ::SetEvent函数,也就是两者基本相同;

② 多媒体库下的计时函数,计时精度到毫秒级,是可信的。

在CPU:i5-3210 2.5G+4G内存+WIN7的机器上,上述结果为5443ms,也就是每一次“等待”和“触发”的执行时间为0.54ns左右。也就是这些函数的执行效率相当的高。即因这些函数造成的延时在纳秒级,不必考虑。

AI 编程 智能体 历史记录 找不到font.h文件 MDK-ARM项目生成问题 解决C代码编译错误 新建会话 i2c手柄类型定义 新建会话 安装C知道 收起 avater 2501_93476800 ../Core/Src/main.c(21): error: #5: cannot open source input file "font.h": No such file or directory 回答 在 main.c 文件中遇到无法打开 font.h 文件(提示 No such file or directory)的错误,通常是由于编译器找不到该头文件的路径导致的。以下是一些可能的解决方法: 检查文件是否存在 要确保 font.h 文件确实存在于指定的路径下。可以使用以下命令在终端中查看文件是否存在: Bash ls ../Core/Inc/font.h 如果文件不存在,需要确认是否遗漏了该文件或者文件被误删除。 检查文件路径 如果 font.h 文件存在,但路径不正确,需要调整 #include 语句中的路径。假设 font.h 文件位于 ../Core/Inc 目录下,在 main.c 中可以这样包含头文件: C #include "../Core/Inc/font.h" 设置编译器的包含路径 若头文件位于项目的其他目录中,可以通过设置编译器的包含路径来让编译器找到该文件。以 GCC 为例,可以使用 -I 选项指定包含路径: Bash gcc -I../Core/Inc main.c -o main 在 Makefile 中,可以这样设置: makefile CFLAGS += -I../Core/Inc 检查文件权限 确保 font.h 文件具有可读权限。可以使用以下命令为文件添加可读权限: Bash chmod +r ../Core/Inc/font.h 检查 IDE 配置 如果是在集成开发环境(IDE)中进行开发,需要确保 IDE 的编译器设置中包含了 font.h 文件所在的目录。不同的 IDE 设置方法不同,需要查阅相应的文档进行配置。 相关提问 除了 GCC,其他编译器如何设置包含路径? 如果 `font.h` 文件存在,但包含路径正确仍无法打开,可能是什么原因? 在 Makefile 中设置包含路径时,有哪些需要注意的地方? 思维导图 参考来源 优快云 优快云 keil里新建的文件在哪里 回答 给定引用中未提及在Keil中新建文件的存放位置相关内容。一般情况下,在Keil中新建文件时,如果没有指定保存路径,默认会保存在当前打开工程的目录下。用户也可以在保存文件时,手动选择想要存放的路径。 相关提问 如何在Keil中更改新建文件的默认保存位置? Keil中不同类型的新建文件保存位置有区别吗? 如果工程目录被移动,Keil中已保存的新建文件会受影响吗? 思维导图 参考来源 优快云 优快云 优快云 优快云 Note: source file '.\oled.c' - object file renamed from 'HCSR04Test\oled.o' to 'HCSR04Test\oled_1.o'. 回答 在Keil环境下出现提示信息 Note: source file '.\oled.c' - object file renamed from 'HCSR04Test\oled.o' to 'HCSR04Test\oled_1.o' 通常有以下两种原因: 重复添加文件:在不同的group文件夹里添加了两个相同的 .c 文件,例如不小心将 oled.c 文件添加到了多个不同的组中,就会导致编译时出现此提示24。 修改源文件路径未清理原引用:修改了源文件 oled.c 的路径,但忘记删除原来所在group的文件引用。Keil在编译时仍然会尝试处理原位置的文件引用,从而出现对象文件重命名的提示3。 该提示产生的影响主要体现在: 编译效率:重复处理相同的源文件会增加编译时间,降低编译效率。 潜在错误:可能会引发一些难以调试的问题,例如目标文件的不一致可能导致程序运行出现异常。 相关提问 如何快速定位Keil工程中重复添加的文件? 出现该提示后,除了已知的解决方法,还有其他解决途径吗? 该提示对生成的可执行文件有什么具体影响? 思维导图 参考来源 优快云 优快云 优快云 优快云 优快云 等待函数 回答 等待函数使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。如果线程在调用一个等待函数的时候,相应的内核对象已经处于触发状态,线程不会进入等待状态。常见的等待函数WaitForSingleObject 和 WaitForMultipleObjects 1。 WaitForSingleObject C++ DWORD WaitForSingleObject( [in] HANDLE hHandle, [in] DWORD dwMilliseconds ); 参数:hHandle 是一个事件的句柄,它可以是 Change notification、Console input、Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer 等对象的句柄;dwMilliseconds 是时间间隔 14。 返回值:如果时间是有信号状态返回 WAIT_OBJECT_0,如果时间超过 dwMilliseconds 值但时间事件还是无信号状态则返回 WAIT_TIMEOUT。当 dwMilliseconds 为 INFINITE 时,函数将直到相应时间事件变成有信号状态才返回,否则一直等待,直到 WaitForSingleObject 有返回值才执行后面的代码 4。 示例代码: C++ #include <windows.h> #include <iostream> CEvent g_event; UINT MyThreadProc(LPVOID pParam) { WaitForSingleObject(g_event, INFINITE); for (;;) { std::cout << "Thread is running." << std::endl; } return 0; } int main() { // 设置事件为有信号状态 g_event.SetEvent(); // 创建线程 HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MyThreadProc, NULL, 0, NULL); if (hThread == NULL) { std::cout << "Failed to create thread." << std::endl; return 1; } // 等待线程结束 WaitForSingleObject(hThread, INFINITE); // 关闭线程句柄 CloseHandle(hThread); return 0; } WaitForMultipleObjects C++ DWORD WaitForMultipleObjects( DWORD dwCount, CONST HANDLE* phObjects, BOOL fWaitAll, DWORD dwMilliseconds ); 参数:dwCount 是要等待的内核数量,必须在 1 - 64 之间;phObjects 是等待的内核对象句柄数组;fWaitAll 为 TRUE 表示等待所有的内核对象变成已通知状态,FALSE 表示等待其中之一变为已通知状态就返回;dwMilliseconds 表示为了等该对象变为已通知状态需要等待的时间 3。 返回值:可能的返回值是 WAIT_FAILED 和 WAIT_TIMEOUT。如果为 fWaitAll 参数传递 TRUE,同时所有对象均变为已通知状态,那么返回值是 WAIT_OBJECT_0。如果为 fWaitAll 传递 FALSE,一旦任何一个对象变为已通知状态,函数便返回,返回值是 WAIT_OBJECT_0 与(WAIT_OBJECT_0 + dwCount - 1)之间的一个值。若返回值不是 WAIT_TIMEOUT 也不是 WAIT_FAILED,应该从返回值中减去 WAIT_OBJECT_0,产生的数字是作为第二个参数传递给 WaitForMultipleObjects 的句柄数组中的索引,该索引说明哪个对象变为已通知状态 5。 相关提问 `WaitForSingleObject` 和 `WaitForMultipleObjects` 在性能上有什么差异? 如何处理 `WaitForMultipleObjects` 函数返回 `WAIT_FAILED` 的情况? 除了 Windows 系统,其他操作系统是否有类似的等待函数? 思维导图 参考来源 优快云 优快云 优快云 优快云 优快云 haldelay 回答 功能 由于未提供 haldelay 函数的具体代码,推测其功能与延时相关。通常在嵌入式系统中,此类函数用于产生精确的微秒级或毫秒级延时,以满足不同外设或任务对时间的要求。例如,在与某些传感器通信时,可能需要在发送命令后延时一段时间再读取数据,这时就可以使用 haldelay 函数来实现精确的延时。 使用方法 一般来说,haldelay 函数可能会有不同的参数,用于指定延时的时间。常见的可能有 delay_us 用于微秒级延时,delay_ms 用于毫秒级延时。以下是一个可能的使用示例: C #include "haldelay.h" int main() { // 初始化延时函数 delay_init(); // 延时 100 微秒 delay_us(100); // 延时 500 毫秒 delay_ms(500); return 0; } 等待功能实现 haldelay 函数等待功能通常是通过循环计数来实现的。在单片机系统中,可以利用系统时钟来进行计数,当计数达到指定的值时,就表示延时时间已到。以下是一个简单的 delay_us 函数的实现示例: C #include "main.h" // 假设系统时钟频率为 1MHz #define SYSCLK_FREQ 1000000 void delay_us(uint32_t nus) { uint32_t ticks = nus * (SYSCLK_FREQ / 1000000); while (ticks--); } void delay_ms(uint16_t nms) { for (uint16_t i = 0; i < nms; i++) { delay_us(1000); } } void delay_init(void) { // 初始化相关时钟等操作 // 这里省略具体实现 } 在这个示例中,delay_us 函数通过循环计数 ticks 来实现微秒级延时,delay_ms 函数则是通过多次调用 delay_us 函数来实现毫秒级延时。 相关提问 `haldelay` 函数延时精度受哪些因素影响? 在不同的单片机平台上,`haldelay` 函数的实现需要做哪些调整? 如何优化 `haldelay` 函数的性能,以减少系统资源的占用? 思维导图 参考来源 优快云 优快云 HAL_Delay(500); 回答 使用方法 HAL_Delay(500); 是一个函数调用语句,HAL_Delay 是 HAL(Hardware Abstraction Layer,硬件抽象层)库中的一个延时函数,括号内的 500 表示延时的时间,单位是毫秒(ms)。在使用时,只需要在需要延时的地方直接调用该函数,并传入所需的延时时间即可。例如: C #include "stm32fxxx_hal.h" int main(void) { HAL_Init(); // 其他初始化代码 while (1) { // 执行某些操作 HAL_Delay(500); // 延时 500 毫秒 // 继续执行其他操作 } } 作用 HAL_Delay(500); 的作用是让程序暂停执行 500 毫秒,也就是 0.5 秒。在实际应用中,延时函数常用于控制程序的执行节奏,例如在控制 LED 闪烁时,通过延时函数可以控制 LED 亮灭的时间间隔;在与外部设备通信时,可能需要在发送命令后延时一段时间再读取数据,以确保设备有足够的时间处理命令。 注意事项 阻塞特性:HAL_Delay 是一个阻塞式的延时函数,在延时期间,CPU 会一直处于等待状态,无法执行其他任务。因此,如果在中断服务函数或者对实时性要求较高的代码中使用该函数,可能会影响系统的响应性能。 时钟依赖:HAL_Delay 函数延时精度依赖于系统时钟的配置。如果系统时钟配置不正确,可能会导致延时时间不准确。在使用 HAL_Delay 之前,需要确保系统时钟已经正确初始化。 卡死问题:在某些情况下,调用 HAL_Delay 函数可能会导致程序卡死。例如,在 SysTick 中断服务函数被禁用或者出现异常时,HAL_Delay 函数可能无法正常工作,从而导致程序卡死 3。 相关提问 如何实现非阻塞式的延时功能? `HAL_Delay` 函数延时精度受哪些因素影响? 在不同的单片机平台上,`HAL_Delay` 函数的使用有什么区别? 思维导图 参考来源 优快云 优快云 优快云 优快云 springf表头 回答 推测你想问的是 sprintf 表头相关信息。sprintf 是 C 语言标准库中的一个函数,用于将格式化的数据写入字符串中。该函数声明在 <stdio.h> 头文件里。 下面是 sprintf 函数的原型: C int sprintf(char *str, const char *format, ...); str:指向用于存储格式化字符串的字符数组的指针。 format:格式化字符串,定义了输出的格式。 ...:可变参数列表,根据 format 字符串中的格式说明符提供相应的值。 以下是一个使用 sprintf 函数的示例: C #include <stdio.h> int main() { char str[50]; int num = 123; sprintf(str, "The number is %d", num); printf("%s\n", str); return 0; } 在这个示例中,sprintf 函数将格式化的字符串 "The number is 123" 写入字符数组 str 中,然后使用 printf 函数将 str 输出到控制台。 相关提问 `sprintf` 函数与 `printf` 函数有什么区别? `sprintf` 函数在使用时可能会出现哪些安全问题? 如何处理 `sprintf` 函数返回值? 思维导图 (uint8_t *)头文件 回答 uint8_t 是 C99 标准中定义的一种标准整数类型,用于表示 8 位无符号整数,它在 <stdint.h> 头文件中被定义5。而 (uint8_t *) 是指向 uint8_t 类型的指针,包含该类型定义的头文件同样是 <stdint.h>。 以下是一个简单的示例代码,展示了如何使用 <stdint.h> 头文件中的 uint8_t 及 (uint8_t *) 类型: C #include <stdint.h> #include <stdio.h> int main() { uint8_t num = 67; uint8_t *ptr = &num; printf("Value pointed by ptr: %u\n", *ptr); return 0; } 相关提问 使用 `(uint8_t *)` 指针时需要注意哪些问题? `<stdint.h>` 头文件中除了 `uint8_t` 还有哪些常用的整数类型定义? 如何对 `(uint8_t *)` 指针进行内存分配和释放? 思维导图 参考来源 优快云 优快云 优快云 优快云 优快云 float num = 3.14159f; uint8_t buff[30]; sprintf((uint8_t *)buff,"num = %.2f",num); OLED_ShowMixedCH(0,0,buff);//该显示结果为保留小数后面2位 num = 3.14 回答 代码 float num = 3.14159f; uint8_t buff[30]; sprintf((uint8_t *)buff,"num = %.2f",num); OLED_ShowMixedCH(0,0,buff); 实现了格式化浮点数并显示保留两位小数结果的功能,下面来详细分析其原理及相关知识。 浮点数变量的定义 C float num = 3.14159f; 这行代码定义了一个 float 类型的变量 num,并将其初始化为 3.14159。在 C 语言中,浮点数常量默认是 double 类型,在数字后面加上 f 后缀表示该常量是 float 类型,以避免隐式类型转换可能带来的问题2。 缓冲区的定义 C uint8_t buff[30]; 这里定义了一个长度为 30 的 uint8_t 类型的数组 buff,作为存储格式化后字符串的缓冲区。uint8_t 是无符号 8 位整数类型,通常用于表示字节,它在 <stdint.h> 头文件中定义。 sprintf 函数的使用 C sprintf((uint8_t *)buff,"num = %.2f",num); sprintf 是 C 标准库中的一个函数,用于将格式化的数据写入字符串。它的原型如下: C int sprintf(char *str, const char *format, ...); (uint8_t *)buff:将 buff 数组的地址强制转换为 uint8_t * 类型,以匹配 sprintf 函数要求的 char * 类型。因为在 C 语言中,char 类型通常也是 8 位的,所以这种转换是安全的。 "num = %.2f":这是格式化字符串,其中 %.2f 是格式化说明符,用于指定浮点数的输出格式。%f 表示输出一个浮点数,.2 表示保留两位小数。 num:要格式化的浮点数变量。 sprintf 函数会根据格式化字符串将 num 的值转换为保留两位小数的字符串,并将结果存储在 buff 数组中。最终,buff 数组中的内容可能是 "num = 3.14"。 OLED_ShowMixedCH 函数的使用 C OLED_ShowMixedCH(0,0,buff); OLED_ShowMixedCH 是一个自定义的函数,用于在 OLED 显示屏上显示混合字符(可能包括中文和英文)。 (0, 0):这是显示的起始坐标,表示从 OLED 屏幕的第 0 行第 0 列开始显示。 buff:存储格式化后字符串的缓冲区,函数会将该字符串显示在 OLED 屏幕上。 相关提问 `sprintf` 函数和 `printf` 函数在使用上有什么区别? 如果 `buff` 数组的长度不足以存储格式化后的字符串,会发生什么? 如何修改格式化字符串以实现保留不同位数的小数? 思维导图 参考来源 优快云 优快云 优快云 c语言类型强制转换 回答 C语言类型强制转换是把变量从一种类型转换为另一种数据类型,可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,形式为 (type_name) expression 2。 强制类型转换的使用示例 以下是一些强制类型转换的具体例子: C #include <stdio.h> int main() { int a = 10; double b = (double)a; // 将a转换成double型 printf("b = %f\n", b); int x = 3, y = 4; int c = (int)(x + y); // 将x + y的值转换为int型 printf("c = %d\n", c); int d = (float)(7 % 5); // 将7 % 5的值转换成float型 printf("d = %d\n", d); return 0; } 强制类型转换的注意事项 括号的使用:类型说明符和表达式都必须加括号(单个变量可以不加括号)。例如,把 (int)(x + y) 写成 (int)x + y 则成了把 x 转换成 int 型之后再与 y 相加 3。 临时性转换:无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型 3。 强制类型转换的应用场景 数据类型不匹配:在某些函数调用或运算中,要求操作数为特定的数据类型,此时需要进行强制类型转换。 数据截断或扩展:当需要将一个较大的数据类型转换为较小的数据类型时,会进行截断操作;反之则进行扩展操作。 相关提问 强制类型转换可能会带来哪些潜在的风险? 不同数据类型之间进行强制类型转换时,具体的转换规则是怎样的? 自动类型转换和强制类型转换有什么区别和联系? 思维导图 参考来源 优快云 优快云 优快云 翻译../Core/Src/main.c(150): warning: #167-D: argument of type "uint8_t *" is incompatible with parameter of type "char *restrict" 回答 警告信息”…/Core/Src/main.c(150): warning: #167-D: argument of type “uint8_t *” is incompatible with parameter of type “char *restrict”“ 可翻译为: …/Core/Src/main.c 文件的第150行出现警告:#167 - D:类型为 “uint8_t *” 的参数与类型为 “char *restrict” 的形参不兼容。 相关提问 如何解决 “uint8_t *” 与 “char *restrict” 类型不兼容的问题? “uint8_t *” 和 “char *restrict” 这两种类型在内存使用上有什么区别? 强制将 “uint8_t *” 转换为 “char *restrict” 会有什么潜在风险? 思维导图 参考来源 优快云 优快云 优快云 ../Core/Src/main.c(149): error: #29: expected an expression 回答 错误 #29: expected an expression 通常表示编译器在代码中期望看到一个有效的表达式,但却遇到了不符合语法规则的内容。以下是一些可能的原因及对应的解决方法: 语法错误 缺失运算符:在表达式中可能遗漏了运算符,例如在两个操作数之间没有使用合适的运算符连接。 C // 错误示例 int a = 5; int b = 3; int c = a b; // 缺少运算符 // 正确示例 int c = a + b; 括号不匹配:代码中的括号可能没有正确配对,导致编译器无法正确解析表达式。 C // 错误示例 if (a > 5 { // 代码块 } // 正确示例 if (a > 5) { // 代码块 } 分号使用不当:分号可能被错误地放置在不应该出现的位置,或者在需要分号的地方遗漏了分号。 C // 错误示例 if (a > 5); { // 代码块 } // 正确示例 if (a > 5) { // 代码块 } 变量或函数未定义 使用未定义的变量:在代码中使用了未声明或未定义的变量。 C // 错误示例 int result = undefined_variable + 5; // 未定义的变量 // 正确示例 int defined_variable = 10; int result = defined_variable + 5; 调用未定义的函数:尝试调用一个没有声明或定义的函数。 C // 错误示例 int result = undefined_function(5); // 未定义的函数 // 正确示例 int defined_function(int x) { return x * 2; } int result = defined_function(5); 预处理指令问题 预处理指令格式错误:预处理指令(如 #define、#ifdef 等)的格式可能不正确。 C // 错误示例 #define MAX_VALUE 100; // 多余的分号 // 正确示例 #define MAX_VALUE 100 查找具体错误位置 可以通过查看错误信息的上下文,定位到第149行代码,仔细检查该行及相邻行的代码,找出可能存在的语法错误。同时,可以借助代码编辑器的语法检查功能,或者使用静态代码分析工具来帮助发现潜在的问题。 相关提问 如何使用静态代码分析工具来检查代码中的语法错误? 除了上述提到的原因,还有哪些可能导致 “expected an expression” 错误? 在C语言中,预处理指令还有哪些常见的错误类型? 思维导图 参考来源 优快云 sprintf怎么用
最新发布
09-29
.版本 2 .程序集 程序集1 .程序集变量 线程池, 线程池类 .程序集变量 许可证, 整数型 .程序集变量 任务队列, 任务类型, , "0" .程序集变量 退出标志, 逻辑型 .数据类型 任务类型 .成员 任务函数, 整数型 ' 子程序指针 .成员 参数指针, 整数型 ' 参数内存指针 ' ================== Windows API声明 ================== .DLL命令 CreateThread, 整数型, "kernel32.dll", "CreateThread" .参数 安全属性, 整数型 .参数 栈大小, 整数型 .参数 线程函数, 子程序指针 .参数 参数指针, 整数型 .参数 标志, 整数型 .参数 线程ID, 整数型, 传址 .DLL命令 CloseHandle, 逻辑型, "kernel32.dll", "CloseHandle" .参数 hObject, 整数型 .DLL命令 CreateMutexA, 整数型, "kernel32.dll", "CreateMutexA" .参数 lpMutexAttributes, 整数型 .参数 bInitialOwner, 逻辑型 .参数 lpName, 文本型 .DLL命令 WaitForSingleObject, 整数型, "kernel32.dll", "WaitForSingleObject" .参数 hHandle, 整数型 .参数 dwMilliseconds, 整数型 .DLL命令 ReleaseMutex, 逻辑型, "kernel32.dll", "ReleaseMutex" .参数 hMutex, 整数型 .DLL命令 CreateEventA, 整数型, "kernel32.dll", "CreateEventA" .参数 lpEventAttributes, 整数型 .参数 bManualReset, 逻辑型 .参数 bInitialState, 逻辑型 .参数 lpName, 文本型 .DLL命令 SetEvent, 逻辑型, "kernel32.dll", "SetEvent" .参数 hEvent, 整数型 .DLL命令 CoInitialize, 整数型, "ole32.dll", "CoInitialize" .参数 pvReserved, 整数型 .DLL命令 CoUninitialize, , "ole32.dll", "CoUninitialize"帮我用这个写一套易语言线程
08-10
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值