译:我在江湖丢了
原文地址:http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/
博客地址:http://lg.uuhonghe.com/index/view?id=3
简介
何为扩展
生命周期
Hello World
创建自己的扩展
ini 配置
全局变量
设置 ini 为全局变量
完整性检查
然后哩?
简介
如果你正阅读本教程,那你可能对PHP语言的扩展编写颇感兴趣。如果不是。。。也许你读完之后会发现你对这个之前不知道的东西产生了兴趣。
本文假设读者基本了解PHP语言和用C写的PHP解释器。
让我们先确认一下你为何想写一个PHP扩展:
1、由于语言内核的抽象深度使你有一些库和系统调用无法使用PHP直接完成。
2、你希望PHP以一些不寻常的方法实现自身行为。
3、你已经写了一堆PHP代码,但你知道它可以跑得更快。
4、你有个实现了特别机智点子的代码想卖,但更重要的是你要卖的代码要能跑但不能在源码里看到。
这些都是非常正当的理由了,但要创建一个扩展,首先你得理解什么是扩展。
何为扩展?
如果你写过PHP,那你一定用过扩展了。只需要小小的几个扩展,一切PHP里的用户空间功能都在这个或那个扩展的函数组里了。大量这些函数都在标准扩展的一部分——标准扩展总共的400多个。PHP源码里捆绑了86个扩展,平均每个有大概30个函数。掐指一算,总约2500个函数。如果这还不够,PECL仓库里还提供了100个以上的附加扩展,更多的可以再网上别的地方找到。
“这些函数都在扩展里,那还有什么?”你会问,“它们扩展了什么?PHP的核心是什么?”。
PHP的内核由两部分组成。在最底层你能找到Zend引擎(简称ZE)。ZE把人能识别的脚本解析为机器识别的符号,并且在进程空间里运行这些符号。ZE同时处理内存管理,变量域和函数调用。这种区分方式的另一部门是PHP内核。PHP内核处理通信、连接和SAPI层(Server Application Programming Interface, 通常也用于指主机环境,如Apache, IIS, CLI, CGI 等),还提供了控制层对 safe_mode 和 open_basedir 的统一检测,还有和用于文件和网络I/O的用户空间函数fopen(), fread()和fwrite()相关的串流层。
生命周期
当一个SAPI启动,例如在 /usr/local/apache/bin/apachectl start 的响应中,PHP以初始化它的内核子系统开始。在这个启动全程将结束之际,会加载每个扩展的内核并调用他们的模块初始化例程(MINIT)。
这给每个扩展一个机会去初始化内部变量,分配资源,注册资源句柄,并且使用ZE注册它的函数,以便当脚本调这些函数时,ZE知道运行哪段代码。
接下来,PHP等待SAPI层来请求一个页面去处理。在CGI或者CLI SAPI的情况下,这会直接发生并且只发生一次。在Apache, IIS 或者其他一些成熟的 web 服务器SAPI中,这是在远程用户请求时发生,并且或发生多次,可能伴随着并发。无论请求如何到达,PHP以通知ZE建立一个供脚本运行的环境为开始,然后调用每个扩展的请求初始化(RINI)函数。RINI给扩展一个机会去建立自己特定的环境变量,分配请求特定的资源,或执行其他任务如审计。RINI函数行为的一个主要例子是在sessions 扩展里,如果session.auto_start项是开启的, RINI将会自动触发用户空间session_start()函数并且预设置$_SESSION变量。
一旦请求被初始化了,ZE通过翻译PHP脚本为tokens,最后转为opcodes来接管,opcodes能够单步调试和执行。
当其中一个opcodes包含的一个扩展方法被调用,ZE会捆绑上该方法的参数,并且临时性地交出控制直接方法完成。
在脚本运行完成之后,PHP调用每个扩展的请求关闭(RSHUTDOWN)函数来做最后的清理工作(例如保证会话变量到磁盘)。接着,ZE运行一个清理进程(被称为垃圾回收),该进程能有效在请求前期中使用的每个变量上执行unset()操作.
操作完成后,PHP等待SAPI请求另一个文档或者信号关闭。在CGI和CLI SAPI情况下,是没有“下一个请求”的,因此SAPI直接启动关闭进程。在关闭进程中,PHP再次遍历每个扩展,调用模块关闭(MSHUTDOWN)函数,最后关闭自己的内核子系统。
以上或许听来使人生畏,然后当你开始钻石一个工作中的扩展时,一些将逐渐清晰。
内存管理
为了防止写得很烂的扩展内存丢失,ZE用一个表明持续性的附加标识来执行它内部的内存管理器。持续性分配是很重要的,能保证内存分配持续到比一个页面请求还长。相对而言,一个不持续性分配在它分配的请求结束时被释放,无论释放函数是否被调用。例如,用户空间变量会在请求结束之后不再使用时候时分配为不持续性的。
然而也许一个扩展理论上会依赖ZE在页面请求结束时自动释放不持续性内存,这是不推荐的。内存分配会给未回收的一个更长的周期,与内存有关的资源则不太可能会被在恰当的时候关闭,没有清理工作会让这一次工作乱作一团。稍后你会看到,确保分配的数据适时清理其时是一件很简单的事情,下面我们简单的对比一下传统内存分配(必须在使用外部类库时使用)和PHP/ZE中的持续性与未持续性内存分配。
Traditional | Non-Persistent | Persistent |
---|---|---|
*
**
构建一个开发环境
现在我们已经学习了PHP和Zend引擎工作方式背后的一些理论,我猜你想运足功力开始开发了。然后在你开始前,必须得收集一些必备的工作来搭建一个满足你需要的开发环境。
首先,你需要PHP本身,因为这一系列开发工具都离不开PHP。如果你还对使用源码搭建PHP不熟悉,推荐你看下这篇文章先:http://www.php.net/install.unix.
(使用Windows开发PHP扩展的文章稍后给出)。虽然用你的linux发行版里的二进制包安全是非常诱人的,但是这些会遗漏两项在开发过程中十分方便的./configure选项。第一个就是
Hello World
任何没有完成Hello World应用的程序介绍都是不完整的。因此,下面将制作一个只有一个返回字符串"Hello World"的函数的扩展。在PHP代码里你可能这样写:
<?php function hello_word(){ return 'Hello World'; } ?>
现在我们使用PHP扩展来实现这段代码,首先我们在PHP源码的ext/目录下创建目录hello并且进到该目录下。事实上该目录在不在PHP目录树下都可以,但是我让你把它放在这里以便后面将展示一个不相关的概念。该目录下需要创建三个文件:一个包含
config.m4
PHP_ARG_ENABLE(hello, whether to enable Hello World support, [--enable-hello Enable Hello World support]) if test "$PHP_HELLO" = "yes"; then AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World]) PHP_NEW_EXTENSION(hello, hello.c, $ext_shared) fi
php_hello.h
#ifndef PHP_HELLO_H #define PHP_HELLO_H 1 #define PHP_HELLO_WORLD_VERSION "1.0" #define PHP_HELLO_WORLD_EXTNAME "hello" PHP_FUNCTION(hello_world); extern zend_module_entry hello_module_entry; #define phpext_hello_ptr &hello_module_entry #endif
hello.c
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_hello.h" static function_entry hello_functions[] = { PHP_FE(hello_world, NULL) {NULL, NULL, NULL} }; zend_module_entry hello_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_HELLO_WORLD_EXTNAME, hello_functions, NULL, NULL, NULL, NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 PHP_HELLO_WORLD_VERSION, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_HELLO ZEND_GET_MODULE(hello) #endif PHP_FUNCTION(hello_world) { RETURN_STRING("Hello World", 1); }
看得出来,上述示例扩展里的大部分代码是胶-协议语言,用于介绍扩展给PHP并且建立一个对话让它们通信的。只有最后4行代码可以称之后"real code",用于执行用户空间层脚本能交互的任务。确实这一层的代码看上去很像我们之前看的PHP代码也容易看懂:
1、声明一个方法
2、让这个方法返回一个字符串:"Hello World"
3、。。呃。。。1?这个1几个意思?
回忆一下,ZE包含了一套复杂的内存管理层,能确保分配的资源在脚本退出时被释放。然而在内存管理的掌控下,释放同样的块两次是非常大的禁忌。这种行为通常称为"double freeing",是一个常见的段错误的原因,涉及到一个正在调用的程序访问一个不再属于它的内存块。同样的,你不希望允许ZE去释放一个存活于程序空间并且其数据块被其他进程占用的静态字符串buffer(例如我们示例中的"Hello World")。
PHP_FUNCTION(hello_world) { char *str; str = estrup("hello World"); RETURN_STRING(str, 0); }
在此版本中,我们手动地分配内存给"Hello World"这个串,并且最终传回调用脚本,然后把内存传给
编译你的扩展
本练习的最后一步就是将你的扩展编译为一个动态可加载模块。如果你把上面的示例原封不动的抄下来,那么只需要在ext/hello/目录下运行下面三步命令就行:
phpize ./configure --enable-hello (译者注:如果编译PHP的时候使用了 --prefix 参数,此处要加上 --with-php-config 选项, 如笔者编译PHP时使用的是 ./configure --prefix=/use/local/phpdev/ 此处命令应使用 ./configure --enable-hello --with-php-c/local/phpdev/bin/php-config) make
运行完上述三个命令之后,你应该在ext/hello/modules/下找到一个 hello.so 文件。(译者注:如果在make时报错: error: unknown type name 'function_entry' ,可以把 'function_entry' 改为 'zend_function_entry',参见:https://bugs.php.net/bug.php?id=61479
)。现在,就像其他PHP扩展一样,你可以把你的扩展拷贝到扩展目录(默认为,/usr/local/lib/php/extensions/,可以通过php.ini确认)然后在php.ini里加上extension=hello.so一行可以在以触发它在程序启动时被加载到了。对于CGI/CLI SAPIs 来说,启动就指下一次运行PHP;而对我web server SAPIs如Apache来说,启动指下次web server重启。让我们试下运行下面命令:
$ php -r 'echo hello_world();'
如果一切顺利,你现在应该能看到这段代码输出"Hello World"了,因为你的扩展里的"hello_world()"返回了一个字符串"Hello World",而echo命令会原封不动地显示传递给他的参数(此处即为该函数的返回值)。
其他标量也可用类似的方式返回,使用
static function_entry hello_functions[] = { PHP_FE(hello_world, NULL) PHP_FE(hello_long, NULL) PHP_FE(hello_double, NULL) PHP_FE(hello_bool, NULL) PHP_FE(hello_null, NULL) {NULL, NULL, NULL} }; PHP_FUNCTION(hello_long) { RETURN_LONG(42); } PHP_FUNCTION(hello_double) { RETURN_DOUBLE(3.1415926535); } PHP_FUNCTION(hello_bool) { RETURN_BOOL(1); } PHP_FUNCTION(hello_null) { RETURN_NULL(); }
你同样需要在头文件php_hello.h里
PHP_FUNCTION(hello_world); PHP_FUNCTION(hello_long); PHP_FUNCTION(hello_double); PHP_FUNCTION(hello_bool); PHP_FUNCTION(hello_null);
因为你没有修改config.m4文件,所以技术上这次跳过phpize和./configure这两个步骤直接make是安全的。然后,在本游戏的这个阶段,我还是要求你从头把三个步骤都执行一遍以确认活干得漂亮。另外,最后一步的时候,你应该执行make clean all而不是简单的执行make,来确保所有源文件重建。再次声明,现在的改动上述这些步骤是非必须的,但是会更安全更清晰。模块建好后,再拷贝到你的扩展目录下,替换旧版本。
这个时候你可以再次调用你的PHP解析器,运行一段简单的脚本来试试你刚刚添加的方法。事实上,为何不现在不试呢?我等着呢。。。
试完了?很好。如果你使用
PHP_FUNCTION(hello_bool){ RETURN_TRUE; }
注意这里没有使用括号哦。
你也许注意到上面这些代码样品我们都没有传0和1什来表示这些值是否需要被拷贝。这是因为没有额外的内存(变量容器之外——我们将在第2部分深入)需要被分配或释放,因为这些标量都很简单很小。
还有另外三种返回类型:
INI Settings
Zend 引擎提供了两个方式处理
现在我们想在php.ini中定义一个变量,"hello.greeting", 用来处理你在"hello_function()"函数里用来打招呼的变量。你需要在hello.c和php_hello.h中添另一些东西,并且
PHP_MINIT_FUNCTION(hello); PHP_MSHUTDOWN_FUNCTION(hello); PHP_FUNCTION(hello_world); PHP_FUNCTION(hello_long); PHP_FUNCTION(hello_double); PHP_FUNCTION(hello_bool); PHP_FUNCTION(hello_null);
现在到hello.c中用下面这串代码覆盖当前版本的
zend_module_entry hello_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_HELLO_WORLD_EXTNAME, hello_functions, PHP_MINIT(hello), PHP_MSHUTDOWN(hello), NULL, NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 PHP_HELLO_WORLD_VERSION, #endif STANDARD_MODULE_PROPERTIES }; PHP_INI_BEGIN() PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL) PHP_INI_END() PHP_MINIT_FUNCTION(hello) { REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(hello) { UNREGISTER_INI_ENTRIES(); return SUCCESS; }
现在,你只需要在hello.c顶部剩下的
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h "#include "php_hello.h"
最后,我们修改
PHP_FUNCTION(hello_world) { RETURN_STRING(INI_STR("hello.greeting"), 1); }
注意,你复制了来自
首次修改的部分包含了两个你需要熟悉的方法:
在你的方法hellow_world()中使用"INI_STR()"来取回当前"hello.greeting"项的值作为一个字符串。那些其他的已有方法取值作为长整型,浮点型和布尔型,如下表所示,"ORIG"补充了其他方法,能提供从
Current Value | Original Value | Type |
signed long | ||
signed double | ||
传入
第二个参数是初始值,并且通常是作为char*串不管是不是数字。这主要是因为实际上.ini文件里的值默认是文本——那是一个文本文件。你可以在你的脚本中使用
传入的第三个参数是一个访问模式修饰符。这是一个用于决定
我们就此跳过第四个参数,只点出该值用来传入一个回调方法便以ini配置无论在何时被修改时调用,比如当使用
全局变量
通常,扩展需要在特定的请求里跟踪变量的值,使之独立于并发请求。在无线程的SAPI中这可能比较简单:只需要在源文件中声明一个全局变量,在需要时调用。然而麻烦在于PHP被设计运行于线程级的web服务器(如Apache 2 和 IIS),这就需要保证一个线程中的全局变量与其他线程中的分离。PHP通过使用TSRM(Thread Safe Resource Management)抽象层,大大地简化了这一操作,有时被称为ZTS(Zend Thread Safety)。实际 上,到现在你已经使用了一部分TSRM了,虽然你对其不甚了解。(不要急着去搜索,通过这一系列的进展,你会发现它无处不在。)
创建线程安全全局变量的第一步,跟创建其他全局变量一样,声明它。为了实现这个例子,你将声明一个以
#ifdef ZTS #include "TSRM.h" #endif ZEND_BEGIN_MODULE_GLOBALS(hello) login counter; ZEND_END_MODULE_GLOBALS(hello) #ifdef ZTS #define HELLO_G(v) TSRM(hello_globals_id, zend_hello_globals *, v) #else #define HELLO_G(v) (hello_globals.v) #endif
这次你还将用到
PHP_MINIT_FUNCTION(hello); PHP_MSHUTDOWN_FUNCTION(hello); PHP_RINIT_FUNCTION(hello);
现在 到hello.c中添加下面这段代码到include 模块后:
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "php_hello.h" ZEND_DECLARE_MODULE_GLOBALS(hello)
修改
zend_module_entry hello_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_HELLO_WORLD_EXTNAME, hello_functions, PHP_MINIT(hello), PHP_MSHUTDOWN(hello), PHP_RINIT(hello), NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 PHP_HELLO_WORLD_VERSION, #endif STANDARD_MODULE_PROPERTIES };
修改你的
static void php_hello_init_globals(zend_hello_globals *hello_globals) { } PHP_RINIT_FUNCTION(hello) { HELLO_G(counter) = 0; return SUCCESS; } PHP_MINIT_FUNCTION(hello) { ZEND_INIT_MODULE_GLOBALS(hello, php_hello_init_globals, NULL); REGISTER_INI_ENTRIES(); return SUCCESS; }
最后,修改你的
PHP_FUNCTION(hello_long) { HELLO_G(counter)++; RETURN_LONG(HELLO_G(counter)); }
在添加到php_hello.h的代码里,使用了一对宏
INI设置 vs 全局变量
如果你回观前文,一个在
ZEND_BEGIN_MODULE_GLOBAL(hello) login counter; zend_bool direction; ZEND_ENG_MODULE_GLOBALS(hello)
然后,通过修改
PHP_INI_BEGIN() PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL) STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_hello_globals, hello_globals) PHP_INI_END()
现在在
static void php_hello_init_globals(zend_hello_globals *hello_globals) { hello_globals->direction = 1; }
最后,在hello_long()中使用这个配置的值来决定是自增还是自减:
PHP_FUNCTION(hello_long) { if (HELLO_G(direction)) { HELLO_G(counter)++; } else { HELLO_G(counter)--; } RETURN_LONG(HELLO_G(counter)); }
就是这样,我们在
完整性检查
到现在,我们的三个文件里的内容应该如下所列的(为了可阅读性,一些条目被移到了一起)。
config.m4
PHP_ARG_ENABLE(hello, whether to enable Hello World support, [ --enable-hello Enable Hello World support]) if test "$PHP_HELLO" = "yes"; then AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World]) PHP_NEW_EXTENSION(hello, hello.c, $ext_shared) fi
php_hello.h
#ifndef PHP_HELLO_H #define PHP_HELLO_H 1 #ifdef ZTS #include "TSRM.h" #endif ZEND_BEGIN_MODULE_GLOBALS(hello) long counter; zend_bool direction; ZEND_END_MODULE_GLOBALS(hello) #ifdef ZTS #define HELLO_G(v) TSRMG(hello_globals_id, zend_hello_globals *, v) #else #define HELLO_G(v) (hello_globals.v) #endif #define PHP_HELLO_WORLD_VERSION "1.0" #define PHP_HELLO_WORLD_EXTNAME "hello" PHP_MINIT_FUNCTION(hello); PHP_MSHUTDOWN_FUNCTION(hello); PHP_RINIT_FUNCTION(hello); PHP_FUNCTION(hello_world); PHP_FUNCTION(hello_long); PHP_FUNCTION(hello_double); PHP_FUNCTION(hello_bool); PHP_FUNCTION(hello_null); extern zend_module_entry hello_module_entry; #define phpext_hello_ptr &hello_module_entry #endif
hello.c
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "php_hello.h" ZEND_DECLARE_MODULE_GLOBALS(hello) static function_entry hello_functions[] = { PHP_FE(hello_world, NULL) PHP_FE(hello_long, NULL) PHP_FE(hello_double, NULL) PHP_FE(hello_bool, NULL) PHP_FE(hello_null, NULL) {NULL, NULL, NULL} }; zend_module_entry hello_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_HELLO_WORLD_EXTNAME, hello_functions, PHP_MINIT(hello), PHP_MSHUTDOWN(hello), PHP_RINIT(hello), NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 PHP_HELLO_WORLD_VERSION, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_HELLO ZEND_GET_MODULE(hello) #endif PHP_INI_BEGIN() PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL) STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_hello_globals, hello_globals) PHP_INI_END() static void php_hello_init_globals(zend_hello_globals *hello_globals) { hello_globals->direction = 1; } PHP_RINIT_FUNCTION(hello) { HELLO_G(counter) = 0; return SUCCESS; } PHP_MINIT_FUNCTION(hello) { ZEND_INIT_MODULE_GLOBALS(hello, php_hello_init_globals, NULL); REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(hello) { UNREGISTER_INI_ENTRIES(); return SUCCESS; } PHP_FUNCTION(hello_world) { RETURN_STRING("Hello World", 1); } PHP_FUNCTION(hello_long) { if (HELLO_G(direction)) { HELLO_G(counter)++; } else { HELLO_G(counter)--; } RETURN_LONG(HELLO_G(counter)); } PHP_FUNCTION(hello_double) { RETURN_DOUBLE(3.1415926535); } PHP_FUNCTION(hello_bool) { RETURN_BOOL(1); } PHP_FUNCTION(hello_null) { RETURN_NULL(); }
接下来做什么?
在这教程中我们开发了一个简单的PHP扩展,导出方法,返回值,声明了
下一章我们研究PHP变量的内核结构,以及变量如何存储、跟踪和在脚本环境中修改。当一个函数被调用时我们使用

“你的组织要求你更改PIN消息”将显示在登录屏幕上。当在使用基于组织的帐户设置的电脑上达到PIN过期限制时,就会发生这种情况,在该电脑上,他们可以控制个人设备。但是,如果您使用个人帐户设置了Windows,则理想情况下不应显示错误消息。虽然情况并非总是如此。大多数遇到错误的用户使用个人帐户报告。为什么我的组织要求我在Windows11上更改我的PIN?可能是您的帐户与组织相关联,您的主要方法应该是验证这一点。联系域管理员会有所帮助!此外,配置错误的本地策略设置或不正确的注册表项也可能导致错误。即

Windows11将清新优雅的设计带到了最前沿;现代界面允许您个性化和更改最精细的细节,例如窗口边框。在本指南中,我们将讨论分步说明,以帮助您在Windows操作系统中创建反映您的风格的环境。如何更改窗口边框设置?按+打开“设置”应用。WindowsI转到个性化,然后单击颜色设置。颜色更改窗口边框设置窗口11“宽度=”643“高度=”500“>找到在标题栏和窗口边框上显示强调色选项,然后切换它旁边的开关。若要在“开始”菜单和任务栏上显示主题色,请打开“在开始”菜单和任务栏上显示主题

默认情况下,Windows11上的标题栏颜色取决于您选择的深色/浅色主题。但是,您可以将其更改为所需的任何颜色。在本指南中,我们将讨论三种方法的分步说明,以更改它并个性化您的桌面体验,使其具有视觉吸引力。是否可以更改活动和非活动窗口的标题栏颜色?是的,您可以使用“设置”应用更改活动窗口的标题栏颜色,也可以使用注册表编辑器更改非活动窗口的标题栏颜色。若要了解这些步骤,请转到下一部分。如何在Windows11中更改标题栏的颜色?1.使用“设置”应用按+打开设置窗口。WindowsI前往“个性化”,然

您是否在Windows安装程序页面上看到“出现问题”以及“OOBELANGUAGE”语句?Windows的安装有时会因此类错误而停止。OOBE表示开箱即用的体验。正如错误提示所表示的那样,这是与OOBE语言选择相关的问题。没有什么可担心的,你可以通过OOBE屏幕本身的漂亮注册表编辑来解决这个问题。快速修复–1.单击OOBE应用底部的“重试”按钮。这将继续进行该过程,而不会再打嗝。2.使用电源按钮强制关闭系统。系统重新启动后,OOBE应继续。3.断开系统与互联网的连接。在脱机模式下完成OOBE的所

任务栏缩略图可能很有趣,但它们也可能分散注意力或烦人。考虑到您将鼠标悬停在该区域的频率,您可能无意中关闭了重要窗口几次。另一个缺点是它使用更多的系统资源,因此,如果您一直在寻找一种提高资源效率的方法,我们将向您展示如何禁用它。不过,如果您的硬件规格可以处理它并且您喜欢预览版,则可以启用它。如何在Windows11中启用任务栏缩略图预览?1.使用“设置”应用点击键并单击设置。Windows单击系统,然后选择关于。点击高级系统设置。导航到“高级”选项卡,然后选择“性能”下的“设置”。在“视觉效果”选

在Windows11上的显示缩放方面,我们都有不同的偏好。有些人喜欢大图标,有些人喜欢小图标。但是,我们都同意拥有正确的缩放比例很重要。字体缩放不良或图像过度缩放可能是工作时真正的生产力杀手,因此您需要知道如何对其进行自定义以充分利用系统功能。自定义缩放的优点:对于难以阅读屏幕上的文本的人来说,这是一个有用的功能。它可以帮助您一次在屏幕上查看更多内容。您可以创建仅适用于某些监视器和应用程序的自定义扩展配置文件。可以帮助提高低端硬件的性能。它使您可以更好地控制屏幕上的内容。如何在Windows11

屏幕亮度是使用现代计算设备不可或缺的一部分,尤其是当您长时间注视屏幕时。它可以帮助您减轻眼睛疲劳,提高易读性,并轻松有效地查看内容。但是,根据您的设置,有时很难管理亮度,尤其是在具有新UI更改的Windows11上。如果您在调整亮度时遇到问题,以下是在Windows11上管理亮度的所有方法。如何在Windows11上更改亮度[10种方式解释]单显示器用户可以使用以下方法在Windows11上调整亮度。这包括使用单个显示器的台式机系统以及笔记本电脑。让我们开始吧。方法1:使用操作中心操作中心是访问

Windows上的激活过程有时会突然转向显示包含此错误代码0xc004f069的错误消息。虽然激活过程已经联机,但一些运行WindowsServer的旧系统可能会遇到此问题。通过这些初步检查,如果这些检查不能帮助您激活系统,请跳转到主要解决方案以解决问题。解决方法–关闭错误消息和激活窗口。然后,重新启动计算机。再次从头开始重试Windows激活过程。修复1–从终端激活从cmd终端激活WindowsServerEdition系统。阶段–1检查Windows服务器版本您必须检查您使用的是哪种类型的W


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

WebStorm Mac版
好用的JavaScript开发工具

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

Atom编辑器mac版下载
最流行的的开源编辑器