obs-windows-building

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OBS Windows Building

OBS Windows平台插件构建

Purpose

用途

Build OBS Studio plugins for Windows using MSVC (Visual Studio) or MinGW. Covers symbol exports, Windows-specific linking, platform source files, and DLL verification.
使用MSVC(Visual Studio)或MinGW在Windows平台构建OBS Studio插件。内容涵盖符号导出、Windows专属链接、平台源码文件以及DLL验证。

When NOT to Use

不适用于以下场景

  • Cross-compiling from Linux → Use obs-cross-compiling
  • Qt/C++ frontend development → Use obs-cpp-qt-patterns
  • Audio plugin implementation → Use obs-audio-plugin-writing
  • Code review → Use obs-plugin-reviewing
  • 从Linux交叉编译 → 使用obs-cross-compiling
  • Qt/C++前端开发 → 使用obs-cpp-qt-patterns
  • 音频插件实现 → 使用obs-audio-plugin-writing
  • 代码审查 → 使用obs-plugin-reviewing

Quick Start: Windows Build in 4 Steps

快速入门:Windows平台构建四步走

Step 1: Install Prerequisites

步骤1:安装前置依赖

Visual Studio 2022:
  • Workload: "Desktop development with C++"
  • Individual components: CMake, Windows SDK
Or MinGW (via MSYS2):
bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake
Visual Studio 2022:
  • 工作负载:"使用C++的桌面开发"
  • 单独组件:CMake、Windows SDK
或MinGW(通过MSYS2安装):
bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake

Step 2: Create Windows CMake Preset

步骤2:创建Windows CMake预设

json
{
  "name": "windows-x64",
  "displayName": "Windows x64",
  "description": "Build for Windows x64 with Visual Studio",
  "binaryDir": "${sourceDir}/build_x64",
  "generator": "Visual Studio 17 2022",
  "architecture": "x64",
  "cacheVariables": {
    "OBS_SOURCE_DIR": "${sourceDir}/.deps/windows-x64/obs-studio-32.0.4"
  }
}
json
{
  "name": "windows-x64",
  "displayName": "Windows x64",
  "description": "Build for Windows x64 with Visual Studio",
  "binaryDir": "${sourceDir}/build_x64",
  "generator": "Visual Studio 17 2022",
  "architecture": "x64",
  "cacheVariables": {
    "OBS_SOURCE_DIR": "${sourceDir}/.deps/windows-x64/obs-studio-32.0.4"
  }
}

Step 3: Create .def Export File

步骤3:创建.def导出文件

Create
src/plugin.def
:
def
LIBRARY my-plugin
EXPORTS
    obs_module_load
    obs_module_unload
    obs_module_post_load
    obs_module_ver
    obs_module_set_pointer
    obs_current_module
    obs_module_description
    obs_module_set_locale
    obs_module_free_locale
    obs_module_get_string
    obs_module_text
创建
src/plugin.def
def
LIBRARY my-plugin
EXPORTS
    obs_module_load
    obs_module_unload
    obs_module_post_load
    obs_module_ver
    obs_module_set_pointer
    obs_current_module
    obs_module_description
    obs_module_set_locale
    obs_module_free_locale
    obs_module_get_string
    obs_module_text

Step 4: Configure CMakeLists.txt

步骤4:配置CMakeLists.txt

cmake
if(WIN32)
    # Windows system libraries
    target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)

    # Export module functions via .def file
    if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
        # MinGW
        set_target_properties(${PROJECT_NAME} PROPERTIES
            LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
        )
    else()
        # MSVC
        set_target_properties(${PROJECT_NAME} PROPERTIES
            LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
        )
    endif()
endif()
cmake
if(WIN32)
    # Windows system libraries
    target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)

    # Export module functions via .def file
    if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
        # MinGW
        set_target_properties(${PROJECT_NAME} PROPERTIES
            LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
        )
    else()
        # MSVC
        set_target_properties(${PROJECT_NAME} PROPERTIES
            LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
        )
    endif()
endif()

MSVC vs MinGW Comparison

MSVC与MinGW对比

AspectMSVCMinGW
IDEVisual StudioVS Code, CLion
DebuggingFull VS debuggerGDB
Build speedSlowerFaster
ABINative WindowsGCC-based
Qt compatRequires MSVC QtWorks with MinGW Qt
CI/CDWindows runnerLinux cross-compile
Recommendation: Use MSVC for native Windows development, MinGW for CI cross-compilation.
对比维度MSVCMinGW
集成开发环境Visual StudioVS Code、CLion
调试工具完整VS调试器GDB
构建速度较慢较快
应用二进制接口(ABI)原生Windows标准基于GCC
Qt兼容性需要MSVC版本的Qt兼容MinGW版本的Qt
CI/CD支持Windows运行器Linux交叉编译
推荐方案: 原生Windows开发使用MSVC,CI交叉编译使用MinGW。

Symbol Export with .def Files

使用.def文件导出符号

Why .def Files?

为什么需要.def文件?

OBS loads plugins at runtime and looks up functions by name. Without explicit exports:
  • MSVC may not export functions without
    __declspec(dllexport)
  • MinGW may export by ordinal only (numbers, not names)
OBS在运行时加载插件,并通过函数名称查找函数。如果没有显式导出:
  • MSVC可能不会导出未标记
    __declspec(dllexport)
    的函数
  • MinGW可能仅通过序号(数字而非名称)导出函数

.def File Format

.def文件格式

def
; Comments start with semicolon
LIBRARY my-plugin        ; DLL name
EXPORTS
    obs_module_load      ; Function to export
    obs_module_unload
    ; Add all OBS_DECLARE_MODULE() and OBS_MODULE_USE_DEFAULT_LOCALE() functions
def
; 注释以分号开头
LIBRARY my-plugin        ; DLL名称
EXPORTS
    obs_module_load      ; 要导出的函数
    obs_module_unload
    ; 添加所有OBS_DECLARE_MODULE()和OBS_MODULE_USE_DEFAULT_LOCALE()相关函数

MSVC Linker Flag

MSVC链接器参数

cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)

MinGW Linker Flag

MinGW链接器参数

cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)

Windows System Libraries

Windows系统库

Common Libraries

常用库

LibraryPurposeHeader
ws2_32
Windows Sockets 2 (networking)
<winsock2.h>
comctl32
Common controls (UI widgets)
<commctrl.h>
user32
Windows API (windows, messages)
<windows.h>
kernel32
Core Windows API
<windows.h>
ole32
COM support
<objbase.h>
uuid
GUID/UUID support
<guiddef.h>
库名称用途头文件
ws2_32
Windows Sockets 2(网络功能)
<winsock2.h>
comctl32
通用控件(UI组件)
<commctrl.h>
user32
Windows API(窗口、消息)
<windows.h>
kernel32
核心Windows API
<windows.h>
ole32
COM支持
<objbase.h>
uuid
GUID/UUID支持
<guiddef.h>

CMake Linking

CMake链接配置

cmake
if(WIN32)
    target_link_libraries(${PROJECT_NAME} PRIVATE
        ws2_32      # Sockets
        comctl32    # UI controls
    )
endif()
cmake
if(WIN32)
    target_link_libraries(${PROJECT_NAME} PRIVATE
        ws2_32      # 套接字
        comctl32    # UI控件
    )
endif()

Include Order (CRITICAL)

头文件包含顺序(至关重要)

c
/* WRONG - will cause compile errors */
#include <windows.h>
#include <winsock2.h>

/* CORRECT - winsock2.h must come first */
#include <winsock2.h>
#include <windows.h>
c
/* 错误写法 - 会导致编译错误 */
#include <windows.h>
#include <winsock2.h>

/* 正确写法 - winsock2.h必须放在前面 */
#include <winsock2.h>
#include <windows.h>

Platform-Specific Source Files

平台专属源码文件

Directory Structure

目录结构

src/
├── plugin-main.c           # Cross-platform
├── my-source.c             # Cross-platform
└── platform/
    ├── socket-posix.c      # Linux/macOS
    └── socket-win32.c      # Windows
src/
├── plugin-main.c           # 跨平台代码
├── my-source.c             # 跨平台代码
└── platform/
    ├── socket-posix.c      # Linux/macOS平台
    └── socket-win32.c      # Windows平台

CMakeLists.txt Pattern

CMakeLists.txt编写模式

cmake
undefined
cmake
undefined

Common sources

通用源码

target_sources(${PROJECT_NAME} PRIVATE src/plugin-main.c src/my-source.c )
target_sources(${PROJECT_NAME} PRIVATE src/plugin-main.c src/my-source.c )

Platform-specific sources

平台专属源码

if(WIN32) target_sources(${PROJECT_NAME} PRIVATE src/platform/socket-win32.c ) else() target_sources(${PROJECT_NAME} PRIVATE src/platform/socket-posix.c ) endif()
undefined
if(WIN32) target_sources(${PROJECT_NAME} PRIVATE src/platform/socket-win32.c ) else() target_sources(${PROJECT_NAME} PRIVATE src/platform/socket-posix.c ) endif()
undefined

Platform Header Pattern

平台头文件编写模式

c
/* platform.h - Platform abstraction */
#pragma once

#ifdef _WIN32
    #include "platform/socket-win32.h"
#else
    #include "platform/socket-posix.h"
#endif

/* Common interface */
int platform_socket_init(void);
void platform_socket_cleanup(void);
int platform_socket_send(const char *host, int port, const void *data, size_t len);
c
/* platform.h - 平台抽象层 */
#pragma once

#ifdef _WIN32
    #include "platform/socket-win32.h"
#else
    #include "platform/socket-posix.h"
#endif

/* 通用接口 */
int platform_socket_init(void);
void platform_socket_cleanup(void);
int platform_socket_send(const char *host, int port, const void *data, size_t len);

Windows-Specific Code Patterns

Windows专属代码模式

Winsock Initialization

Winsock初始化

c
/* socket-win32.c */
#include <winsock2.h>
#include <ws2tcpip.h>

static bool winsock_initialized = false;

int platform_socket_init(void)
{
    WSADATA wsa_data;
    int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
    if (result != 0) {
        return -1;
    }
    winsock_initialized = true;
    return 0;
}

void platform_socket_cleanup(void)
{
    if (winsock_initialized) {
        WSACleanup();
        winsock_initialized = false;
    }
}
c
/* socket-win32.c */
#include <winsock2.h>
#include <ws2tcpip.h>

static bool winsock_initialized = false;

int platform_socket_init(void)
{
    WSADATA wsa_data;
    int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
    if (result != 0) {
        return -1;
    }
    winsock_initialized = true;
    return 0;
}

void platform_socket_cleanup(void)
{
    if (winsock_initialized) {
        WSACleanup();
        winsock_initialized = false;
    }
}

Windows API Loader Pattern

Windows API加载模式

For optional Windows APIs (not always available):
c
/* api-loader.c */
#include <windows.h>

typedef BOOL (WINAPI *SetProcessDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);

static SetProcessDpiAwarenessContext_t pSetProcessDpiAwarenessContext = NULL;

void load_optional_apis(void)
{
    HMODULE user32 = GetModuleHandleW(L"user32.dll");
    if (user32) {
        pSetProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext_t)
            GetProcAddress(user32, "SetProcessDpiAwarenessContext");
    }
}

void set_dpi_awareness(void)
{
    if (pSetProcessDpiAwarenessContext) {
        pSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
    }
}
针对可选Windows API(并非所有系统都支持):
c
/* api-loader.c */
#include <windows.h>

typedef BOOL (WINAPI *SetProcessDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);

static SetProcessDpiAwarenessContext_t pSetProcessDpiAwarenessContext = NULL;

void load_optional_apis(void)
{
    HMODULE user32 = GetModuleHandleW(L"user32.dll");
    if (user32) {
        pSetProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext_t)
            GetProcAddress(user32, "SetProcessDpiAwarenessContext");
    }
}

void set_dpi_awareness(void)
{
    if (pSetProcessDpiAwarenessContext) {
        pSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
    }
}

OBS Plugin Installation Paths

OBS插件安装路径

User Installation (Recommended)

用户级安装(推荐)

%APPDATA%\obs-studio\plugins\my-plugin\
├── bin\
│   └── 64bit\
│       └── my-plugin.dll
└── data\
    └── locale\
        └── en-US.ini
%APPDATA%\obs-studio\plugins\my-plugin\
├── bin\
│   └── 64bit\
│       └── my-plugin.dll
└── data\
    └── locale\
        └── en-US.ini

System Installation

系统级安装

C:\ProgramData\obs-studio\plugins\my-plugin\
├── bin\
│   └── 64bit\
│       └── my-plugin.dll
└── data\
    └── locale\
        └── en-US.ini
C:\ProgramData\obs-studio\plugins\my-plugin\
├── bin\
│   └── 64bit\
│       └── my-plugin.dll
└── data\
    └── locale\
        └── en-US.ini

CMake Install Target

CMake安装目标配置

cmake
if(WIN32)
    set(OBS_PLUGIN_DIR "$ENV{APPDATA}/obs-studio/plugins/${PROJECT_NAME}")
endif()

install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION ${OBS_PLUGIN_DIR}/bin/64bit
)

install(DIRECTORY data/locale
    DESTINATION ${OBS_PLUGIN_DIR}/data
)
cmake
if(WIN32)
    set(OBS_PLUGIN_DIR "$ENV{APPDATA}/obs-studio/plugins/${PROJECT_NAME}")
endif()

install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION ${OBS_PLUGIN_DIR}/bin/64bit
)

install(DIRECTORY data/locale
    DESTINATION ${OBS_PLUGIN_DIR}/data
)

DLL Verification

DLL验证

Check File Type

检查文件类型

cmd
:: PowerShell
Get-Item my-plugin.dll | Select-Object Name, Length
cmd
:: PowerShell
Get-Item my-plugin.dll | Select-Object Name, Length

Check Exports with dumpbin (MSVC)

使用dumpbin检查导出(MSVC)

cmd
dumpbin /exports my-plugin.dll
Expected output:
    ordinal hint RVA      name
          1    0 00001000 obs_current_module
          2    1 00001010 obs_module_description
          3    2 00001020 obs_module_load
          ...
cmd
dumpbin /exports my-plugin.dll
预期输出:
    ordinal hint RVA      name
          1    0 00001000 obs_current_module
          2    1 00001010 obs_module_description
          3    2 00001020 obs_module_load
          ...

Check Exports with objdump (MinGW)

使用objdump检查导出(MinGW)

bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"
bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"

FORBIDDEN Patterns

禁用模式

PatternProblemSolution
Missing .def fileFunctions not exported by nameCreate plugin.def
Wrong include orderwinsock2 errorsInclude winsock2.h before windows.h
Missing WSAStartupSocket functions failCall platform_socket_init()
Hardcoded pathsBreaks on other machinesUse %APPDATA% or relative paths
ANSI APIsUnicode issuesUse wide (W) APIs or UTF-8
Missing /DEF linker flagNo exports in DLLAdd LINK_FLAGS in CMake
模式问题解决方案
缺失.def文件函数未按名称导出创建plugin.def文件
头文件包含顺序错误winsock2编译错误将winsock2.h放在windows.h之前包含
未调用WSAStartup套接字函数执行失败调用platform_socket_init()
硬编码路径在其他机器上无法正常运行使用%APPDATA%或相对路径
使用ANSI API存在Unicode兼容问题使用宽字符(W)API或UTF-8编码
缺失/DEF链接参数DLL中无导出内容在CMake中添加LINK_FLAGS配置

Troubleshooting

故障排查

Plugin Not Visible in OBS

OBS中无法看到插件

Check:
  1. DLL is in
    bin/64bit/
    subdirectory
  2. Path is correct:
    %APPDATA%\obs-studio\plugins\{name}\bin\64bit\
  3. DLL exports are present:
    dumpbin /exports my-plugin.dll
检查项:
  1. DLL是否位于
    bin/64bit/
    子目录下
  2. 路径是否正确:
    %APPDATA%\obs-studio\plugins\{name}\bin\64bit\
  3. DLL是否包含导出内容:执行
    dumpbin /exports my-plugin.dll
    检查

"Entry Point Not Found" Error

「找不到入口点」错误

Cause: Missing
obs_module_load
export
Fix: Ensure .def file includes
obs_module_load
and linker flag is set.
原因: 缺失
obs_module_load
导出项
修复方案: 确保.def文件包含
obs_module_load
,且已设置链接器参数。

Winsock Errors

Winsock错误

Symptom: Socket functions return -1 or WSANOTINITIALISED
Fix: Call
WSAStartup()
before any socket operations.
症状: 套接字函数返回-1或WSANOTINITIALISED
修复方案: 在任何套接字操作前调用
WSAStartup()

Unicode/ANSI Mismatch

Unicode/ANSI不匹配

Symptom: String corruption, "???" characters
Fix:
c
/* Use wide APIs or define UNICODE */
#define UNICODE
#define _UNICODE
#include <windows.h>
症状: 字符串损坏、出现「???」字符
修复方案:
c
/* 使用宽字符API或定义UNICODE宏 */
#define UNICODE
#define _UNICODE
#include <windows.h>

Build Commands

构建命令

Visual Studio

Visual Studio

cmd
:: Configure
cmake --preset windows-x64

:: Build
cmake --build --preset windows-x64 --config RelWithDebInfo

:: Install
cmake --install build_x64 --config RelWithDebInfo
cmd
:: 配置
cmake --preset windows-x64

:: 构建
cmake --build --preset windows-x64 --config RelWithDebInfo

:: 安装
cmake --install build_x64 --config RelWithDebInfo

MinGW (MSYS2)

MinGW(MSYS2)

bash
undefined
bash
undefined

Configure

配置

cmake -G "Ninja" -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake -G "Ninja" -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo

Build

构建

cmake --build build
cmake --build build

Install

安装

cmake --install build
undefined
cmake --install build
undefined

External Documentation

外部文档

Context7

Context7

mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "Windows plugin build Visual Studio MSVC"
mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "Windows plugin build Visual Studio MSVC"

Official References

官方参考资料

Related Skills

相关技能

  • obs-cross-compiling - Cross-compile from Linux to Windows
  • obs-cpp-qt-patterns - Qt frontend integration
  • obs-plugin-developing - Plugin architecture overview
  • obs-audio-plugin-writing - Audio plugin implementation
  • obs-cross-compiling - 从Linux交叉编译到Windows
  • obs-cpp-qt-patterns - Qt前端集成
  • obs-plugin-developing - 插件架构概述
  • obs-audio-plugin-writing - 音频插件实现

Related Agent

相关Agent

Use obs-plugin-expert for coordinated guidance across all OBS plugin skills.
使用obs-plugin-expert获取所有OBS插件技能的协同指导。