Skip to content

Shared Item Projects

Taiizor edited this page Jun 19, 2026 · 3 revisions

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.

Contents

Two reuse mechanisms — do not confuse them

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

The file pair: .shproj and .projitems

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"]
Loading

Each shared project is two files in the same folder:

<Name>.shproj

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

<Name>.projitems

The actual list of files. It declares the shared-items metadata and lists every source file:

  • <HasSharedItems>true</HasSharedItems>
  • <SharedGUID>...</SharedGUID> — matches the .shproj ProjectGuid
  • <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.

How an executable consumes shared code

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.

The full list of shared projects

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.

Internal directory roles

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)

Why shared code can vary per consumer

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.

Adding a file to a shared project

Because shared item projects use the old MSBuild 2003 schema, SDK-style globbing does NOT apply — you must register every file explicitly:

  1. Create the .cs (or .xaml) file in the appropriate role folder inside the shared project.
  2. Edit the project's .projitems and add a <Compile Include="$(MSBuildThisFileDirectory)<RelativePath>.cs" /> entry (or a <Page>/<DependentUpon> pair for XAML).
  3. 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.

Adding a whole new shared project

  1. Create the folder src/Shared/Sucrose.Shared.<Name>/.
  2. Author <Name>.shproj — copy an existing one and generate a fresh ProjectGuid.
  3. Author <Name>.projitems — set a matching SharedGUID, Import_RootNamespace=Sucrose.Shared.<Name>, and the <Compile> entries.
  4. Add <Import Project="...projitems" Label="Shared" /> to each consuming .csproj.
  5. Register the .shproj in src/Sucrose.slnx under 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.

Gotchas

  • Consumers import the .projitems, not the .shproj.
  • .shproj/.projitems use 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 .shproj appears in the solution only for IDE listing; build inclusion is the .csproj import.

See also

Home

Getting Started

Wallpaper Types

Using Sucrose

Settings Reference

Creating Wallpapers

Engine Reference

Automation & Command Line

Architecture & Internals

Data, Files & Diagnostics

Building & Contributing

Help & Support

Clone this wiki locally