Skip to content

Commit

Permalink
Port Petzold HelloWin from WInterop
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyKuhne committed Feb 4, 2024
1 parent 452ce51 commit 7ece471
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/samples/Petzold/5th/HelloWin/HelloWin.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<ApplicationManifest>app1.manifest</ApplicationManifest>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\thirtytwo\thirtytwo.csproj" />
</ItemGroup>
</Project>
152 changes: 152 additions & 0 deletions src/samples/Petzold/5th/HelloWin/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Windows.Win32.UI.WindowsAndMessaging;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.Media.Audio;
using System.Runtime.InteropServices;
using Windows;

namespace HelloWin;

/// <summary>
/// Sample from Programming Windows, 5th Edition.
/// Original (c) Charles Petzold, 1998
/// Figure 3-1, Pages 44-46.
/// </summary>
internal unsafe static class Program
{
// Windows metadata doesn't currently define this as it is a macro.
const uint SND_ALIAS_SYSTEMHAND = 'S' | (((uint)'H') << 8);

[STAThread]
private static void Main()
{
Application.Run(new HelloWindow("HelloWin"));

// Using Window and WindowClass are recommended. They do all of this setup for you.
// To do the same thing manually, you would do the following:

const string szAppName = "HelloWin";

WindowProcedure wndProc = WindowProcedure;
HMODULE module;
Interop.GetModuleHandleEx(0, (PCWSTR)null, &module);

HWND hwnd;

fixed (char* appName = szAppName)
fixed (char* title = "The Hello Program")
{
WNDCLASSEXW wndClass = new()
{
cbSize = (uint)sizeof(WNDCLASSEXW),
style = WNDCLASS_STYLES.CS_HREDRAW | WNDCLASS_STYLES.CS_VREDRAW,
lpfnWndProc = (WNDPROC)Marshal.GetFunctionPointerForDelegate(wndProc),
hInstance = module,
hIcon = Interop.LoadIcon(default, Interop.IDI_APPLICATION),
hCursor = Interop.LoadCursor(default, Interop.IDC_ARROW),
hbrBackground = (HBRUSH)Interop.GetStockObject(GET_STOCK_OBJECT_FLAGS.WHITE_BRUSH),
lpszClassName = appName
};

ATOM atom = Interop.RegisterClassEx(&wndClass);

hwnd = Interop.CreateWindowEx(
WINDOW_EX_STYLE.WS_EX_OVERLAPPEDWINDOW,
appName,
title,
WINDOW_STYLE.WS_OVERLAPPEDWINDOW,
Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT,
HWND.Null,
HMENU.Null,
module,
null);


}

Interop.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_SHOWDEFAULT);
Interop.UpdateWindow(hwnd);

while (Interop.GetMessage(out MSG msg, HWND.Null, 0, 0))
{
Interop.TranslateMessage(msg);
Interop.DispatchMessage(msg);
}

GC.KeepAlive(wndProc);
}

private static LRESULT WindowProcedure(HWND window, uint message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case Interop.WM_CREATE:
Interop.PlaySound(
(char*)SND_ALIAS_SYSTEMHAND,
HMODULE.Null,
SND_FLAGS.SND_ASYNC | SND_FLAGS.SND_NODEFAULT | SND_FLAGS.SND_ALIAS_ID);
return (LRESULT)0;
case Interop.WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = Interop.BeginPaint(window, &ps);

RECT rect;
Interop.GetClientRect(window, &rect);

// Technically this is unsafe as ellipsis options will modify the passed in string.
fixed (char* text = "Hello, Windows 98!")
{
_ = Interop.DrawTextEx(
hdc,
text,
-1,
&rect,
DRAW_TEXT_FORMAT.DT_SINGLELINE | DRAW_TEXT_FORMAT.DT_CENTER | DRAW_TEXT_FORMAT.DT_VCENTER,
null);
}

Interop.EndPaint(window, &ps);
return (LRESULT)0;
case Interop.WM_DESTROY:
Interop.PostQuitMessage(0);
return (LRESULT)0;
}

return Interop.DefWindowProc(window, message, wParam, lParam);
}

private class HelloWindow : MainWindow
{
public HelloWindow(string text) : base(text, backgroundBrush: StockBrush.White)
{
}

protected override LRESULT WindowProcedure(HWND window, MessageType message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case MessageType.Create:
Interop.PlaySound(
(char*)SND_ALIAS_SYSTEMHAND,
HMODULE.Null,
SND_FLAGS.SND_ASYNC | SND_FLAGS.SND_NODEFAULT | SND_FLAGS.SND_ALIAS_ID);
return (LRESULT)0;
case MessageType.Paint:
using (DeviceContext dc = window.BeginPaint())
{
dc.DrawText(
"Hello, Windows 98!",
window.GetClientRectangle(),
DrawTextFormat.SingleLine | DrawTextFormat.Center | DrawTextFormat.VerticallyCenter);
}
return (LRESULT)0;
}

return base.WindowProcedure(window, message, wParam, lParam);
}
}
}
32 changes: 32 additions & 0 deletions src/samples/Petzold/5th/HelloWin/app1.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>

<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- Windows 10 1703 level of DPI awareness -->
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>

<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>

</assembly>
7 changes: 7 additions & 0 deletions thirtytwo.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AltWind", "src\samples\Petz
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clover", "src\samples\Petzold\5th\Clover\Clover.csproj", "{2A3E46F6-6E58-4FA6-8CF9-9EABFD288BC4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWin", "src\samples\Petzold\5th\HelloWin\HelloWin.csproj", "{FE627283-6848-44D9-B17D-F483625ED43F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -83,6 +85,10 @@ Global
{2A3E46F6-6E58-4FA6-8CF9-9EABFD288BC4}.Debug|x64.Build.0 = Debug|x64
{2A3E46F6-6E58-4FA6-8CF9-9EABFD288BC4}.Release|x64.ActiveCfg = Release|x64
{2A3E46F6-6E58-4FA6-8CF9-9EABFD288BC4}.Release|x64.Build.0 = Release|x64
{FE627283-6848-44D9-B17D-F483625ED43F}.Debug|x64.ActiveCfg = Debug|x64
{FE627283-6848-44D9-B17D-F483625ED43F}.Debug|x64.Build.0 = Debug|x64
{FE627283-6848-44D9-B17D-F483625ED43F}.Release|x64.ActiveCfg = Release|x64
{FE627283-6848-44D9-B17D-F483625ED43F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -97,6 +103,7 @@ Global
{13110246-EBE1-441B-B721-B0614D62B13B} = {C059056C-D771-4CF5-A93F-AA7140FF7827}
{1DFDC4A1-DF15-402F-A6AB-5C90A2B71C48} = {13110246-EBE1-441B-B721-B0614D62B13B}
{2A3E46F6-6E58-4FA6-8CF9-9EABFD288BC4} = {13110246-EBE1-441B-B721-B0614D62B13B}
{FE627283-6848-44D9-B17D-F483625ED43F} = {13110246-EBE1-441B-B721-B0614D62B13B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3761BFC9-DBEF-4186-BB8B-BC0D84ED9AE5}
Expand Down

0 comments on commit 7ece471

Please sign in to comment.