-
-
Notifications
You must be signed in to change notification settings - Fork 60
Shared Item Projects
Sucrose achieves most of its code reuse with Shared Item Projects (.shproj + .projitems), not with NuGet packages or class libraries. A shared project is never compiled on its own; its source files are physically compiled into every executable that imports it — compile-time inclusion, like a "linked files" mechanism. Paired with a per-executable preprocessor symbol, the same shared file can compile differently per app, engine, or platform. This page explains the file-pair model, how an executable consumes shared code, the full list of shared projects, and how to add a file or a whole new shared project.
- Two reuse mechanisms — do not confuse them
- The file pair: .shproj and .projitems
- How an executable consumes shared code
- The full list of shared projects
- Why shared code can vary per consumer
- Adding a file to a shared project
- Adding a whole new shared project
- Gotchas
- See also
| Mechanism | Folder | File type | How consumed | Compiled separately? |
|---|---|---|---|---|
| Class libraries | src/Library/ |
.csproj (SDK-style, OutputType=Library) |
<ProjectReference Include="...csproj" /> |
Yes — produce their own .dll
|
| Shared Item Projects |
src/Shared/ (+ src/Shared/Engine/) |
.shproj + .projitems
|
<Import Project="...projitems" Label="Shared" /> |
No — source inlined into the consumer |
The class libraries (Manager, Memory, Mpv.NET, Pipe, Resources, Signal, Transmission, XamlAnimatedGif) live under src/Library/. Everything described on the rest of this page concerns the Shared Item Projects under src/Shared/.
flowchart LR
subgraph Shared["Shared Item Project"]
Shproj[".shproj<br/>IDE wrapper, ProjectGuid"]
Projitems[".projitems<br/>file list, Compile entries"]
CS["shared .cs / .xaml source"]
Shproj -. imports .-> Projitems
Projitems --> CS
end
CS -->|"import .projitems, Label=Shared"| Launcher["Sucrose.Launcher.csproj<br/>(LAUNCHER)"]
CS -->|"import .projitems, Label=Shared"| Portal["Sucrose.Portal.csproj<br/>(PORTAL)"]
CS -->|"import .projitems, Label=Shared"| Engine["Sucrose.Live.*.csproj<br/>(ENGINE + LIVE_*)"]
Launcher --> O1["Launcher.exe"]
Portal --> O2["Portal.exe"]
Engine --> O3["Live.*.exe"]
Each shared project is two files in the same folder:
The IDE/MSBuild project wrapper. It carries a ProjectGuid, imports the Visual Studio CodeSharing props/targets, and imports its own .projitems with Label="Shared". Example — src/Shared/Sucrose.Shared.Core/Sucrose.Shared.Core.shproj:
<PropertyGroup Label="Globals">
<ProjectGuid>30366616-3837-4234-aea7-ca7dfbd55345</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
...
<Import Project="Sucrose.Shared.Core.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\...\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />The actual list of files. It declares the shared-items metadata and lists every source file:
<HasSharedItems>true</HasSharedItems>-
<SharedGUID>...</SharedGUID>— matches the.shprojProjectGuid -
<Import_RootNamespace>Sucrose.Shared.Core</Import_RootNamespace>— the root namespace the files use
A typical compile entry looks like:
<Compile Include="$(MSBuildThisFileDirectory)Enum\UpdateType.cs" />XAML uses <Page> entries with <Generator>MSBuild:Compile</Generator>, and the code-behind uses <DependentUpon>Gif.xaml</DependentUpon>. Empty directories are listed with <Folder>.
Both files use the old MSBuild 2003 XML schema (xmlns=".../developer/msbuild/2003"), unlike the SDK-style .csproj projects.
A consuming .csproj imports the .projitems (not the .shproj) with Label="Shared". Example — src/Launcher/Sucrose.Launcher/Sucrose.Launcher.csproj:
<Import Project="..\..\Shared\Sucrose.Shared.Zip\Sucrose.Shared.Zip.projitems" Label="Shared" />
<Import Project="..\..\Shared\Sucrose.Shared.Live\Sucrose.Shared.Live.projitems" Label="Shared" />
<Import Project="..\..\Shared\Sucrose.Shared.Signal\Sucrose.Shared.Signal.projitems" Label="Shared" />
<Import Project="..\..\Shared\Sucrose.Shared.Launcher\Sucrose.Shared.Launcher.projitems" Label="Shared" />
<Import Project="..\..\Shared\Sucrose.Shared.Dependency\Sucrose.Shared.Dependency.projitems" Label="Shared" />The .shproj files do appear in the solution (src/Sucrose.slnx, under the /Shared/ and /Shared/Engine/ folders) so the IDE displays them, but the build inclusion happens via the .projitems import in each .csproj — the .shproj is for the IDE and solution listing only.
There are 23 shared projects total: 14 core + 9 engine.
Core shared (src/Shared/) — 14:
Sucrose.Shared.Core, Sucrose.Shared.Dependency, Sucrose.Shared.Discord, Sucrose.Shared.Launcher, Sucrose.Shared.Live, Sucrose.Shared.Pipe, Sucrose.Shared.Signal, Sucrose.Shared.Space, Sucrose.Shared.Store, Sucrose.Shared.Theme, Sucrose.Shared.Transmission, Sucrose.Shared.Watchdog, Sucrose.Shared.Zip, Sucrose.Shared.SevenZip.
Engine-specific shared (src/Shared/Engine/) — 9:
base Sucrose.Shared.Engine, plus Sucrose.Shared.Engine.Aurora, Sucrose.Shared.Engine.CefSharp, Sucrose.Shared.Engine.MpvPlayer, Sucrose.Shared.Engine.VlcPlayer, Sucrose.Shared.Engine.Nebula, Sucrose.Shared.Engine.Vexana, Sucrose.Shared.Engine.WebView, Sucrose.Shared.Engine.Xavier.
A central contract surface lives in Sucrose.Shared.Dependency.Enum.* — the cross-process enums (CommandType, WallpaperType, EngineType, ReportType, and so on) that every process must agree on.
Files inside a shared project are organized by role:
| Folder | Contents |
|---|---|
Enum/ |
Enum types (e.g. Sucrose.Shared.Dependency/Enum/WallpaperType.cs) |
Helper/ |
Static helper/utility classes |
Manage/ |
Configuration/state management |
Manage/Manager/ |
Settings-manager classes |
Manage/Readonly/ |
Read-only constants |
Struct/ |
Struct types |
Extension/ |
Extension methods |
Services/ |
Pipe/signal service classes (in .Pipe, .Signal) |
Event/, View/ (XAML) |
Used in engine shared projects (e.g. Sucrose.Shared.Engine.MpvPlayer has View/Gif.xaml, Event/Video.cs) |
Each executable defines a unique symbol via <DefineConstants>$(DefineConstants);SYMBOL</DefineConstants> in its .csproj. Shared source uses #if SYMBOL blocks so one file compiles differently per host (per app, per engine, per platform). This is the whole reason the Shared Item Project model is used instead of a single shared DLL. The full symbol catalog is in Preprocessor Symbols.
Because shared item projects use the old MSBuild 2003 schema, SDK-style globbing does NOT apply — you must register every file explicitly:
- Create the
.cs(or.xaml) file in the appropriate role folder inside the shared project. - Edit the project's
.projitemsand add a<Compile Include="$(MSBuildThisFileDirectory)<RelativePath>.cs" />entry (or a<Page>/<DependentUpon>pair for XAML). - Rebuild any consuming executable; the new file is now inlined into it.
Forgetting step 2 is the classic mistake: the file exists on disk but is never compiled into anything.
- Create the folder
src/Shared/Sucrose.Shared.<Name>/. - Author
<Name>.shproj— copy an existing one and generate a freshProjectGuid. - Author
<Name>.projitems— set a matchingSharedGUID,Import_RootNamespace=Sucrose.Shared.<Name>, and the<Compile>entries. - Add
<Import Project="...projitems" Label="Shared" />to each consuming.csproj. - Register the
.shprojinsrc/Sucrose.slnxunder the/Shared/folder.
For an engine-specific shared project, place it under src/Shared/Engine/ and follow the same steps; see the engine recipe in Extending Sucrose.
- Consumers import the
.projitems, not the.shproj. -
.shproj/.projitemsuse the old MSBuild 2003 XML schema, unlike SDK-style.csproj. - Adding a file requires editing the
.projitems<Compile Include=...>list — globbing does not apply. - The
.shprojappears in the solution only for IDE listing; build inclusion is the.csprojimport.
Getting Started
- Installation
- System Requirements
- Quick Start
- Portal Interface Tour
- Updating Sucrose
- Uninstalling Sucrose
Wallpaper Types
Using Sucrose
- Managing Library
- Using Store
- Customizing Wallpaper
- Multi-Monitor
- Wallpaper Cycling
- Choosing Engines
- Performance Rules
- Theme, Tray & Startup
- Discord Rich Presence
Settings Reference
- Settings Overview
- Settings: General
- Settings: Personal
- Settings: Performance
- Settings: Wallpaper
- Settings: System
- Settings: Other
- Settings: All Keys
Creating Wallpapers
- Create Overview
- Create: Step By Step
- Create: Package Format
- Create: Customization Controls
- Create: JS Bridge
- Create: Audio API
- Create: System API
- Create: Property Listener & Filters
- Create: Web Architecture
- Create: Compatibility
- Create: Example Wallpapers
- Create: Sharing & Publishing
Engine Reference
- Engines Overview
- Engine: MpvPlayer
- Engine: VlcPlayer
- Engine: WebView
- Engine: CefSharp
- Engine: Nebula
- Engine: Vexana
- Engine: Xavier
- Engine: Aurora
- Engine Comparison
Automation & Command Line
Architecture & Internals
- Architecture Overview
- Lifecycle
- Commandog Dispatcher
- Single-Instance Mutexes
- IPC
- Backgroundog Service
- Crash Reporting
- Update Internals
- Property Service
- Undo Internals
Data, Files & Diagnostics
Building & Contributing
- Building From Source
- Repository Layout
- Shared Item Projects
- Code Conventions
- Preprocessor Symbols
- Publish Pipeline
- Bundle Installer Internals
- Extending Sucrose
- Contributing
- Translating with Localizer
- Localization Coverage
- Security Policy
- Privacy & Telemetry
Help & Support