obs-windows-building

Build OBS Studio plugins for Windows using MSVC or MinGW. Covers Visual Studio setup, .def file exports, Windows linking (ws2_32, comctl32), platform-specific sources, and DLL verification. Use when building OBS plugins natively on Windows or troubleshooting Windows builds.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "obs-windows-building" with this command: npx skills add meriley/claude-code-skills/meriley-claude-code-skills-obs-windows-building

OBS Windows Building

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.

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

Quick Start: Windows Build in 4 Steps

Step 1: Install Prerequisites

Visual Studio 2022:

  • Workload: "Desktop development with C++"
  • Individual components: CMake, Windows SDK

Or MinGW (via MSYS2):

pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake

Step 2: Create Windows CMake Preset

{
  "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

Create src/plugin.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

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

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.

Symbol Export with .def Files

Why .def Files?

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)

.def File Format

; 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

MSVC Linker Flag

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

MinGW Linker Flag

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

Windows System Libraries

Common Libraries

LibraryPurposeHeader
ws2_32Windows Sockets 2 (networking)<winsock2.h>
comctl32Common controls (UI widgets)<commctrl.h>
user32Windows API (windows, messages)<windows.h>
kernel32Core Windows API<windows.h>
ole32COM support<objbase.h>
uuidGUID/UUID support<guiddef.h>

CMake Linking

if(WIN32)
    target_link_libraries(${PROJECT_NAME} PRIVATE
        ws2_32      # Sockets
        comctl32    # UI controls
    )
endif()

Include Order (CRITICAL)

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

/* CORRECT - winsock2.h must come first */
#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

CMakeLists.txt Pattern

# Common sources
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()

Platform Header Pattern

/* 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);

Windows-Specific Code Patterns

Winsock Initialization

/* 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

For optional Windows APIs (not always available):

/* 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

User Installation (Recommended)

%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

CMake Install Target

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

Check File Type

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

Check Exports with dumpbin (MSVC)

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
          ...

Check Exports with objdump (MinGW)

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

Troubleshooting

Plugin Not Visible in 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

"Entry Point Not Found" Error

Cause: Missing obs_module_load export

Fix: Ensure .def file includes obs_module_load and linker flag is set.

Winsock Errors

Symptom: Socket functions return -1 or WSANOTINITIALISED

Fix: Call WSAStartup() before any socket operations.

Unicode/ANSI Mismatch

Symptom: String corruption, "???" characters

Fix:

/* Use wide APIs or define UNICODE */
#define UNICODE
#define _UNICODE
#include <windows.h>

Build Commands

Visual Studio

:: Configure
cmake --preset windows-x64

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

:: Install
cmake --install build_x64 --config RelWithDebInfo

MinGW (MSYS2)

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

# Build
cmake --build build

# Install
cmake --install build

External Documentation

Context7

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

Related Agent

Use obs-plugin-expert for coordinated guidance across all OBS plugin skills.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

obs-cpp-qt-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

vendure-admin-ui-writing

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

vendure-entity-writing

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

vendure-admin-ui-reviewing

No summary provided by upstream source.

Repository SourceNeeds Review