> I can't see where the dialogs unit is getting the TMsgDlgButtons method > or function or procedure or whatever it is called in Pascal from.
Short story: the patch is attached, it should help:) Longer explanation: 1. TMsgDlgButtons is a "type". It's a set (which is like a type-safe bitfield in Pascal). Writing "Dialogs.TMsgDlgButtons" means "take TMsgDlgButtons type from Dialogs unit, not from any other unit that may define the same name" --- that's how you deal with multiple used units having the same identifier in Pascal. 2. What happens in this code is a little dirty, as mricron code defines it's own type "TMsgDlgButtons", with the *exact* same memory layout as standard "TMsgDlgButtons" type in "Dialogs" unit. "Dialogs" unit is part of the Lazarus library (LCL). Then the line lButtons:= Dialogs.TMsgDlgButtons(Buttons); converts one type to another. The dirtyness here is that such typecast avoids any type checks, it just assumes that memory layout of both "TMsgDlgButtons" types matches, and that the programmer knows what (s)he is doing:) 3. To make it a little confusing, type names are the same, so you need to be aware how compiler resolves them, and some error messages become unclear. This message from FPC: Illegal type conversion: "TMsgDlgButtons" to "TMsgDlgButtons" actually means that we cannot convert "TMsgDlgButtons as defined in unit dialogsx" to "TMsgDlgButtons as defined in unit Dialogs". Possibly FPC checks got stricter? Which would be a good thing here --- this code is indeed dangerous, it's good that it's prohibited, IMHO. In fact, Lazarus Dialogs.TMsgDlgButtons type did change (there's a new enum mbClose), it only accidentally didn't change the memory layout of TMsgDlgButtons (as mbClose was added at the end). 4. The attached patch just does the type conversion the long (but safe) way. Regards, Michalis
--- common/dialogsx.pas.orig 2016-02-06 15:20:36.000000000 +0100 +++ common/dialogsx.pas 2016-02-06 15:32:45.000000000 +0100 @@ -66,6 +66,36 @@ end; {$ENDIF} +{ Convert our TMsgDlgButtons type to Dialogs.TMsgDlgButtons type + in a type-safe manner. Do not assume that memory layout matches between + - TMsgDlgButtons and Dialogs.TMsgDlgButtons, or + - TMsgDlgBtn and Dialogs.TMsgDlgBtn. +} +function MsgDlgButtonsConvertToStandard( + const Buttons: TMsgDlgButtons): Dialogs.TMsgDlgButtons; +var + B: TMsgDlgBtn; +begin + Result := []; + for B := Low(B) to High(B) do + if B in Buttons then + { convert our TMsgDlgBtn to Dialogs.TMsgDlgBtn type } + case B of + mbYes : Include(Result, Dialogs.mbYes ); + mbNo : Include(Result, Dialogs.mbNo ); + mbOK : Include(Result, Dialogs.mbOK ); + mbCancel : Include(Result, Dialogs.mbCancel ); + mbAbort : Include(Result, Dialogs.mbAbort ); + mbRetry : Include(Result, Dialogs.mbRetry ); + mbIgnore : Include(Result, Dialogs.mbIgnore ); + mbAll : Include(Result, Dialogs.mbAll ); + mbNoToAll : Include(Result, Dialogs.mbNoToAll ); + mbYesToAll: Include(Result, Dialogs.mbYesToAll); + mbHelp : Include(Result, Dialogs.mbHelp ); + else raise Exception.Create('Unsupported TMsgDlgBtn value'); + end; +end; + function MsgDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word; {$IFDEF GUI} var @@ -74,7 +104,7 @@ begin lDlgType := Dialogs.TMsgDlgType(DlgType); - lButtons:= Dialogs.TMsgDlgButtons(Buttons); + lButtons:= MsgDlgButtonsConvertToStandard(Buttons); result := MessageDlg(Msg, lDlgType, lButtons,HelpCtx); {$ELSE} begin