• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2025-03-25 20:14 Aet 隐藏边栏 |   抢沙发  7 
文章评分 2 次,平均分 5.0

Windows相关

创建Mutex的有无Global的影响

  1. 概述
    1. Windows 内核对象(如 MutexEventSemaphore)的命名规则决定了它们的可见范围:
    2. 适用场景:跨会话(如服务进程与用户进程)、跨用户或系统级同步
  2. 加了Global\
    1. 表示该对象位于 全局内核命名空间,可被 所有用户会话(Sessions) 和 进程 访问
  3. 加了Local\(或不加前缀)
    1. 表示该对象位于 当前会话的本地命名空间,仅对 同一会话内的进程 可见
    2. 默认行为:若不显式指定前缀,系统默认使用 Local\
    3. 适用场景:同一用户会话内的进程间同步

关于会话

  1. Windows 的 会话(Session) 是操作系统隔离用户环境的逻辑单元,主要服务于 终端服务(Terminal Services) 或多用户场景:
    1. 每个登录用户 通常会分配一个 独立会话
    2. Session 0 是特殊的系统会话

主线程里启动一个线程,PostThreadMessage发消息能不能收到

  1. 主线程启动的新线程能否收到 PostThreadMessage 的消息,取决于目标线程是否已创建消息队列
  2. 消息队列的创建条件:当线程首次调用以下任一操作时,系统会为其分配消息队列:
    1. 创建窗口(CreateWindow / CreateWindowEx
    2. 调用消息处理函数(GetMessage / PeekMessage
    3. 其他隐式依赖消息队列的 UI 操作(如注册窗口类、处理对话框等)
  3. 若消息队列未创建:
    1. PostThreadMessage 发送的消息会丢失,且函数返回 FALSE,可通过 GetLastError() 检查错误码(如 ERROR_INVALID_THREAD_ID

创建一个窗口,怎么让它一直在父窗口上面

  1. 方法1
    1. 使用 WS_CHILD 样式(推荐的方法),具体如下:
    2. 创建父窗口:使用 WS_OVERLAPPEDWINDOW 样式
    3. 创建子窗口:使用 WS_CHILD 样式,并指定父窗口句柄
    4. 系统会自动维护其 Z 序在父窗口之上,子窗口会随父窗口移动、最小化/恢复

  1. 方法二
    1. 使用 HWND_TOPMOST 和父窗口关联,具体如下:
    2. 创建父窗口:普通窗口样式(如 WS_OVERLAPPEDWINDOW
    3. 创建子窗口:使用 WS_EX_TOPMOST 扩展样式,并通过 SetWindowPos 绑定到父窗口
    4. 监听父窗口位置变化:在父窗口的 WM_WINDOWPOSCHANGED 消息中更新子窗口位置

  1. 创建一个模态的子窗口
    1. 但是这种方法会阻塞主线程的消息循环,具体如下:
    2. 使用普通窗口类,并在点击按钮或菜单时触发模态窗口的创建
    3. 通过 DialogBox 函数加载对话框资源,并绑定对话框过程函数
    4. 在资源文件(.rc)中定义对话框模板,或在代码中动态创建

栈的增长方向

  1. 由高地址向低地址增长

MDdMTd

  1. 概述
    1. d debug
    2. M 多线程
    3. T Text代码
    4. D 动态
  2. /MT /MTd指静态编译(多线程静态版本),使用lib以及MSVC相关的静态库
    1. 定义了它后,编译器把LIBCMT.lib 安置到OBJ文件中,让链接器使用LIBCMT.lib 处理外部符号
  3. /MD /MDd指动态编译(多线程DLL版本),使用相应的DLL版本编译
    1. 定义了它后,编译器把 MSVCRT.lib 安置到OBJ文件中,它连接到DLL的方式是静态链接,实际上工作的库是MSVCR80.DLL

Windbg相关

查看内存的命令相关

d*

  1. db:以 字节(Byte)形式显示内存,同时显示 ASCII 字符

  1. dw:以 字(Word, 2字节) 形式显示内存

  1. dd:以双字(DWORD, 4字节)形式显示内存

  1. dq:以四字(QWORD, 8字节)形式显示内存

  1. dc:以DWORD + ASCII 混合形式显示

da

  1. 显示 ANSI 字符串

du

  1. 显示 Unicode 字符串

ddsdps

  1. 将内存内容视为 符号地址(需符号加载)

!address

  1. 分析指定地址的 内存区域属性(如堆、栈、保留内存等):
  2. BaseAddress:内存块起始地址
  3. RegionSize:内存块大小
  4. Type:类型(MEM_PRIVATE, MEM_IMAGE等)
  5. Protect:保护属性(PAGE_READWRITE等)

!vprot(查看内存保护状态)

  1. 快速查看内存页的 保护属性:

s(搜索内存)

  1. 在内存中搜索特定字节序列或字符串:

edeweb(编辑内存)

  1. 直接修改内存内容(慎用!):

dt

  1. 根据符号信息显示 数据结构:

.formats

  1. 将内存值转换为多种格式(十进制、十六进制、ASCII等):

!heap

  1. 查看堆内存分配情况:

查看栈内存

查看线程环境块(TEB

查看进程环境块(PEB

内存断点

内存差异比较

怎么查看结构体

  1. 查看结构体定义

  1. 显示内存中的结构体实例

  1. 递归显示嵌套结构体
    1. 使用 -r 参数指定递归深度:

  1. 显示结构体大小

  1. 模糊查找符号

显示数组或指针内容

  1. 对数组或指针成员展开显示:

COM相关

CoInitializeCoInitializeEX区别

  1. CoInitialize
    1. 其默认将当前线程设置为单线程单元(STA, Single-Threaded Apartment
    2. 这意味着:
    3. COM 对象只能通过该线程的窗口消息队列(如 GetMessage/DispatchMessage)进行并发控制,避免多线程竞争
    4. 通常用于需要与 UI 交互的线程(例如主线程),例如操作剪贴板、拖放功能等
  2. CoInitializeEx
    1. COINIT_APARTMENTTHREADED:与 CoInitialize 等效
    2. COINIT_MULTITHREADED:线程加入多线程套间,所有 MTA 线程共享一个上下文,不需要消息队列
    3. COINIT_DISABLE_OLE1DDE:禁用对旧版 OLE 1.0 的支持(可选)
  3. 场景:
    1. CoInitialize:在遗留代码中常见,默认要求线程有消息泵(消息循环)
      示例:传统的 ActiveX 控件或 COM 对象需要在主线程中使用
    2. CoInitializeEx
      STA 模式,兼容 CoInitialize 行为,但明确指定线程模型
      MTA 模式,适用于后台线程处理不需要 UICOM 对象(如并行计算)
      示例:工作线程中调用无需 GUI 交互的 COM 组件
  4. 推荐:
    1. 优先使用 CoInitializeEx
      CoInitialize 已被微软标记为过时(obsolescent
    2. 需显式指定线程模型,避免默认行为的潜在歧义
  5. 注意:
    1. 每个线程只能初始化一次 COM
      重复调用会失败(返回 RPC_E_CHANGED_MODE),除非上一次调用已被 CoUninitialize
    2. 清理资源
      调用 CoUninitialize 配对释放资源,通常置于 __finally 块或析构函数中
    3. 线程模型选择的影响
      STA:线程需要处理消息队列(常见于需要 COM 对象与用户交互)
      MTA:无需消息泵,但必须手动处理线程安全和同步

CoCreateInstance里面是怎么实现的

  1. 概述
    1. COMComponent Object Model)中用于创建对象实例的核心 API
    2. 其内部实现涉及多个关键步骤,包括注册表查询、组件加载、类工厂获取及实例创建等
  2. 步骤如下:
  3. 参数验证
    1. 验证传入的 rclsidCLSID)、pUnkOuter(聚合指针)、dwClsContext(执行上下文)和 riid(接口 IID)是否有效
    2. 若参数非法(如 riid 为空),立即返回 E_INVALIDARG
  4. 解析 CLSID 并查找注册信息
    1. 注册表查询:根据 CLSID 在注册表中查找对应的组件实现路径。关键注册表路径为:
    2. 上下文匹配:根据 dwClsContext(如 CLSCTX_INPROC_SERVERCLSCTX_LOCAL_SERVER)筛选可用组件

  1. 加载组件
    1. 进程内组件(DLL
      加载 DLL:通过 LoadLibrary 加载 InProcServer32 指定的 DLL
      获取类工厂:调用 DLL 的导出函数 DllGetClassObject,传入 CLSIDIID_IClassFactory,获取类工厂接口指针
    2. 本地 EXE 组件
      启动进程:通过 CreateProcess 启动 LocalServer32 指定的 EXE
      跨进程通信:EXE 启动后向 COM 注册类工厂,CoCreateInstance 通过 COMSCMService Control Manager)跨进程获取类工厂
  2. 获取类工厂并创建实例
    1. 调用类工厂:通过获得的 IClassFactory 指针,调用其 CreateInstance 方法
    2. 聚合处理:若 pUnkOuter 非空(聚合请求),确保被创建对象支持聚合

  1. 处理线程模型与封送(Marshaling
    1. 线程模型检查:比较调用线程的公寓类型(STA/MTA)与组件注册的线程模型(如 ThreadingModel 值):
      兼容时:直接返回对象指针
      不兼容时:创建接口代理(Proxy),将调用封送至目标线程或进程
    2. 封送初始化:若对象跨线程/进程,调用 CoMarshalInterface 生成代理存根(Proxy-Stub
  2. 错误处理与资源释放
    1. 错误码返回:若任一步骤失败(如注册表未找到 CLSID),返回对应错误码(如 REGDB_E_CLASSNOTREG
    2. 释放资源:若中途失败,确保释放已加载的 DLL 或类工厂指针,避免内存泄漏

comidl文件会生成哪些默认的接口

  1. IUnknown 接口方法
    1. 所有 COM 接口必须继承自 IUnknown,因此 IDL 生成的接口会默认包含其三个核心方法:
    2. QueryInterface:查询对象是否支持指定接口,并返回接口指针
    3. AddRef:增加对象的引用计数
    4. Release:减少对象的引用计数,计数归零时销毁对象
  2. 用户自定义接口
    1. IDL 文件中显式定义的接口会被编译为 C++ 抽象类,包含用户定义的方法。例如:

  1. 类型库相关接口(可选)
    1. 如果 IDL 文件包含 library 块生成类型库(.tlb),可能涉及以下接口:
    2. IDispatch:支持后期绑定(如 VBScriptVBA
      GetTypeInfoCount
      GetTypeInfo
      GetIDsOfNames
      Invoke
    3. IClassFactory:创建组件实例
      CreateInstance
      LockServer
  2. 代理存根代码(Proxy-Stub
    1. 为支持跨进程/线程调用,MIDL 编译器会生成 代理存根 相关代码,包含以下关键接口:
    2. IRpcProxyBuffer:管理代理对象的 RPC 通信
      Connect
      Disconnect
    3. IRpcStubBuffer:管理存根对象的 RPC 通信
      Invoke
      IsIIDSupported
  3. 全局唯一标识符(GUID
    1. IDL 中定义的每个接口和类会生成对应的 GUID(全局唯一标识符),存储在头文件中:

编程规范

多线程相关

定义一个全局的bool,主线程设置true,其他线程发现true则退出,可行吗

  1. 使用std::atomic

  1. 使用condition_variable

C++11后面的特性

智能指针

  1. auto_ptr被淘汰的原因
    1. 已弃用,因为赋值操作会导致原来的智能指针失去对内存的所有权

  1. shared_ptr</li> <li>weak_ptr
  2. weak_ptr的场景
    1. 打破循环引用
    2. 缓存系统
      缓存需要临时保存对象的弱引用,当外部不再使用对象时,允许其自动释放;若缓存需要时对象仍存在,可重新获取
    3. 观察者模式
    4. 临时访问共享资源

string_viewconst string&

  1. 底层实现
    1. const string&
      是对一个已存在的 std::string 对象的常量引用,依赖 std::string 本身的内存管理(如堆分配的字符数组)
      必须指向一个有效的 std::string 对象
      传递非 std::string 参数时(如字符串字面量 "Hello"),会隐式构造临时 std::string,可能导致不必要的内存分配和拷贝
    2. std::string_view
      是一个轻量级的非拥有视图,仅包含指向字符数据的指针和长度信息,不管理内存
      可以引用任何连续的字符序列(如 std::stringC 风格字符串、字符数组等)
      不涉及内存分配或数据拷贝,构造和析构成本极低
  2. 内存和生命周期
    1. const string&
      如果引用的是临时对象(如函数返回的 std::string),临时对象的生命周期会延长到引用结束
      但传递非 std::string 参数时(如 char*),需要构造临时 std::string,可能引发性能问题
    2. std::string_view
      不管理内存,仅持有数据的指针和长度
      必须确保底层数据的生命周期长于 std::string_view 本身,否则可能导致悬垂引用
      无法延长被引用数据的生命周期
  3. 性能
    1. const string&
      当参数本身是 std::string 时,无额外开销
      当传递非 std::string 参数时(如 char*"Hello"),会构造临时 std::string,导致堆内存分配和数据拷贝
    2. std::string_view
      构造和析构几乎无开销(仅复制指针和长度)
      无内存分配或数据拷贝,适合高频调用或处理大字符串的场景
  4. 场景
    1. const string&
      需要与现有 std::string 对象交互
      需要依赖 std::string 的成员函数或保证数据安全
      不确定底层数据的生命周期时(避免悬垂引用)
    2. std::string_view
      需要高效处理只读字符串参数(如工具函数、日志、解析器等)
      需要接受多种字符串类型(std::string, char*, 子字符串等
      明确知道底层数据的生命周期足够长

lambda

std::forward

std::async

std::future

std::package_task

std::promise

其他相关内容

WS_OVERLAPPEDWINDOW样式

  1. Windows API 中用于创建标准顶层应用程序窗口的 组合窗口样式
    1. 它整合了多个基础样式,提供了完整的用户界面元素,适用于大多数主窗口场景

  1. 样式详解
样式 功能描述
WS_OVERLAPPED 创建一个可重叠的顶层窗口(带有边框和标题栏的基础样式)。
WS_CAPTION 包含标题栏(必须与 WS_BORDERWS_DLGFRAME 组合使用)。
WS_SYSMENU 添加系统菜单(点击标题栏图标可弹出 关闭/最小化/最大化 等选项)。
WS_THICKFRAME 允许用户通过拖拽边框调整窗口大小(显示可调节的窗口边框)。
WS_MINIMIZEBOX 在标题栏右侧显示 最小化按钮(⚪)。
WS_MAXIMIZEBOX 在标题栏右侧显示 最大化按钮(⬜)。
  1. 移除最大化按钮

  1. 窗口初始化状态

关于样式冲突

  1. WS_POPUP
    1. WS_OVERLAPPEDWINDOW 冲突,后者包含 WS_OVERLAPPED
  2. WS_CHILD
    1. 不能与 WS_OVERLAPPEDWINDOW 同时使用,子窗口需用独立样式

WS_CHILD样式

  1. Windows API 中用于创建 子窗口(Child Window) 的核心样式
    1. 它是构建复杂用户界面的基础,常见于对话框控件、面板容器等场景
  2. 子窗口必须依附于父窗口
    1. 使用 WS_CHILD 创建的窗口必须通过 CreateWindowExhWndParent 参数指定父窗口句柄
    2. 子窗口的生命周期、可见性和坐标均受父窗口控制
  3. 不可独立存在
    1. 子窗口无法脱离父窗口单独显示,关闭父窗口时会自动销毁所有子窗口
  4. 坐标系统:
    1. 子窗口的位置(x/y)相对于父窗口的 客户区左上角,而非屏幕坐标

  1. 可见性与裁剪

    1. 裁剪区域:子窗口超出父窗口客户区的部分会被自动裁剪(不可见)
    2. 可见性继承:若父窗口被隐藏(ShowWindow(hParent, SW_HIDE)),所有子窗口也会隐藏
  2. 子窗口的消息响应

    1. 在子窗口过程中处理必要消息,未处理的消息转发给默认处理函数:

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2025-03-26
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享