On 29.12.2016 23:31, Tim Rentsch wrote:
[snip]
> The definitions for the CRACK_... macros (ie, in the generated
> file "generated/crackit.h") are produced programmatically from
> the HANDLE_... macros in <windowsx.h>, using a short awk script:
>
> #! /bin/awk -f
>
> $0 ~ /#define HANDLE_WM_/ {
> gsub( /[(]hwnd,/, "(fn," );
> gsub( /,fn[)]/, ")" );
> gsub( /[(][(]hwnd[)],/, "(" );
> gsub( /[(]fn[)][(]hwnd[)]/, "(fn)()" );
> gsub( / HANDLE_/, " CRACK_" );
> print
> }
>
> So, for what it's worth, that is now the best suggestion I have
> to offer.
Sorry for being very slow about things.
Anyway I've started on this road now, though not with AWK, which I just
barely remember from “The UNIX Programming Environment” long long ago…
Instead of macros I've resurrected, that is, I've reimplemented, an old
dispatching scheme of mine where a class that represents a kind of
window, inherits for example the interface
public wm::Paint::Handler
and just implements
auto on( wm::Paint const& )
-> Void
override
from that interface, in order to handle WM_PAINT, say. The curious
`Void` return type instead of plain `void` is in order to be able to
wrap calls of the handlers in a single general dispatcher.
I once ditched this scheme because it has abstraction costs, in
particular the `public` inheritance necessary for `dynamic_cast`, which
as far as I can see can only be avoided by a costly indirection.
I've just implemented the `wm::Paint` class and two others by hand, to
sound out the requirements for generating them automatically from
`<windowsx.h>`, and also as a proof of concept.
The current AWKward (?) C++ <windowsx.h> analysis code, that so far
only extracts the API level handler signatures from the <windowsx.h>
comments, looks like this:
[code]
#include <p/cppx/hopefully_and_fail.hpp> // cppx::(hopefully, fail)
#include <p/cppx/basic_type_aliases.hpp> // cppx::(Byte, Size)
#include <assert.h>
#include <ctype.h> // isspace
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdexcept>
#include <stdlib.h>
#include <vector>
using namespace std;
namespace cppx = progrock::cppx;
using cppx::hopefully;
using cppx::fail;
using cppx::Byte;
using cppx::Size;
auto starts_with( string const& prefix, string const& s )
-> bool
{ return s.substr( 0, prefix.length() ) == prefix; }
auto is_whitespace( char const ch )
-> bool
{ return !!::isspace( static_cast<Byte>( ch ) ); }
auto is_alphabetic( char const ch )
-> bool
{ return !!::isalpha( static_cast<Byte>( ch ) ); }
auto is_digit( char const ch )
-> bool
{ return !!::isdigit( static_cast<Byte>( ch ) ); }
auto is_identifier_char( char const ch )
-> bool
{ return is_digit( ch ) or is_alphabetic( ch ) or ch == '_'; }
class Tokenizer
{
private:
string s_;
int i_;
int n_;
static auto ends_token( char const start_ch, char const ch )
-> bool
{
assert( not is_whitespace( start_ch ) );
if( start_ch == '(' or start_ch == ')' )
return true;
else if( start_ch == '/' )
return ch != '*';
else if( start_ch == '*' )
return ch != '/';
else if( start_ch == '0' )
return ch != 'L';
else if( is_alphabetic( start_ch ) )
return not is_identifier_char( ch );
else
return true;
}
public:
auto finished() const
-> bool
{ return n_ == 0; }
void advance()
{
int const i_beyond = s_.length();
i_ += n_;
if( i_ == i_beyond )
{
n_ = 0;
return;
}
// Skip whitespace at start.
while( i_ < i_beyond and is_whitespace( s_[i_] ) ) { ++i_; }
// Find end of token.
int i2 = i_ + 1;
while( i2 < i_beyond and not ends_token( s_[i_], s_[i2] ) ) {
++i2; }
n_ = i2 - i_;
}
auto current() const
-> string
{ return s_.substr( i_, n_ ); }
Tokenizer( string const& s )
: s_( s )
, i_( 0 )
, n_( 0 )
{ advance(); }
};
struct Argument
{
string name;
string type;
};
struct Function
{
string base_name;
string result_type;
vector<Argument> arguments;
auto str() const
-> string
{
string result = base_name + '(';
int const n = arguments.size();
if( n > 0 ) { result += ' '; }
for( int i = 0; i < n; ++i )
{
if( i >= 1 ) { result += ", "; }
auto const& arg = arguments[i];
result += arg.type + ' ' +
arg.name;
}
if( n > 0 ) { result += ' '; }
result += ')';
return result_type == "void"
? "void " + result
: "auto " + result + " -> " + result_type;
}
};
auto pointer_notation( string const& typespec )
-> string
{ return starts_with( "LP", typespec )? typespec.substr( 2 ) + "*" :
typespec; }
void cpp_main()
{
ifstream in( "windowsx_part.txt" );
hopefully( not in.fail() )
|| fail( "Failed to open input file" );
string line;
while( getline( in, line ) )
{
if( starts_with( "/* ", line ) )
{
Function f;
Tokenizer t{ line };
t.advance(); // Skip "/*".
f.result_type = pointer_notation( t.current() );
t.advance();
f.base_name = t.current().substr( 6 );
t.advance();
hopefully( t.current() == "(" )
|| fail( "Expected `(` in `" + line + "`" );
t.advance(); // Skip "("
for( bool more_arguments = true; more_arguments; t.advance() )
{
string arg_name;
string arg_type;
string last_token;
for( ;; )
{
hopefully( not t.finished() )
|| fail( "Unexpected end of line in `" + line +
"`" );
string current = t.current();
if( current == "," or current == ")" )
{
arg_name = last_token;
more_arguments = (current == ",");
break;
}
else
{
if( arg_type.length() != 0 and last_token !=
"*" ) { arg_type += " "; }
arg_type += pointer_notation( last_token );
last_token = current;
}
t.advance();
}
f.arguments.push_back( Argument{ arg_name, arg_type } );
}
cout << f.str() << endl;
}
}
}
auto main()
-> int
{
try
{
cpp_main();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
[/code]
It works on a copy of the relevant part of Microsoft's `<windowsx.h>`,
with the two comments that are real comments changed manually from `/*`
to `/***`, and it then produces this list of API level handler functions:
[output]
void Compacting( HWND hwnd, UINT compactRatio )
void WinIniChange( HWND hwnd, CTSTR* lpszSectionName )
void SysColorChange( HWND hwnd )
auto QueryNewPalette( HWND hwnd ) -> BOOL
void PaletteIsChanging( HWND hwnd, HWND hwndPaletteChange )
void PaletteChanged( HWND hwnd, HWND hwndPaletteChange )
void FontChange( HWND hwnd )
void SpoolerStatus( HWND hwnd, UINT status, int cJobInQueue )
void DevModeChange( HWND hwnd, CTSTR* lpszDeviceName )
void TimeChange( HWND hwnd )
void Power( HWND hwnd, int code )
auto QueryEndSession( HWND hwnd ) -> BOOL
void EndSession( HWND hwnd, BOOL fEnding )
void Quit( HWND hwnd, int exitCode )
void SystemError( HWND hwnd, int errCode )
auto Create( HWND hwnd, CREATESTRUCT* lpCreateStruct ) -> BOOL
auto NCCreate( HWND hwnd, CREATESTRUCT* lpCreateStruct ) -> BOOL
void Destroy( HWND hwnd )
void NCDestroy( HWND hwnd )
void ShowWindow( HWND hwnd, BOOL fShow, UINT status )
void SetRedraw( HWND hwnd, BOOL fRedraw )
void Enable( HWND hwnd, BOOL fEnable )
void SetText( HWND hwnd, CTSTR* lpszText )
auto GetText( HWND hwnd, int cchTextMax, TSTR* lpszText ) -> INT
auto GetTextLength( HWND hwnd ) -> INT
auto WindowPosChanging( HWND hwnd, WINDOWPOS* lpwpos ) -> BOOL
void WindowPosChanged( HWND hwnd, const WINDOWPOS* lpwpos )
void Move( HWND hwnd, int x, int y )
void Size( HWND hwnd, UINT state, int cx, int cy )
void Close( HWND hwnd )
auto QueryOpen( HWND hwnd ) -> BOOL
void GetMinMaxInfo( HWND hwnd, MINMAXINFO* lpMinMaxInfo )
void Paint( HWND hwnd )
auto EraseBkgnd( HWND hwnd, HDC hdc ) -> BOOL
auto IconEraseBkgnd( HWND hwnd, HDC hdc ) -> BOOL
void NCPaint( HWND hwnd, HRGN hrgn )
auto NCCalcSize( HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS*
lpcsp ) -> UINT
auto NCHitTest( HWND hwnd, int x, int y ) -> UINT
auto QueryDragIcon( HWND hwnd ) -> HICON
void DropFiles( HWND hwnd, HDROP hdrop )
void Activate( HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized )
void ActivateApp( HWND hwnd, BOOL fActivate, DWORD dwThreadId )
auto NCActivate( HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL
fMinimized ) -> BOOL
void SetFocus( HWND hwnd, HWND hwndOldFocus )
void KillFocus( HWND hwnd, HWND hwndNewFocus )
void Key( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void Key( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void Char( HWND hwnd, TCHAR ch, int cRepeat )
void DeadChar( HWND hwnd, TCHAR ch, int cRepeat )
void SysKey( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void SysKey( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void SysChar( HWND hwnd, TCHAR ch, int cRepeat )
void SysDeadChar( HWND hwnd, TCHAR ch, int cRepeat )
void MouseMove( HWND hwnd, int x, int y, UINT keyFlags )
void LButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void LButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void LButtonUp( HWND hwnd, int x, int y, UINT keyFlags )
void RButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void RButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void RButtonUp( HWND hwnd, int x, int y, UINT flags )
void MButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void MButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void MButtonUp( HWND hwnd, int x, int y, UINT flags )
void MouseWheel( HWND hwnd, int xPos, int yPos, int zDelta, UINT fwKeys )
void NCMouseMove( HWND hwnd, int x, int y, UINT codeHitTest )
void NCLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCLButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
void NCRButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCRButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCRButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
void NCMButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCMButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCMButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
auto MouseActivate( HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT
msg ) -> int
void CancelMode( HWND hwnd )
void Timer( HWND hwnd, UINT id )
void InitMenu( HWND hwnd, HMENU hMenu )
void InitMenuPopup( HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu )
void MenuSelect( HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup,
UINT flags )
auto MenuChar( HWND hwnd, UINT ch, UINT flags, HMENU hmenu ) -> DWORD
void Command( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify )
void HScroll( HWND hwnd, HWND hwndCtl, UINT code, int pos )
void VScroll( HWND hwnd, HWND hwndCtl, UINT code, int pos )
void Cut( HWND hwnd )
void Copy( HWND hwnd )
void Paste( HWND hwnd )
void Clear( HWND hwnd )
void Undo( HWND hwnd )
auto RenderFormat( HWND hwnd, UINT fmt ) -> HANDLE
void RenderAllFormats( HWND hwnd )
void DestroyClipboard( HWND hwnd )
void DrawClipboard( HWND hwnd )
void PaintClipboard( HWND hwnd, HWND hwndCBViewer, const PAINTSTRUCT*
lpPaintStruct )
void SizeClipboard( HWND hwnd, HWND hwndCBViewer, const RECT* lprc )
void VScrollClipboard( HWND hwnd, HWND hwndCBViewer, UINT code, int pos )
void HScrollClipboard( HWND hwnd, HWND hwndCBViewer, UINT code, int pos )
void AskCBFormatName( HWND hwnd, int cchMax, TSTR* rgchName )
void ChangeCBChain( HWND hwnd, HWND hwndRemove, HWND hwndNext )
auto SetCursor( HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg )
-> BOOL
void SysCommand( HWND hwnd, UINT cmd, int x, int y )
auto ICreate( HWND hwnd, const MDICREATESTRUCT* lpmcs ) -> HWND
void IDestroy( HWND hwnd, HWND hwndDestroy )
void IActivate( HWND hwnd, BOOL fActive, HWND hwndActivate, HWND
hwndDeactivate )
void IRestore( HWND hwnd, HWND hwndRestore )
auto INext( HWND hwnd, HWND hwndCur, BOOL fPrev ) -> HWND
void IMaximize( HWND hwnd, HWND hwndMaximize )
auto ITile( HWND hwnd, UINT cmd ) -> BOOL
auto ICascade( HWND hwnd, UINT cmd ) -> BOOL
void IIconArrange( HWND hwnd )
auto IGetActive( HWND hwnd ) -> HWND
auto ISetMenu( HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU
hmenuWindow ) -> HMENU
void ChildActivate( HWND hwnd )
auto InitDialog( HWND hwnd, HWND hwndFocus, ARAM* lParam ) -> BOOL
auto NextDlgCtl( HWND hwnd, HWND hwndSetFocus, BOOL fNext ) -> HWND
void ParentNotify( HWND hwnd, UINT msg, HWND hwndChild, int idChild )
void EnterIdle( HWND hwnd, UINT source, HWND hwndSource )
auto GetDlgCode( HWND hwnd, MSG* lpmsg ) -> UINT
auto CtlColor( HWND hwnd, HDC hdc, HWND hwndChild, int type ) -> HBRUSH
void SetFont( HWND hwndCtl, HFONT hfont, BOOL fRedraw )
auto GetFont( HWND hwnd ) -> HFONT
void DrawItem( HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem )
void MeasureItem( HWND hwnd, MEASUREITEMSTRUCT* lpMeasureItem )
void DeleteItem( HWND hwnd, const DELETEITEMSTRUCT* lpDeleteItem )
auto CompareItem( HWND hwnd, const COMPAREITEMSTRUCT* lpCompareItem ) -> int
auto VkeyToItem( HWND hwnd, UINT vk, HWND hwndListbox, int iCaret ) -> int
auto CharToItem( HWND hwnd, UINT ch, HWND hwndListbox, int iCaret ) -> int
void QueueSync( HWND hwnd )
void CommNotify( HWND hwnd, int cid, UINT flags )
void DisplayChange( HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT
cyScreen )
auto DeviceChange( HWND hwnd, UINT uEvent, DWORD dwEventData ) -> BOOL
void ContextMenu( HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos )
void HotKey( HWND hwnd, int idHotKey, UINT fuModifiers, UINT vk )
[/output]
So, I've made some progress on this, taking your advice – perhaps taking
it more far than you intended. :)
- Alf