【转】调用约定__cdecl、__stdcall和__fastcall的区别

什么是调用约定

函数的调用约定,顾名思义就是对函数调用的一个约束和规定(规范),描述了函数参数是怎么传递和由谁清除堆栈的。它决定以下内容:(1)函数参数的压栈顺序,(2)由调用者还是被调用者把参数弹出栈,(3)以及产生函数修饰名的方法。

历史背景

在微机出现之前,计算机厂商几乎都会提供一份操作系统和为不同编程语言编写的编译器。平台所使用的调用约定都是由厂商的软件实现定义的。 在Apple Ⅱ出现之前的早期微机几乎都是“裸机”,少有一份OS或编译器的,即是IBM PC也是如此。IBM PC兼容机的唯一的硬件标准是由Intel处理器(8086, 80386)定义的,并由IBM分发出去。硬件扩展和所有的软件标准(BIOS调用约定)都开放有市场竞争。 一群独立的软件公司提供了操作系统,不同语言的编译器以及一些应用软件。基于不同的需求,历史实践和开发人员的创造力,这些公司都使用了各自不同的调用约定,往往差异很大。 在IBM兼容机市场洗牌后,微软操作系统和编程工具(有不同的调用约定)占据了统治地位,此时位于第二层次的公司如Borland和Novell,以及开源项目如GCC,都还各自维护自己的标准。互操作性的规定最终被硬件供应商和软件产品所采纳,简化了选择可行标准的问题。

调用者清理

在这些约定中,调用者自己清理堆栈上的参数(arguments),这样就允许了可变参数列表的实现,如printf()。

cdecl

cdecl(C declaration,即C声明)是源起C语言的一种调用约定,也是C语言的事实上的标准。在x86架构上,其内容包括:

  1. 函数实参在线程栈上按照从右至左的顺序依次压栈。
  2. 函数结果保存在寄存器EAX/AX/AL中
  3. 浮点型结果存放在寄存器ST0中
  4. 编译后的函数名前缀以一个下划线字符
  5. 调用者负责从线程栈中弹出实参(即清栈)
  6. 8比特或者16比特长的整形实参提升为32比特长。
  7. 受到函数调用影响的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS
  8. 不受函数调用影响的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS
  9. RET指令从函数被调用者返回到调用者(实质上是读取寄存器EBP所指的线程栈之处保存的函数返回地址并加载到IP寄存器)

Visual C++规定函数返回值如果是POD值且长度如果不超过32比特,用寄存器EAX传递;长度在33-64比特范围内,用寄存器EAX:EDX传递;长度超过64比特或者非POD值,则调用者为函数返回值预先分配一个空间,把该空间的地址作为隐式参数传递给被调函数。

GCC的函数返回值都是由调用者分配空间,并把该空间的地址作为隐式参数传递给被调函数,而不使用寄存器EAX。GCC自4.5版本开始,调用函数时,堆栈上的数据必须以16B对齐(之前的版本只需要4B对齐即可)。

考虑下面的C代码片段:

  int callee(int, int, int);int caller(void){register int ret;ret = callee(1, 2, 3);ret += 5;return ret;}

在x86上, 会产生如下汇编代码(AT&T 语法):

   .globl  callercaller:pushl   %ebpmovl    %esp,%ebppushl   $3pushl   $2pushl   $1call    calleeaddl    $12,%espaddl    $5,%eaxleaveret

在函数返回后,调用的函数清理了堆栈。 在cdecl的理解上存在一些不同,尤其是在如何返回值的问题上。结果,x86程序经过不同OS平台的不同编译器编译后,会有不兼容的情况,即使它们使用的都是“cdecl”规则并且不会使用系统调用。某些编译器返回简单的数据结构,长度大致占用两个寄存器,放在寄存器对EAX:EDX中;大点的结构和类对象需要异常处理器的一些特殊处理(如一个定义的构造函数,析构函数或赋值),存放在内存上。为了放置在内存上,调用者需要分配一些内存,并且让一个指针指向这块内存,这个指针就作为隐藏的第一个参数;被调用者使用这块内存并返回指针----返回时弹出隐藏的指针。 在Linux/GCC,浮点数值通过x87伪栈被推入堆栈。像这样:

   sub esp, 8      ; 给double值一点空间fld [ebp + x]   ; 加载double值到浮点堆栈上fstp [esp]      ; 推入堆栈call functadd esp, 8

使用这种方法确保能以正确的格式推入堆栈。 cdecl调用约定通常作为x86 C编译器的默认调用规则,许多编译器也提供了自动切换调用约定的选项。如果需要手动指定调用规则为cdecl,编译器可能会支持如下语法:

  return_type _cdecl funct();

其中_cdecl修饰符需要在函数原型中给出,在函数声明中会覆盖掉其他的设置。

syscall

与cdecl类似,参数被从右到左推入堆栈中。EAX, ECX和EDX不会保留值。参数列表的大小被放置在AL寄存器中(?)。 syscall是32位OS/2 API的标准。

optlink

参数也是从右到左被推入堆栈。从最左边开始的三个字符变元会被放置在EAX, EDX和ECX中,最多四个浮点变元会被传入ST(0)到ST(3)中----虽然这四个参数的空间也会在参数列表的栈上保留。函数的返回值在EAX或ST(0)中。保留的寄存器有EBP, EBX, ESI和EDI。 optlink在IBM VisualAge编译器中被使用。

被调用者清理

如果被调用者要清理栈上的参数,需要在编译阶段知道栈上有多少字节要处理。因此,此类的调用约定并不能兼容于可变参数列表,如printf()。然而,这种调用约定也许会更有效率,因为需要解堆栈的代码不要在每次调用时都生成一遍。 使用此规则的函数容易在asm代码被认出,因为它们会在返回前解堆栈。x86 ret指令允许一个可选的16位参数说明栈字节数,用来在返回给调用者之前解堆栈。代码类似如下:

 ret 12

pascal

基于Pascal语言的调用约定,参数从左至右入栈(与cdecl相反)。被调用者负责在返回前清理堆栈。 此调用约定常见在如下16-bit 平台的编译器:OS/2 1.x,微软Windows 3.x,以及Borland Delphi版本1.x。

register

Borland fastcall的别名。

stdcall

stdcall是由微软创建的调用约定,是Windows API的标准调用约定。非微软的编译器并不总是支持该调用协议。GCC编译器如下使用:

int __attribute__((__stdcall__ )) func()

stdcall是Pascal调用约定与cdecl调用约定的折衷:被调用者负责清理线程栈,参数从右往左入栈。其他各方面基本与cdecl相同。但是编译后的函数名后缀以符号"@",后跟传递的函数参数所占的栈空间的字节长度。寄存器EAX, ECX和EDX被指定在函数中使用,返回值放置在EAX中。stdcall对于微软Win32 API和Open Watcom C++是标准。

微软的编译工具规定:PASCAL, WINAPI, APIENTRY, FORTRAN, CALLBACK, STDCALL, __far __pascal, __fortran, __stdcall均是指此种调用约定。

fastcall

此约定还未被标准化,不同编译器的实现也不一致。

Microsoft/GCC fastcall

Microsoft或GCC的__fastcall约定(也即__msfastcall)把第一个(从左至右)不超过32比特的参数通过寄存器ECX/CX/CL传递,第二个不超过32比特的参数通过寄存器EDX/DX/DL,其他参数按照自右到左顺序压栈传递。

Borland fastcall

从左至右,传入三个参数至EAX, EDX和ECX中。剩下的参数推入栈,也是从左至右。 在32位编译器Embarcadero Delphi中,这是缺省调用约定,在编译器中以register形式为人知。 在i386上的某些版本Linux也使用了此约定。

调用者或被调用者清理

thiscall

在调用C++非静态成员函数时使用此约定。基于所使用的编译器和函数是否使用可变参数,有两个主流版本的thiscall。 对于GCC编译器,thiscall几乎与cdecl等同:调用者清理堆栈,参数从右到左传递。差别在于this指针,thiscall会在最后把this指针推入栈中,即相当于在函数原型中是隐式的左数第一个参数。

在微软Visual C++编译器中,this指针通过ECX寄存器传递,其余同cdecl约定。当函数使用可变参数,此时调用者负责清理堆栈(参考cdecl)。thiscall约定只在微软Visual C++ 2005及其之后的版本被显式指定。其他编译器中,thiscall并不是一个关键字(反汇编器如IDA使用__thiscall)。

Intel ABI

根据Intel ABI,EAX、EDX及ECX可以自由在过程或函数中使用,不需要保留。

x86-64调用约定

x86-64调用约定得益于更多的寄存器可以用来传参。而且,不兼容的调用约定也更少了,不过还是有2种主流的规则。

微软x64调用约定

微软x64调用约定使用RCX, RDX, R8, R9这四个寄存器传递头四个整型或指针变量(从左到右),使用XMM0, XMM1, XMM2, XMM3来传递浮点变量。其他的参数直接入栈(从右至左)。整型返回值放置在RAX中,浮点返回值在XMM0中。少于64位的参数并没有做零扩展,此时高位充斥着垃圾。 在Windows x64环境下编译代码时,只有一种调用约定----就是上面描述的约定,也就是说,32位下的各种约定在64位下统一成一种了。 在微软x64调用约定中,调用者的一个职责是在调用函数之前(无论实际的传参使用多大空间),在栈上的函数返回地址之上(靠近栈顶)分配一个32字节的“影子空间”;并且在调用结束后从栈上弹掉此空间。影子空间是用来给RCX, RDX, R8和R9提供保存值的空间,即使是对于少于四个参数的函数也要分配这32个字节。

例如, 一个函数拥有5个整型参数,第一个到第四个放在寄存器中,第五个就被推到影子空间之外的栈顶。当函数被调用,此栈用来组成返回值----影子空间32位+第五个参数。

在x86-64体系下,Visual Studio 2008在XMM6和XMM7中(同样的有XMM8到XMM15)存储浮点数。结果对于用户写的汇编语言例程,必须保存XMM6和XMM7(x86不用保存这两个寄存器),这也就是说,在x86和x86-64之间移植汇编例程时,需要注意在函数调用之前/之后,要保存/恢复XMM6和XMM7。

System V AMD64 ABI

此约定主要在Solaris,GNU/Linux,FreeBSD和其他非微软OS上使用。头六个整型参数放在寄存器RDI, RSI, RDX, RCX, R8和R9上;同时XMM0到XMM7用来放置浮点变元。对于系统调用,R10用来替代RCX。同微软x64约定一样,其他额外的参数推入栈,返回值保存在RAX中。 与微软不同的是,不需要提供影子空间。在函数入口,返回值与栈上第七个整型参数相邻。

以上内容来源中文维基:https://zh.wikipedia.org/zh-hans/X86%E8%B0%83%E7%94%A8%E7%BA%A6%E5%AE%9A

 

我们知道函数由以下几部分构成:返回值类型 函数名(参数列表),如: 
【code1】

void function();
int add(int a, int b);

以上是大家所熟知的构成部分,其实函数的构成还有一部分,那就是调用约定。如下: 
【code2】

void __cdecl function();
int __stdcall add(int a, int b);

上面的__cdecl和__stdcall就是调用约定,其中__cdecl是C和C++默认的调用约定,所以通常我们的代码都如 【code1】中那样定义,编译器默认会为我们使用__cdecl调用约定。常见的调用约定有__cdecl、__stdcall、fastcall,应用最广泛的是__cdecl和__stdcall,下面我们会详细进行讲述。。还有一些不常见的,如 __pascal、__thiscall、__vectorcall。

声明和定义处调用约定必须要相同

在VC++中,调用约定是函数类型的一部分,因此函数的声明和定义处调用约定要相同,不能只在声明处有调用约定,而定义处没有或与声明不同。如下: 
【code3】 错误的使用一:

int __stdcall add(int a, int b);
int add(int a, int b)
{return a + b;
}

报错:

error C2373: ‘add’: redefinition; different type modifiers 
error C2440: ‘initializing’: cannot convert from ‘int (__stdcall *)(int,int)’ to ‘int’

补充:

int __cdecl add(int a, int b);
int add(int a, int b)
{return a + b;
}

以上就没问题,因为默认是__cdecl。

【code4】 错误的使用二:

int  add(int a, int b);
int __stdcall add(int a, int b)
{return a + b;
}

报错:

error C2373: ‘add’: redefinition; different type modifiers 
error C2440: ‘initializing’: cannot convert from ‘int (__cdecl *)(int,int)’ to ‘int’

【code5】 错误的使用三:

int __stdcall add(int a, int b);
int __cdecl add(int a, int b)
{return a + b;
}

报错:

error C2373: ‘add’: redefinition; different type modifiers 
error C2440: ‘initializing’: cannot convert from ‘int (__stdcall *)(int,int)’ to ‘int’

【code6】 正确的用法:

int __stdcall add(int a, int b);
int __stdcall add(int a, int b)
{return a + b;
}

函数的调用过程

要深入理解函数调用约定,你须要了解函数的调用过程和调用细节。 
假设函数A调用函数B,我们称A函数为”调用者”,B函数为“被调用者”。如下面的代码,ShowResult为调用者,add为被调用者。

int add(int a, int b)
{return a + b;
}void ShowResult()
{std::cout << add(5, 10) << std::endl;
}

函数调用过程可以这么描述: 
(1)先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。 
(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。 
(3)然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。 
(4)函数B返回后,从当前栈帧的ebp即恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,ebp和esp就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。 
这个过程在AT&T汇编中通过两条指令完成,即: 

   leaveret这两条指令更直白点就相当于:mov   %ebp , %esppop    %ebp

 

__cdecl的特点

__cdecl 是 C Declaration 的缩写,表示 C 和 C++ 默认的函数调用约定。是C/C++和MFCX的默认调用约定。

  • 按从右至左的顺序压参数入栈、。
  • 由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的,返回值在EAX中。因此对于像printf这样可变参数的函数必须用这种约定。
  • 编译器在编译的时候对这种调用规则的函数生成修饰名的时候,在输出函数名前加上一个下划线前缀,格式为_function。如函数int add(int a, int b)的修饰名是_add。

(1).为了验证参数是从右至左的顺序压栈的,我们可以看下面这段代码,Debug进行单步调试,可以看到我们的调用栈会先进入GetC(),再进入GetB(),最后进入GetA()。 

(2).第二点“调用者把参数弹出栈”,这是编译器的工作,暂时没办法验证。要深入了解这部分,需要学习汇编语言相关的知识。

(3).函数的修饰名,这个可以通过对编译出的dll使用VS的”dumpbin /exports ProjectName.dll”命令进行查看(后面章节会进行详细介绍),或直接打开.obj文件查找对应的方法名(如搜索add)。

从代码和程序调试的层面考虑,参数的压栈顺序和栈的清理我们都不用太观注,因为这是编译器的决定的,我们改变不了。但第三点却常常困扰我们,因为如果不弄清楚这点,在多个库之间(如dll、lib、exe)相互调用、依赖时常常出出现莫名其妙的错误。这个我在后面章节会进行详细介绍。

__stdcall的特点

__stdcall是Standard Call的缩写,是C++的标准调用方式,当然这是微软定义的标准,__stdcall通常用于Win32 API中(可查看WINAPI的定义)。   microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall,如果用vc开发dll给其他语言用,则应该指定__stdcall方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__cdecl方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__stdcall的规则,一定要在函数退出(ret)前恢复堆栈。

  • 按从右至左的顺序压参数入栈。
  • 由被调用者把参数弹出栈。切记:函数自己在退出时清空堆栈,返回值在EAX中。
  • __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_function@number。如函数int sub(int a, int b)的修饰名是_sub@8。

__fastcall的特点

__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的。

  • 实际上__fastcall用ECX和EDX传送前两个DWORD或更小的参数,剩下的参数仍自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。
  • __fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@number,如double multi(double a, double b)的修饰名是@multi@16。
  • __fastcall和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第1个参数进ECX,第2个进EDX,其他参数是从右向左的入栈,返回仍然通过EAX。

__thiscall

__thiscall是C++类成员函数缺省的调用约定,但它没有显示的声明形式。因为在C++类中,成员函数调用还有一个this指针参数,因此必须特殊处理,thiscall调用约定的特点:

  • 参数入栈:参数从右向左入栈
  • this指针入栈:如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入栈。
  • 栈恢复:对参数个数不定的,调用者清理栈,否则函数自己清理栈。

总结

这里主要总结一下_cdecl、_stdcall、__fastcall三者之间的区别:

要点__cdecl__stdcall__fastcall
参数传递方式右->左右->左左边开始的两个不大于4字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数自右向左压栈传送
清理栈方调用者清理被调用函数清理被调用函数清理
适用场合C/C++、MFC的默认方式; 可变参数的时候使用;Win API要求速度快
C编译修饰约定_functionname_functionname@number@functionname@number

以上内容参考:https://blog.csdn.net/luoweifu/article/details/52425733#commentBox

_cdecl 是C Declaration的缩写,表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。被调用函数无需要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是Standard Call的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retn X,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

PASCAL 是Pascal语言的函数调用方式,也可以在C/C++中使用,参数压栈顺序与前两者相反。返回时的清栈方式忘记了。。。

_fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。

_thiscall 是为了解决类成员调用中this指针传递而规定的。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C++编译器使用eax。返回方式和_stdcall相当。

_fastcall 和 _thiscall涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。

C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。

带有可变参数的函数必须且只能使用_cdecl方式,例如下面的函数:
int printf(char * fmtStr, ...);
int scanf(char * fmtStr, ...);

这两个关键字看起来似乎很少和我们打交道,但是看了下面的定义(来自windef.h
),你一定会觉得惊讶:
     #define CALLBACK     __stdcall
     #define WINAPI       __stdcall
     #define WINAPIV      __cdecl
     #define APIENTRY     WINAPI
     #define APIPRIVATE   __stdcall
     #define PASCAL       __stdcall
     #define cdecl _cdecl
     #ifndef CDECL
     #define CDECL _cdecl
     #endif
    几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,为什么??
     首先,我们谈一下两者之间的区别:
       WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??
       如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。
       如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。
       那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。
       到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WCF从理论到实践(14):WCF解决方案模板 (转)

WCF从理论到实践(14):WCF解决方案模板 正所谓磨刀不误砍柴工,虽然VS2008为我们提供了WCFServiceLibrary项目模板,但在实际开发的时候,我们通常更喜欢按照自己的方式来建立WCF项目,通常情况下,我们将服务契约(通常是接口)数据契约,消息契约等契约单独作为一个项目,而将服务的实现…

java面试宝典 多线程,《java面试宝典》之java多线程面试题

1&#xff1a;什么是线程&#xff1f;轻量级的进程2&#xff1a;线程的三个部分是&#xff1f;处理机代码数据3&#xff1a;为什么使用多线程使UI响应更快利用多处理器系统简化建模4&#xff1a;代码示例&#xff1a;Java中实现多线程的两种方式&#xff0c;包括如何定义多线程…

【转】__declspec用法详解

__declspec用法详解 __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。其它的有关存储方式的修饰符如static与extern等是C和 C语言的ANSI规范&#xff0c;而__declspec是一种扩展属性的定义。扩展属性语法简化并标准化了C和C语言关于Microsoft的扩展。 用法&am…

EBOOT跳转到NK的过程

先做个说明&#xff1a;我的平台环境是&#xff1a;CE5.0&#xff08;S3C2450&#xff09;。 我的config.bib定义的镜像起始地址为0x8c20 0000(虚拟地址), EBoot将镜像下载到以0x8c20 0000为起始地址的RAM中, 但实际上OS跳转的地址却是0x8c20 1000, 也就是说, 传递到Lauch函数的…

thinkphp index.php隐藏,thinkphp5怎么隐藏index.php入口文件?

隐藏方法&#xff1a;1、打开apache的http.conf配置文件&#xff0c;开启mod_rewrite.so模块&#xff1b;2、AllowOverride None项中将None改为All&#xff1b;3、修改“.htaccess”的配置内容&#xff0c;将原代码替换为官方手册提供的代码。thinkphp现在的php主流框架之一&am…

【转】extern “C“和__declspec(dllexport)以及__declspec(dllimport) 和def的简单解析

转自&#xff1a;https://blog.csdn.net/xupan_jsj/article/details/9028759 前面的extern "C" __declspec(dllexport) __declspec(dllimport)都是用于函数或者变量&#xff0c;甚至类的声明的&#xff08;可以把extern "C"放在class的前面&#xff0c;…

JAGUARSDN1网络的开机自动启动 禁用,WIFI模块的启动关闭控制

先确认下系统中有没有加载NDISPWR.DLL&#xff0c;如果没有的话&#xff0c;把这个组件加上 WIFI在默认情况下&#xff0c;是开机自动打开的&#xff0c;如果要开机禁用&#xff0c;在HKEY_LOCAL_MACHINE/Comm/NdisPower创建一个键值 name 4 name是你用的WIFI的名字 如果想…

高考临考突发情况应急预案大全

临考感冒看卷头痛如何应对 高考应急预案助考生 明天&#xff0c;全省49万余考生就将走进高考考场&#xff0c;考生顺利迎考是全社会的心愿&#xff0c;可种种意外总有可能出现在考生面前。高考过程中遇到意外情况如何处理&#xff1f;昨天&#xff0c;本报记者约请了多位考试专…

php病毒图片后缀名,脚本图片类后门病毒的完美使用方法

前两天&#xff0c;看了一篇《脚本注入图片新方法》的文章&#xff0c;相信很多人都通过这篇文章了解了如何在图片中加入脚本&#xff0c;以及如何在正常的asp(或php)文件中通过include函数使图片中的脚本产生效用。但是&#xff0c;这种方法的问题又随之而来了&#xff1a;有人…

WPF指南之XAML概述

[转]WPF指南之XAML概述 周日, 05/04/2008 - 23:26 — robot 出处: it168要赢得世界&#xff0c;必须在恰当的时间做出恰当的事。这一点&#xff0c;微软做到了。历经微软DOS&#xff0c;Win 31, Win95, Win 98, Win 2k, WinXP, 一路走来&#xff0c;一次比一次热闹&#xff0c;…

如何修改wince的网络配置

如何修改wince的网络配置呢&#xff1f; 首先&#xff0c;必须知道网卡驱动名字。在s3c2410上&#xff0c;名字叫“CS8900”&#xff0c;用工具连接上wince查看他的注册表。你将可以得到下面的东西。 [HKEY_LOCAL_MACHINE/Comm/CS8900] "DisplayName""CS8900&qu…

【转】extern “C“以及__declspec(dllexport) 讲解和def文件dll导出方法

转自&#xff1a;https://blog.csdn.net/qing666888/article/details/41135245 一&#xff0c;__ declspec&#xff08;dllexport&#xff09;&#xff1a; 将一个函数声名为导出函数&#xff0c;就是说这个函数要被其他程序调用&#xff0c;即作为DLL的一个对外函数接口。通常…

php源码查找替换,php 替换模板中的 PHP源码标签字符方法

//替换php代码function RepPhpAspJspcode($string){global $public_r;if(!$public_r[candocode]){//$stringstr_replace("<?xml ","[!--ecms.xml--]",$string);$stringstr_replace("$stringstr_replace("\\>","\\>",$s…

【转】DICOM医学图像处理:浅析SWF、MWL、SPS、MPPS

转自&#xff1a;https://blog.csdn.net/zssureqh/article/details/40151107 背景&#xff1a; 最近重新花时间阅读了DICOM标准&#xff0c;顺带着看了一下HL7标准和IHE&#xff0c;对标题中提到的SWF、MWL、SPS和MPPS有了更进一步的认识&#xff0c;现将自己的理解整理出来&a…

Parallel Extensions CTP第二版发布

Parallel Extensions CTP第二版发布 LazyBee 2008年6月微软Parallel Extensions项目组发布了Parallel Extendsions CTP的第二个版本。这个版本主要包含以下组件&#xff1a; 1 任务并行库TPL(Task Parallel Library): 提供命令的方式将面向数据的操作以及轻量级的任务自动的运行…

wince中的背光灯控制

要控制背光灯就必须知道相关设置&#xff0c;以下是wince中背光灯的设置。在BL_ReadRegistry函数中被读取。 [HKEY_CURRENT_USER/ControlPanel/BackLight] "ACTimeout"dword:0000012c "UseExt"dword:00000001 "UseBattery"dword:00000001 …

Php点击更换封面,JavaScript_js实现点击图片改变页面背景图的方法,本文实例讲述了js实现点击图 - phpStudy...

js实现点击图片改变页面背景图的方法本文实例讲述了js实现点击图片改变页面背景图的方法。分享给大家供大家参考。具体实现方法如下&#xff1a;点击图片即改变页面的背景图片希望本文所述对大家的javascript程序设计有所帮助。相关阅读:C语言编程中统计输入的行数以及单词个数…

VistaDB 数据库,.NET的新选择

VistaDB 3.3 fully managed embedded database engine runs Nothing but .Net! Designed and built as a 100% managed code database engine. Now with TSQL Procs! 商业版&#xff0c;提供ADO.NET 2.0 的Provider。商业版。但是有 Express 版&#xff0c;可应用于非商业环境。…

wince中重启网卡

WCHAR Name[]_T("CS89001/0"); HANDLE m_hFileHandle CreateFile(_T("NDS0:"), 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) INVALID_HANDLE_VALUE); if( m_hFileHandle INVALID_HANDLE_VALUE ) { //获得网卡名时打开设备错误 …

【转】DICOM的常用Tag分类和说明

转自&#xff1a;https://blog.csdn.net/inter_peng/article/details/46513847 1. 前言&#xff1a; 基于DICOM3.0标准的医学图像中&#xff0c;每一张图像中都携带着许多的信息&#xff0c;这些信息主要可以分为Patient, Study, Series和Image四类。每一个DICOM Tag都…