Windows PC 자동 절전 도구: .NET Native AOT 기반 sleep-pc 개발기
태그: #DotNet nativeaot win32api #ConsoleApp #PowerManagement
개요
Windows PC의 자동 절전 기능을 구현하는 .NET Native AOT 도구 개발 과정을 다룬 기술 문서입니다. Win32 API를 활용한 강제 절전 기능부터 Native AOT 컴파일, NuGet 패키지 배포까지의 전체 개발 과정을 단계별로 설명합니다.
배경 및 문제 상황
절전 문제의 복잡성
- MacBook과 Windows 노트북의 절전 실패 문제가 빈번히 발생
- Windows Media Player Legacy 재생 완료 후 자동 절전이 되지 않는 특정 상황 발생
- 기존 전원 관리 설정(powercfg 등)으로는 근본적 해결이 어려운 경우 존재
개발 동기
배경 영상 재생 후 자동 절전이 필요한 사용자를 위해 타이머 기반 강제 절전 도구 개발 필요성 대두
핵심 기술 구현
1. Win32 API를 통한 절전 기능
SetSuspendState 함수 활용
[DllImport("PowrProf.dll", SetLastError = true)]
static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
기본 구현 방식:
var wait = TimeSpan.FromSeconds(60 * 60); // 1시간
Thread.Sleep(wait);
SetSuspendState(false, false, false);
중요한 동작 특성
- hibernate=false 설정에도 불구하고 시스템 설정에 따라 실제로는 최대 절전 모드로 진입하는 경우 발생
- Hybrid Sleep 활성화 시 특히 이런 현상이 나타남
- 대부분의 사용 사례에서는 실제 절전 모드와 최대 절전 모드 구분이 크게 중요하지 않음
2. ConsoleAppFramework를 통한 CLI 개발
라이브러리 선택 이유
ConsoleAppFramework v5의 주요 특징:
- Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation
- AOT Safe CLI Framework
- C# Source Generator 기반 고성능 구현
- .NET 8+ 요구사항
구현 예제
public static async Task Countdown(
[Range(1, 99 * 60 * 60)]uint sleepDelaySeconds = 60 * 60,
bool dryRun = false,
CancellationToken ct = default)
{
var wait = TimeSpan.FromSeconds(sleepDelaySeconds);
await Task.Delay(wait, ct);
if (!dryRun)
{
SetSuspendState(false, false, false);
}
}
자동 생성되는 도움말:
Usage: [options...] [-h|--help] [--version]
Options:
-s|--seconds|--sleep-delay-seconds <uint> The time in seconds before the computer is put to sleep. Defaults to 1 hour (Default: 3600)
--dry-run If true, prints a message instead of sleeping (Optional)
3. Native AOT 컴파일 최적화
LibraryImport 마이그레이션
기존 DllImport에서 새로운 LibraryImport로 전환:
[LibraryImport("PowrProf.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetSuspendState(
[MarshalAs(UnmanagedType.U1)] bool hibernate,
[MarshalAs(UnmanagedType.U1)] bool forceCritical,
[MarshalAs(UnmanagedType.U1)] bool disableWakeEvent);
크기 최적화 설정
최종 실행 파일 크기 3.3MB 달성을 위한 설정:
<PublishAot>true</PublishAot>
<DebuggerSupport>false</DebuggerSupport>
<EventSourceSupport>false</EventSourceSupport>
<InvariantGlobalization>true</InvariantGlobalization>
<IlcDisableReflection>true</IlcDisableReflection>
<IlcOptimizationPreference>Size</IlcOptimizationPreference>
4. NuGet 패키지 배포 전략
컴프로마이즈 패키지 접근법
- 루트 패키지: .NET 8 프레임워크 의존적 빌드 + .NET 10 사용자를 위한 플랫폼별 버전 포인터
- 플랫폼별 패키지: Native AOT 에셋만 포함 (.NET 10+ 사용자용)
- RollForward Major 설정: .NET 9에서도 실행 가능
프로젝트 파일 구성
<PropertyGroup Condition="$(RuntimeIdentifier) != ''">
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier) == ''">
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
</PropertyGroup>
5. 콘솔 UI 개선
실시간 카운트다운 구현
백스페이스를 활용한 인플레이스 업데이트:
Console.Write("⏰ Time remaining: ");
Console.Write("\b\b\b\b\b\b\b\b{0:hh\\:mm\\:ss}", wait);
정확한 타이밍 제어
var deadline = DateTimeOffset.UtcNow.Add(wait);
while (!ct.IsCancellationRequested)
{
Console.Write("\b\b\b\b\b\b\b\b{0:hh\\:mm\\:ss}", wait);
await Task.Delay(1_000, ct);
wait = deadline - DateTimeOffset.UtcNow;
}
실용적 팁과 주의사항
개발 시 고려사항
- DllImport vs LibraryImport: Native AOT에서는 LibraryImport 권장
- Spectre.Console 사용 제한: AOT 호환성 문제로 단순한 콘솔 조작 기법 활용
- 타이밍 드리프트 방지: 절대 시간 기준 계산으로 정확한 타이밍 보장
배포 최적화
- 크기 최적화: 다양한 트리밍 옵션 활용으로 ~0.3MB 추가 절약 가능
- Sizoscope 도구: Native AOT 바이너리 분석을 통한 크기 최적화 가이드
사용자 경험
- 드라이 런 모드: 실제 절전 없이 테스트 가능
- Ctrl+C 취소: 사용자가 언제든 실행 중단 가능
- UTF-8 인코딩: 이모지와 특수 문자 정상 출력
설치 및 사용법
설치 명령
dotnet tool install -g sleep-pc
기본 사용법
sleep-pc --seconds 3600 --dry-run # 1시간 후 절전 (테스트 모드)
sleep-pc -s 1800 # 30분 후 실제 절전
학습 리소스
관련 기술 문서
- ConsoleAppFramework v5 공식 문서: 고성능 CLI 프레임워크 활용법
- .NET Native AOT 가이드: 컴파일 최적화 및 크기 축소 기법
- Win32 Power Management API: SetSuspendState 함수 상세 사용법
추가 도구
- Sizoscope: Native AOT 바이너리 내부 분석 도구
- NuGet 패키징: .NET 도구 배포 전략 및 멀티 타겟팅
프로젝트 접근성
GitHub 저장소
전체 소스 코드와 구현 세부사항 확인 가능
NuGet 패키지
sleep-pc
이름으로 공식 배포, 글로벌 도구로 설치 가능
결론
Windows PC 절전 문제 해결을 위한 단순하면서도 효과적인 도구 개발 사례입니다. Win32 API 활용부터 최신 .NET Native AOT 기술 적용, 효율적인 NuGet 배포까지 모던 .NET 개발의 전체 스택을 다루고 있습니다. 특히 성능과 크기 최적화에 중점을 둔 실용적 접근법을 제시합니다.