在macOS/Linux编译面向Windows的.NET Core 8 C#程序及打印机设置方案
解决方案汇总
1. 利用.NET交叉编译+Windows目标框架
直接在Linux/macOS上编译面向Windows的程序,核心是指定Windows专属的目标框架和运行时:
- 修改项目文件(.csproj),指定目标框架为
net8.0-windows,并确保包含Windows平台资产:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-windows</TargetFramework> <WindowsSpecificAssets>all</WindowsSpecificAssets> <OutputType>Exe</OutputType> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Drawing.Common" Version="8.0.0" /> </ItemGroup> </Project>
- 使用
WINDOWS条件编译符号包裹System.Drawing.Printing相关代码,确保编译时能识别Windows专属符号:
#if WINDOWS using System.Drawing.Printing; public class PrinterHelper { public static (PaperSize, Margins) GetPrinterSettings(string printerName) { using var settings = new PrinterSettings { PrinterName = printerName }; return (settings.DefaultPageSettings.PaperSize, settings.DefaultPageSettings.Margins); } public static void Print(PrintDocument doc) => doc.Print(); } #endif
- 在Linux/macOS终端执行交叉编译命令,指定Windows运行时:
dotnet publish -c Release -r win-x64 --self-contained false
(注:需先执行dotnet workload install windows安装Windows目标编译组件)
2. 抽象打印接口分离平台逻辑
通过接口隔离Windows打印实现,避免跨平台编译时的符号错误:
- 核心项目定义打印接口:
public interface IPrintHandler { (PaperSizeInfo, MarginInfo) GetPrinterConfig(string printerName); void ExecutePrint(PrintContent content); } // 用自定义类替代System.Drawing的类型,避免跨平台引用问题 public record PaperSizeInfo(string Name, float Width, float Height); public record MarginInfo(int Left, int Top, int Right, int Bottom);
- 创建Windows专属类库,实现接口并引用
System.Drawing.Printing:
using System.Drawing.Printing; public class WindowsPrintHandler : IPrintHandler { public (PaperSizeInfo, MarginInfo) GetPrinterConfig(string printerName) { using var settings = new PrinterSettings { PrinterName = printerName }; var pageSettings = settings.DefaultPageSettings; return ( new PaperSizeInfo(pageSettings.PaperSize.Name, pageSettings.PaperSize.Width, pageSettings.PaperSize.Height), new MarginInfo(pageSettings.Margins.Left, pageSettings.Margins.Top, pageSettings.Margins.Right, pageSettings.Margins.Bottom) ); } public void ExecutePrint(PrintContent content) { // 基于System.Drawing.Printing实现打印逻辑 using var doc = new PrintDocument(); doc.PrintPage += (s, e) => { /* 绘制打印内容 */ }; doc.Print(); } }
- 主项目根据目标平台注册实现:
#if WINDOWS services.AddSingleton<IPrintHandler, WindowsPrintHandler>(); #else // 非Windows环境注册空实现,仅用于编译通过 services.AddSingleton<IPrintHandler, NullPrintHandler>(); #endif public class NullPrintHandler : IPrintHandler { public (PaperSizeInfo, MarginInfo) GetPrinterConfig(string printerName) => throw new NotSupportedException("仅支持Windows平台"); public void ExecutePrint(PrintContent content) => throw new NotSupportedException("仅支持Windows平台"); }
- 交叉编译时指定Windows运行时即可,编译过程不会因符号缺失报错。
3. 直接调用Win32 API(进阶方案)
跳过System.Drawing.Printing,通过P/Invoke调用Windows原生API获取打印机设置并执行打印,无需依赖Windows专属库的编译时引用:
using System.Runtime.InteropServices; public class Win32PrinterHelper { // 示例:获取打印机默认纸张尺寸(简化版) [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool GetPrinter(IntPtr hPrinter, int level, IntPtr pPrinter, int cbBuf, out int pcbNeeded); public static PaperSizeInfo GetDefaultPaperSize(string printerName) { // 省略Win32 API调用细节,需自行实现打印机句柄获取、参数解析逻辑 // 最终返回自定义的PaperSizeInfo对象 } // 打印相关Win32 API调用同理,如StartDocPrinter、StartPagePrinter等 }
这种方式编译时不依赖System.Drawing.Common,仅在Windows运行时调用API,适合对依赖控制严格的场景。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

