Skip to content

Instantly share code, notes, and snippets.

@skarllot
Last active July 3, 2024 08:47
Show Gist options
  • Save skarllot/4953ddb6e23d8a6f0816029c4155997a to your computer and use it in GitHub Desktop.
Save skarllot/4953ddb6e23d8a6f0816029c4155997a to your computer and use it in GitHub Desktop.
Build .NET Compact Framework 3.5

Install

Force MSBuild support

  • Copy files and directories from 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\*' to 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5';
  • Copy files from 'C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\Debugger\BCL\*' to 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\CompactFramework' directory;
  • Create 'RedistList' directory inside created 'CompactFramework' directory;
  • Create 'FrameworkList.xml' inside 'RedistList' directory and type the following:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\CompactFramework\RedistList\FrameworkList.xml

<?xml version="1.0" encoding="utf-8"?>
<FileList  Redist="Net35-CF" Name=".NET Compact Framework 3.5">
</FileList>

Visual Studio 2017/2019 - .NET Standard/Class Library

If do not care to add a dependency to the project to support 'net35-cf' build, configure the project as follows:

project.csproj

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net35-cf</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NETStandard.WindowsCE" Version="1.4.0" />
  </ItemGroup>

Otherwise, if do not want to use any support package. You must to configure the project as follows:

project.csproj

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net35-cf</TargetFrameworks>
    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)' == 'net35-cf'">
    <TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <TargetFrameworkProfile>CompactFramework</TargetFrameworkProfile>
    <DefineConstants>$(DefineConstants);NET35_CF;WindowsCE</DefineConstants>
    <DisableImplicitFrameworkReferences>True</DisableImplicitFrameworkReferences>
    <NoStdLib>True</NoStdLib>
    <NoConfig>true</NoConfig>
    <FileAlignment>512</FileAlignment>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
    <Optimize>False</Optimize>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'net35-cf'">
    <Reference Include="mscorlib, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Data, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Runtime.Serialization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Xml, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
  </ItemGroup>

Visual Studio 2015 - Core XPROJ

  • Use 'net35-cf' or '.NETFramework,Version=v3.5,Profile=CompactFramework' TFM.

project.json

{
    "frameworks": {
        "net35-cf": {
            "frameworkAssemblies": {
                "mscorlib": "",
                "System": "",
                "System.Core": ""
            }
        }
    }
}

Visual Studio 2015 - Classic CSPROJ

PropertyGroup

    <NoStdLib>True</NoStdLib>
    <NoConfig>true</NoConfig>
    <FileAlignment>512</FileAlignment>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>

ItemGroup

    <Reference Include="mscorlib, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
    <Reference Include="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />

Project

  <Import Project="$(SolutionDir)Microsoft.CompactFramework.CSharp.targets" />

Use deprecated MSBuild 3.5

  • Path: C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe
  • On 'C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.CompactFramework.CSharp.targets' file replace '$(MSBuildBinPath)' by 'C:\Windows\Microsoft.NET\Framework\v3.5'.
  • On .CSPROJ file, replace '$(MSBuildBinPath)' by 'C:\Windows\Microsoft.NET\Framework\v3.5'.
@pentestdude
Copy link

Is this supposed to work on VS2019 as well?

@skarllot
Copy link
Author

@pentestdude Yes, it is

@dittodhole
Copy link

Finally got it to work with:

<AssemblySearchPaths>$(AssemblySearchPaths);C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE;</AssemblySearchPaths>

instead of the hint paths.

this one is genious!

applied it, like:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net35-cf</TargetFrameworks>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
  </PropertyGroup>
  <PropertyGroup Condition="'$(TargetFramework)' == 'net35-cf'">
    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
    <TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <TargetFrameworkProfile>CompactFramework</TargetFrameworkProfile>
    <DefineConstants>$(DefineConstants);NET35_CF;WindowsCE</DefineConstants>
    <NoStdLib>True</NoStdLib>
    <NoConfig>true</NoConfig>
    <FileAlignment>512</FileAlignment>
    <PlatformID>E2BECB1F-8C8C-41BA-B736-9BE7D946A398</PlatformID>
    <Optimize>False</Optimize>
    <AssemblySearchPaths>$(AssemblySearchPaths);C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE;</AssemblySearchPaths>
  </PropertyGroup>
  <ItemGroup Condition="'$(TargetFramework)' == 'net35-cf'">
    <Reference Include="mscorlib" />
    <Reference Include="System.Core" />
  </ItemGroup>
...

works like charm, thanks a lot! <3

@HaronDDC
Copy link

HaronDDC commented Jun 4, 2021

Hi! It is amazing article. Thanks a lot for your work. Couldn't you know any way to debug Compact framework applications using VS 2019? Thanks a lot!

@skarllot
Copy link
Author

skarllot commented Jun 4, 2021

@HaronDDC unfortunately not

@scottpidzarko
Copy link

scottpidzarko commented Aug 23, 2022

Thanks for the amazing article. I have successfully built a dll from a project I used to have to work on in Visual Studio 2008.

I am having some difficulty getting my compiled dll to get apparently get built with the same toolchain as in Visual studio 2008. My embedded device requires that the dlls used be signed and valid in a "Sandbox" - and System.Threading.Interlocked isn't allowed. Building the project with Visual Studio 2008 produces different output when viewed with DnSpy:

The problem is with multicast delegates, ie: this.RecoverNotificationEvent += new DelegateNoParametersEvent(this.RecoverNotificationEventHandler);

2008 happily outputs this, which is a-OK:

// Token: 0x0600005E RID: 94 RVA: 0x000025B8 File Offset: 0x000007B8
[MethodImpl(MethodImplOptions.Synchronized)]
internal void add_RecoverNotificationEvent(DelegateNoParametersEvent value)
{
    this.RecoverNotificationEvent = (DelegateNoParametersEvent)Delegate.Combine(this.RecoverNotificationEvent, value);
}

Whereas vs2019 does this to the compiled output, which utilizes Interlocked which is not sandbox compatible:

// Token: 0x0600016F RID: 367 RVA: 0x0000325C File Offset: 0x0000145C
[CompilerGenerated]
internal void add_RecoverNotificationEvent(DelegateNoParametersEvent value)
{
    DelegateNoParametersEvent delegateNoParametersEvent = this.RecoverNotificationEvent;
    DelegateNoParametersEvent delegateNoParametersEvent2;
    do
    {
        delegateNoParametersEvent2 = delegateNoParametersEvent;
        DelegateNoParametersEvent delegateNoParametersEvent3 = (DelegateNoParametersEvent)Delegate.Combine(delegateNoParametersEvent2, value);
        delegateNoParametersEvent = Interlocked.CompareExchange<DelegateNoParametersEvent>(ref this.RecoverNotificationEvent, delegateNoParametersEvent3, delegateNoParametersEvent2);
    }
    while (delegateNoParametersEvent != delegateNoParametersEvent2);
}

My .csproj:

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<TargetFrameworks>net35-cf</TargetFrameworks>		
		<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
		<GenerateDocumentationFile>true</GenerateDocumentationFile>
		<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>		
		<!-- allow ourselves to use AssemblyInfo in .net sdk projects -->
		<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
		<!-- this is needed for the wildcard in the build nubmer -->
		<Deterministic>false</Deterministic>
	</PropertyGroup>	
	<PropertyGroup Condition="'$(TargetFramework)' == 'net35-cf'">
		<!-- stop XML files from being generated -->		
		<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
		<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
		<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
		<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
		<TargetFrameworkProfile>CompactFramework</TargetFrameworkProfile>
		<DefineConstants>$(DefineConstants);NET35_CF;WindowsCE</DefineConstants>
		<NoStdLib>True</NoStdLib>
		<NoConfig>true</NoConfig>
		<FileAlignment>512</FileAlignment>
		<PlatformID>E2BECB1F-8C8C-41BA-B736-9BE7D946A398</PlatformID>
		<Optimize>False</Optimize>
		<AssemblySearchPaths>$(AssemblySearchPaths);C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE;</AssemblySearchPaths>
	</PropertyGroup>

	<ItemGroup Condition="'$(TargetFramework)' == 'net35-cf'">
		<Reference Include="mscorlib, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />		
		<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
			<SpecificVersion>False</SpecificVersion>
			<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
		</Reference>
		<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
			<SpecificVersion>False</SpecificVersion>
			<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
		</Reference>
		<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
			<SpecificVersion>False</SpecificVersion>
			<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
		</Reference>
		<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
			<SpecificVersion>False</SpecificVersion>
			<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
		</Reference>
		<Reference Include="System, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
		<Reference Include="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
		<Reference Include="System.Data, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac" />
	</ItemGroup>
	<!-- uncommenting this makes it angry about outputpaths. Adding an outputpath tag makes it angry about a target in obj which I can't work around-->
	<!-- <Import Project="C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.CompactFramework.CSharp.targets" /> -->
</Project>

Any pointers/comments? I've been trying different methods throughout the last couple of days and I can't seem to get over this hurdle any way I go about it. I know what I'm hoping to do can be done, as someone I know in the same industry has no problem using Jetbrains Rider to specify the version of MSBuild and point at the CompactFrameWork.CSharp.targets file and get what he needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment