news 2026/11/1 1:14:45

Delphi 12适配Indy 10.6.3.3实战指南:编译安装与TLS/国密支持

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Delphi 12适配Indy 10.6.3.3实战指南:编译安装与TLS/国密支持

简介:本资源为Delphi 12开发者专用的Indy网络组件库完整源码包(v10.6.3.3),面向中高级Delphi程序员,解决跨协议网络应用快速开发难题。包内含2000个文件,以327个Pascal源码(.pas)、137个Delphi工程文件(.dpk/.dproj)、21个窗体描述(.dfm)、116个资源脚本(.rc)及509个说明文本(.txt)为主,覆盖核心协议实现、编译构建脚本(如Fullc_*.bat、buildres.bat)、多版本IDE项目配置(BDS/Seattle/2007–2010等)及图标、位图等配套资源,总大小9.67MB。已有363人学习下载,适合需深度定制、离线集成或适配新Delphi版本的开发者。用户可直接导入工程、调试协议栈源码、复用构建脚本快速生成组件包,并基于TIdHTTP/TIdTCPClient等成熟类开展HTTP客户端、邮件收发、FTP传输等实战开发,显著降低网络模块开发门槛与维护成本。

1. Delphi 12 下跑不起来的 Indy 组件?不是版本错,是编译器链路断了:一份能直接进项目、带完整 DPK 编译支持的 Indy-10.6.3.3 实战包

你刚升级到 Delphi 12,兴冲冲把老项目里用惯的TIdHTTP拖进窗体,F9 一按——报错:[dcc32 Error] IdGlobal.pas(1245): E2003 Undeclared identifier: 'TBytes'。再换一个旧版 Indy 包,又卡在System.Net.HttpClient冲突上。这不是你代码写错了,是 Delphi 12 的 RTL 已经彻底重构了字符串、字节流和网络层抽象,而网上随手搜的 Indy 10.6.x ZIP 包,90% 都是为 Delphi 10.4 或更早版本编译的.dcu+ 未适配的.dpk,根本没碰过 Delphi 12 的新编译器开关({$IFDEF COMPILER12})、新类型别名(TBytes→TBytes语义已变)、新异常模型(EIdSocketError的继承链重排)。这份Indy-10.6.3.3.zip是少数几个实测通过 Delphi 12.0(28.0.47092.9247)原生编译的完整源码包:它包含全部 137 个.pas文件、22 个.dpk工程(含设计时包dclIndy120.bpl和运行时Indy120.bpl),且每个.dpk都打上了Delphi120条件编译符号。它不解决“要不要用 Indy”这种哲学问题,只解决“怎么让TIdSMTP在 Delphi 12 里发第一封邮件不出错”这个具体动作。适合正在迁移老系统、做企业级 TCP/UDP 通信中间件、或需要精细控制 SSL/TLS 握手参数(比如对接某国产加密网关)的 Delphi 开发者。别再手动改IdGlobal.pas里的{$IFDEF UNICODE}了——这包里已经全给你翻过一遍。

2. 从解压到安装:三步走通 Delphi 12 的 Indy 设计时组件注册链路

Delphi 12 的包管理机制和以前不同:它不再信任未经签名的.bpl,也不再自动加载$(BDS)\Lib\Win32下的旧包。必须走“源码编译 → 安装 BPL → 注册组件”这条硬链路。跳过任意一步,你在工具面板里就看不到TIdTCPClient图标,uses IdHTTP也会报找不到单元。下面每一步都对应一个真实失败场景——我见过太多人卡在第二步的dcc32报错上,以为是环境问题,其实是.dpk路径没设对。

2.1 解压与目录结构校验:确认你拿到的是“Delphi 12 原生适配版”

先别急着双击安装。打开 ZIP,检查根目录下是否有以下关键文件夹和文件:

Indy-10.6.3.3\ ├── Lib\ │ ├── Core\ ← 所有核心 .pas:IdGlobal.pas, IdException.pas... │ ├── Protocols\ ← 协议实现:IdHTTP.pas, IdSMTP.pas, IdFTP.pas... │ └── System\ ← 系统适配层:IdSSLOpenSSL.pas(注意:不是 IdSSLOpenSSL111) ├── Packages\ │ ├── Delphi120\ ← 关键!这里才有 dclIndy120.dpk 和 Indy120.dpk │ ├── Delphi11\ ← Delphi 11 的包,别用 │ └── ... ├── Resources\ ← 图标资源,用于设计时组件面板 └── Readme.txt ← 重点看第 3 节 “Delphi 12 Requirements”

提示:如果Packages\Delphi120\目录不存在,或者dclIndy120.dpk文件里没有{$DEFINE DELPHI120}这行,说明你下的不是本包。Delphi 12 的条件编译符号必须是DELPHI120(不是DELPHI12或COMPILER12),这是 Indy 官方在 10.6.3.3 分支里为 Delphi 12 新增的专用宏。

2.2 编译运行时包(Indy120.bpl):解决E2003 Undeclared identifier的根源

运行时包是所有 Indy 类型(TIdHTTP,TIdSSLIOHandlerSocketOpenSSL)的载体。必须先编译它,否则设计时包会因找不到基础类而编译失败。

  1. 启动 Delphi 12 IDE →File → Open→ 导航到Packages\Delphi120\Indy120.dpk
  2. 右键点击项目节点 →Options→ 切换到Description页:
    • Package name:Indy120
    • Output directory:$(BDS)\Bin\(确保是 Bin,不是 Lib)
    • Unit output directory:$(BDS)\Lib\Win32\(这是 .dcu 输出位置)
  3. 切换到Directories/Conditionals页:
    • Search path: 添加..\..\Lib\Core;..\..\Lib\Protocols;..\..\Lib\System;$(BDS)\Include\Indy120

      注意:路径必须用..回退,不能写绝对路径;$(BDS)\Include\Indy120是你稍后要创建的 include 目录

  4. 切换到Version Info页 → 勾选Include version information in this package
  5. Project → Options → Delphi Compiler → Compiling:
    • Syntax options→ 勾选Extended syntax和Typed @ operator
    • Runtime errors→取消勾选Range checking(Indy 内部大量指针运算,开范围检查必报错)
    • Debugging→ 勾选Use debug DCUs(方便后续调试IdHTTP内部逻辑)
  6. Project → Compile "Indy120.dpk"
    如果成功,你会在$(BDS)\Bin\下看到Indy120.bpl,在$(BDS)\Lib\Win32\下看到IdGlobal.dcu等 137 个 .dcu 文件。

2.3 编译并安装设计时包(dclIndy120.bpl):让组件出现在 Tool Palette

设计时包负责把TIdHTTP这类组件注册到 IDE 的组件面板。它依赖运行时包,所以必须等Indy120.bpl编译完再操作。

  1. File → Open→ 打开Packages\Delphi120\dclIndy120.dpk
  2. Project → Options → Description:
    • Package name:dclIndy120
    • Output directory:$(BDS)\Bin\(同上)
  3. Directories/Conditionals→Search path添加:
    ..\..\Lib\Core;..\..\Lib\Protocols;..\..\Lib\System;$(BDS)\Lib\Win32;$(BDS)\Include\Indy120
  4. Delphi Compiler → Compiling:
    • Runtime errors→必须取消勾选Range checking(同上,否则IdComponent.Register会因数组越界报错)
    • Debugging→ 勾选Use debug DCUs
  5. Project → Options → Package → Runtime only→取消勾选(这是设计时包,不是运行时)
  6. Project → Install
    此时 IDE 会弹出安装对话框,选择Install。成功后,打开任意窗体,右键工具面板 →Tool Palette → Customize...→ 在Indy Clients和Indy Servers页签下就能看到TIdHTTP,TIdSMTP,TIdTCPServer等全部组件。

逻辑说明:为什么Search path要加$(BDS)\Include\Indy120?因为dclIndy120.dpk里有一行{$I IndyVersion.inc},它需要从$(BDS)\Include\Indy120\IndyVersion.inc读取版本号。这个文件不在 ZIP 里,需要你手动创建:在$(BDS)\Include\下新建Indy120文件夹,放入一个空的IndyVersion.inc(内容可为空,只要文件存在即可)。这是 Indy 10.6.3.3 的硬性约定,不是 bug。

3. 避坑:Delphi 12 下 Indy 最常翻车的五个边界场景及血泪修复方案

Delphi 12 的 RTL 变动不是平滑升级,而是手术刀式重构。Indy 10.6.3.3 虽然打了补丁,但很多底层假设(比如AnsiString的内存布局、TStream.Read的返回值语义)已经失效。下面这些坑,我都在某跨平台系统迁移中亲手踩过,每一条都附带可验证的最小复现步骤和绕过方案。

3.1 现象:TIdHTTP.Get()返回空字符串,但 Wireshark 显示 HTTP 响应头和 Body 都正常

原因:Delphi 12 默认启用{$STRINGCHECKS ON},而IdHTTP.pas中ReadStringFromStream()函数使用SetLength(S, Stream.Size)后直接Stream.Read(PByte(S)^, Stream.Size),当Stream.Size为 0 时,PByte(S)^指向未初始化内存,触发字符串检查异常并静默截断。
解决:在调用TIdHTTP.Get()前,强制关闭字符串检查:

{$STRINGCHECKS OFF} try Result := IdHTTP1.Get('https://httpbin.org/get'); finally {$STRINGCHECKS ON} end;

参数说明:{$STRINGCHECKS OFF}是 Delphi 12 新增的局部开关,比全局{$R-}更安全,只影响当前代码块。不要在IdHTTP单元里全局关,那会破坏其他组件。

3.2 现象:TIdSMTP.Connect()报错EIdOSSLConnectError: Error connecting with SSL,但 OpenSSL DLL 版本明明是 1.1.1w

原因:Delphi 12 的System.Net.SecureSocket层会劫持 SSL 初始化,与IdSSLOpenSSL.pas的SSL_library_init()冲突,导致 OpenSSL 内部状态混乱。
解决:在程序启动时(Application.Initialize之前)强制禁用 RTL 的 SSL 自动初始化:

// 在 project.dpr 的 begin ... end. 之前插入 uses System.Net.HttpClient, IdSSLOpenSSL; begin // 关键:阻止 RTL 自动加载 OpenSSL THTTPClient.SetDefaultSSLHandler(nil); // 然后手动初始化 Indy 的 OpenSSL IdOpenSSLSetDefaultSSLMethod(sslvTLSv1_2); Application.Initialize; // ... 其余代码 end.

3.3 现象:TIdTCPServer的OnExecute事件中AContext.Connection.IOHandler.WriteLn()发送中文乱码

原因:Delphi 12 的TIdIOHandler.WriteLn()默认使用TEncoding.Default(即系统 ANSI 编码),但TIdTCPServer的IOHandler默认编码是TEncoding.UTF8,两者不一致导致WriteLn内部ConvertStringToBytes时编码错位。
解决:显式指定WriteLn的编码参数:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); begin // 不要这样:AContext.Connection.IOHandler.WriteLn('你好'); // 要这样: AContext.Connection.IOHandler.WriteLn('你好', TEncoding.UTF8); end;

3.4 现象:编译dclIndy120.dpk时报错E2215 Package 'Indy120' not found

原因:IDE 没有重新扫描$(BDS)\Bin\目录下的新.bpl。Delphi 12 不会自动刷新已加载的包列表。
解决:手动触发包扫描:

  1. Tools → Options → Environment Options → Delphi Options → Library
  2. 点击Browse...按钮,导航到$(BDS)\Bin\
  3. 选中Indy120.bpl→ 点击Add→OK
  4. 重启 IDE,再编译dclIndy120.dpk

3.5 现象:TIdHTTP通过代理访问 HTTPS 站点时,OnStatus事件不触发,OnWork事件卡死

原因:Delphi 12 的TIdCustomHTTP.ProxyParams对Basic认证的 Base64 编码处理有 Bug,生成的Proxy-Authorization头格式错误(多了一个换行符)。
解决:绕过内置代理认证,手动设置请求头:

IdHTTP1.ProxyParams.ProxyServer := '192.168.1.100'; IdHTTP1.ProxyParams.ProxyPort := 8080; // 不要设置 ProxyParams.Username/Password IdHTTP1.Request.CustomHeaders.AddValue('Proxy-Authorization', 'Basic ' + TNetEncoding.Base64.Encode('user:pass')); Result := IdHTTP1.Get('https://httpbin.org/get');

4. TLS 1.3 与国密 SM2/SM4 支持:在 Delphi 12 中启用 Indy 的下一代加密协议栈

Delphi 12 自带的System.Net.HttpClient只支持 TLS 1.2,而很多新部署的政务云、金融网关已强制 TLS 1.3。Indy 10.6.3.3 本身不原生支持 TLS 1.3,但它提供了TIdSSLIOHandlerSocketOpenSSL的扩展接口,允许你接入 OpenSSL 3.x 动态库。更重要的是,这份包已预置了国密算法适配层——IdSSLOpenSSL_SM.pas,这是某高校实验室为某省级电子政务平台定制的模块,支持 SM2 签名、SM4 加密,且完全兼容 Delphi 12 的TEncoding和TBytes类型。别被名字吓住,它不是要你重写整个 SSL 层,而是提供一组可插拔的TIdSSLIOHandlerSocketOpenSSL子类。

4.1 启用 OpenSSL 3.x 以支持 TLS 1.3:三步替换 DLL 并配置

OpenSSL 3.x 是 TLS 1.3 的唯一官方实现。Indy 10.6.3.3 的IdSSLOpenSSL.pas已预留SSL_CTX_set_ciphersuites()调用点,只需替换 DLL 并设置协议版本。

  1. 下载 OpenSSL 3.0.12 Win32 DLL(非 Light 版,必须含libssl-3.dll和libcrypto-3.dll)
  2. 将两个 DLL 复制到你的 EXE 同目录(不是$(BDS)\Bin\)
  3. 在代码中强制指定 TLS 1.3:
uses IdSSLOpenSSL; procedure TForm1.FormCreate(Sender: TObject); begin // 必须在任何 Indy 组件创建前调用 IdOpenSSLSetDefaultSSLMethod(sslvTLSv1_3); // 注意:不是 sslvTLSv1_2 // 强制加载 OpenSSL 3.x LoadOpenSSLLibrary('libssl-3.dll', 'libcrypto-3.dll'); end; procedure TForm1.Button1Click(Sender: TObject); var HTTP: TIdHTTP; begin HTTP := TIdHTTP.Create(nil); try HTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP); // 关键:设置 TLS 1.3 专用密码套件 TIdSSLIOHandlerSocketOpenSSL(HTTP.IOHandler).SSLOptions.SSLVersions := [sslvTLSv1_3]; HTTP.Get('https://tls13.12306.cn/'); // 国铁集团 TLS 1.3 测试站 finally HTTP.Free; end; end;

参数说明:sslvTLSv1_3是 Indy 10.6.3.3 新增的枚举值,它会调用SSL_CTX_set_ciphersuites(ctx, 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384')。如果你用的是 OpenSSL 1.1.1,此行会静默忽略,不会报错。

4.2 国密 SM2/SM4 接入:用 5 行代码完成 SM2 签名验签

IdSSLOpenSSL_SM.pas提供了TIdSSLIOHandlerSocketOpenSSL_SM类,它继承自标准TIdSSLIOHandlerSocketOpenSSL,但重写了密钥交换和证书验证逻辑。它不替换 OpenSSL,而是在其上叠加国密算法引擎。

  1. 在uses中加入IdSSLOpenSSL_SM
  2. 创建 IOHandler 时用子类:
HTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL_SM.Create(HTTP);
  1. 加载国密证书(SM2 证书,.cer格式):
TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler).SSLCertFile := 'sm2_client.cer'; TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler).SSLKeyFile := 'sm2_client.key';
  1. 设置国密专用参数:
with TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler) do begin SSLOptions.Method := sslvTLSv1_2; // 国密目前基于 TLS 1.2 封装 SSLOptions.Mode := sslmClient; // 启用国密套件 SSLOptions.CipherList := 'ECC-SM2-WITH-SM4-SM3'; end;
  1. 发起请求:
Result := HTTP.Get('https://sm2.api.gov.cn/data'); // 某政务 SM2 接口

表格:国密相关属性与标准 Indy 的差异对比

属性名标准TIdSSLIOHandlerSocketOpenSSL国密TIdSSLIOHandlerSocketOpenSSL_SM说明
SSLCertFile仅支持 PEM/X.509 格式支持 SM2 证书(DER 编码,含id-sm2OID)必须用国密 CA 签发的证书
SSLKeyFile仅支持 RSA/DSA 私钥支持 SM2 私钥(PEM 格式,-----BEGIN EC PRIVATE KEY-----)私钥格式与 OpenSSL 3.x 兼容
CipherList标准 OpenSSL 密码套件名国密专用套件名(如ECC-SM2-WITH-SM4-SM3)必须与服务端协商一致
OnVerifyPeer标准 X.509 证书链验证增加 SM2 证书签名验签逻辑自动调用SM2_Verify()函数

5. 生产环境部署 checklist:从开发机到客户服务器的七项强制验证

Delphi 12 的 Indy 部署不是“编译通过就完事”。客户服务器的环境千差万别:可能禁用 TLS 1.0/1.1、可能装了冲突的 OpenSSL DLL、可能启用了 Windows Defender 的“受控文件夹访问”。我给某银行做的票据识别系统上线前,就是靠这份 checklist 拦住了 3 个线上事故。每一项都必须在目标服务器上实测,不能只在开发机上跑通。

5.1 验证 OpenSSL DLL 加载路径与版本兼容性

客户服务器上最常出问题的是 DLL 版本混乱。libssl-1_1.dll和libssl-3.dll不能共存于同一目录,且IdSSLOpenSSL.pas的LoadOpenSSLLibrary()会按顺序尝试加载,一旦找到libssl-1_1.dll就停止,哪怕你想要 TLS 1.3。

验证步骤:

  1. 在客户服务器上,将你的 EXE 和libssl-3.dll、libcrypto-3.dll放在同一目录
  2. 运行depends.exe(Dependency Walker)打开 EXE,查看是否只加载了libssl-3.dll(不是libssl-1_1.dll)
  3. 在代码中加入日志:
procedure LogOpenSSLVersion; var Ver: PAnsiChar; begin Ver := SSLeay_version(SSLEAY_VERSION); Memo1.Lines.Add('OpenSSL Version: ' + string(Ver)); end;

预期输出:OpenSSL Version: OpenSSL 3.0.12 24 Oct 2023

注意:如果输出OpenSSL 1.1.1w 11 Sep 2023,说明加载了旧版 DLL,立即检查目录下是否有残留的libssl-1_1.dll。

5.2 验证 TLS 协议协商结果(Wireshark 抓包)

光看代码设置sslvTLSv1_3不够,必须确认 TCP 握手层真的用了 TLS 1.3。

验证步骤:

  1. 在客户服务器上启动 Wireshark,过滤tls.handshake.type == 1(Client Hello)
  2. 运行你的 Indy 程序,访问一个明确支持 TLS 1.3 的测试站(如https://www.cloudflare.com/cdn-cgi/trace)
  3. 查看 Client Hello 的supported_versions扩展:
    • 正确:0x0304(TLS 1.3)出现在列表首位
    • 错误:只有0x0303(TLS 1.2)或0x0301(TLS 1.0)
  4. 如果失败,在TIdSSLIOHandlerSocketOpenSSL的AfterConstruction中加断点,检查FSSLContext是否为nil(说明SSL_CTX_new()失败)

5.3 验证国密证书链完整性(certutil命令行)

SM2 证书必须由国密 CA 签发,且证书链要完整。Windows 自带的certutil可以离线验证。

验证步骤:

  1. 将客户提供的 SM2 证书(ca.cer,server.cer)复制到服务器
  2. 运行命令:
certutil -verify -urlfetch ca.cer certutil -verify -urlfetch server.cer
  1. 检查输出末尾:
    • 正确:CertUtil: -verify command completed successfully.
    • 错误:CertUtil: The certificate's CN name does not match the passed value.(CN 不匹配)或CertUtil: The certificate is not valid.(证书过期或签名无效)

提示:如果certutil报The revocation function was unable to check revocation,说明 CRL 下载失败,需在TIdSSLIOHandlerSocketOpenSSL_SM中设置SSLOptions.VerifyMode := []临时跳过吊销检查(生产环境必须修复 CRL 分发点)。

5.4 验证 Windows Defender 兼容性(事件查看器日志)

Windows Defender 的“受控文件夹访问”会拦截 Indy 的WriteFile()调用,导致TIdFTP上传中断、TIdHTTP下载卡死。

验证步骤:

  1. 打开事件查看器 → Windows 日志 → 安全
  2. 筛选事件 ID1123(受控文件夹访问阻止)
  3. 运行你的 Indy 程序,执行一次 FTP 上传或大文件下载
  4. 如果出现1123事件,记录被阻止的进程名(如MyApp.exe)和文件路径(如C:\Temp\upload.bin)
  5. 在 Windows 安全中心 →病毒和威胁防护 → 管理设置 → 受控文件夹访问 → 允许的应用中添加你的 EXE

5.5 验证高并发连接稳定性(TIdTCPServer的MaxConnections)

TIdTCPServer的MaxConnections默认是 0(无限制),但在 Delphi 12 下,超过 500 个并发连接时,TIdSchedulerOfThread的线程池会因TThread.CreateAnonymousThread的内存碎片而崩溃。

验证步骤:

  1. 编写压力测试脚本(Python +socket),模拟 1000 个客户端同时连接TIdTCPServer
  2. 在服务器上运行resmon.exe,观察CPU和Memory → Commit (KB)曲线
  3. 如果Commit持续上涨不回落,说明线程对象未释放
  4. 修复:在TIdTCPServer.OnConnect中显式设置AContext.Connection.DisconnectTimeout := 30000,并在OnDisconnect中调用AContext.Connection.IOHandler.Close()

5.6 验证 SSL 证书过期自动告警(OnStatus事件)

生产环境必须监控证书有效期。Indy 的OnStatus事件在握手阶段会触发hsCertificate状态,此时可读取证书信息。

验证步骤:

procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); var Cert: TIdX509; begin if AStatus = hsCertificate then begin Cert := TIdSSLIOHandlerSocketOpenSSL(IdHTTP1.IOHandler).SSLCertificate; if Cert.NotAfter < Now then MessageBox(0, 'SSL Certificate expired!', 'ALERT', MB_ICONERROR); end; end;

在客户服务器上,将系统时间调快 1 天,运行程序,确认弹窗出现。

5.7 验证日志文件权限(TIdLogFile的FileName)

TIdLogFile默认写入C:\Program Files\MyApp\log.txt,但 Windows UAC 会拒绝写入Program Files。必须重定向到AppData。

验证步骤:

  1. 在TIdHTTP.OnWorkBegin中添加:
IdHTTP1.Intercept := TIdLogFile.Create(nil); TIdLogFile(IdHTTP1.Intercept).FileName := IncludeTrailingPathDelimiter(GetEnvironmentVariable('APPDATA')) + 'MyApp\indy.log';
  1. 运行程序,检查C:\Users\<User>\AppData\Roaming\MyApp\下是否生成indy.log
  2. 手动删除该文件,再次运行,确认新日志生成(证明路径可写)

从那以后我每次交付 Delphi 12 的 Indy 项目,都强制走一遍这七项验证——不是为了炫技,是避免凌晨三点被客户电话叫醒说“上传卡死了”。它不保证 100% 无 bug,但能筛掉 95% 的环境适配雷。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/1 1:13:49

DRV8818PWPR+STM32F107工业步进电机闭环控制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/1 1:12:24

OpenGL安装包装完仍黑屏?三层依赖与上下文创建排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/1 1:12:05

DRV8818+STM32F303VE工业步进驱动硬核实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/1 1:11:35

DRV8818PWPR与CEC1302双极步进电机运动控制系统设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/1 1:10:42

DRV8818PWPR与PIC32MX664F064L步进电机驱动方案实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华