📄 myldbd4routines.pas
字号:
unit MYLDBD4Routines;
interface
{$I MYLDBVer.inc}
uses Windows, Classes, Sysutils,
{$IFNDEF D5H}
Db,
{$ENDIF}
MYLDBExcept,
MYLDBConst;
const
kernel = 'kernel32.dll';
oleaut = 'oleaut32.dll';
var
ClearAnyProc: Pointer; { Handler clearing a varAny }
type
{$IFNDEF D5H}
{ TMasterDataLink }
TMasterDataLink = class(TDetailDataLink)
private
FDataSet: TDataSet;
FFieldNames: string;
FFields: TList;
FOnMasterChange: TNotifyEvent;
FOnMasterDisable: TNotifyEvent;
procedure SetFieldNames(const Value: string);
protected
procedure ActiveChanged; override;
procedure CheckBrowseMode; override;
function GetDetailDataSet: TDataSet; override;
procedure LayoutChanged; override;
procedure RecordChanged(Field: TField); override;
public
constructor Create(DataSet: TDataSet);
destructor Destroy; override;
property FieldNames: string read FFieldNames write SetFieldNames;
property Fields: TList read FFields;
property OnMasterChange: TNotifyEvent read FOnMasterChange write FOnMasterChange;
property OnMasterDisable: TNotifyEvent read FOnMasterDisable write FOnMasterDisable;
end;
{$ENDIF}
StrRec = packed record
allocSiz: Longint;
refCnt: Longint;
length: Longint;
end;
{ FloatToText, FloatToTextFmt, TextToFloat, and FloatToDecimal type codes }
// TFloatValue = (fvExtended, fvCurrency);
{ FloatToText format codes }
// TFloatFormat = (ffGeneral, ffExponent, ffFixed, ffNumber, ffCurrency);
{ FloatToDecimal result record }
TFloatRec = packed record
Exponent: Smallint;
Negative: Boolean;
Digits: array[0..20] of Char;
end;
PMemoryManager = ^TMemoryManager;
TMemoryManager = record
GetMem: function(Size: Integer): Pointer;
FreeMem: function(P: Pointer): Integer;
ReallocMem: function(P: Pointer; Size: Integer): Pointer;
end;
TFormatSettings = record
CurrencyFormat: Byte;
NegCurrFormat: Byte;
ThousandSeparator: Char;
DecimalSeparator: Char;
CurrencyDecimals: Byte;
DateSeparator: Char;
TimeSeparator: Char;
ListSeparator: Char;
CurrencyString: string;
ShortDateFormat: string;
LongDateFormat: string;
TimeAMString: string;
TimePMString: string;
ShortTimeFormat: string;
LongTimeFormat: string;
ShortMonthNames: array[1..12] of string;
LongMonthNames: array[1..12] of string;
ShortDayNames: array[1..7] of string;
LongDayNames: array[1..7] of string;
TwoDigitYearCenturyWindow: Word;
end;
const
skew = sizeof(StrRec);
rOff = sizeof(StrRec) - sizeof(Longint); { refCnt offset }
overHead = sizeof(StrRec) + 1;
const
MinCurrency: Currency = -922337203685477.5807 {$IFDEF LINUX} + 1 {$ENDIF}; //!! overflow?
MaxCurrency: Currency = 922337203685477.5807 {$IFDEF LINUX} - 1 {$ENDIF}; //!! overflow?
const
reInvalidPtr = 2;
reVarInvalidOp = 16;
(*
reOutOfMemory = 1;
reDivByZero = 3;
reRangeError = 4;
reIntOverflow = 5;
reInvalidOp = 6;
reZeroDivide = 7;
reOverflow = 8;
reUnderflow = 9;
reInvalidCast = 10;
reAccessViolation = 11;
reStackOverflow = 12;
reControlBreak = 13;
rePrivInstruction = 14;
reVarTypeCast = 15;
reVarDispatch = 17;
reVarArrayCreate = 18;
reVarNotArray = 19;
reVarArrayBounds = 20;
reAssertionFailed = 21;
reExternalException = 22; { not used here; in SysUtils }
reIntfCastError = 23;
reSafeCallError = 24;
*)
function MYLDB_VarArrayGet(var A: Variant; IndexCount: Integer;
Indices: Integer): Variant; cdecl;
function VarArrayGet(const A: Variant; const Indices: array of Integer): Variant;
{ Memory manager support }
procedure GetMemoryManager(var MemMgr: TMemoryManager);
procedure SetMemoryManager(const MemMgr: TMemoryManager);
function IsMemoryManagerSet: Boolean;
procedure Error(errorCode: Byte);
{ FloatToCurr will range validate a value to make sure it falls
within the acceptable currency range }
{ FloatToCurr will range validate a value to make sure it falls
within the acceptable currency range }
function FloatToCurr(const Value: Extended): Currency;
function TryFloatToCurr(const Value: Extended; out AResult: Currency): Boolean;
function TryStrToFloat(const S: string; out Value: Extended): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Double): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Single): Boolean; overload;
(*
function FloatToStr(Value: Extended): string; overload;
function FloatToStr(Value: Extended;
const FormatSettings: TFormatSettings): string; overload;
{ StrToFloat converts the given string to a floating-point value. The string
must consist of an optional sign (+ or -), a string of digits with an
optional decimal point, and an optional 'E' or 'e' followed by a signed
integer. Leading and trailing blanks in the string are ignored. The
DecimalSeparator global variable defines the character that must be used
as a decimal point. Thousand separators and currency symbols are not
allowed in the string. If the string doesn't contain a valid value, an
EConvertError exception is raised. }
function StrToFloat(const S: string): Extended; overload;
function StrToFloat(const S: string;
const FormatSettings: TFormatSettings): Extended; overload;
function StrToFloatDef(const S: string;
const Default: Extended): Extended; overload;
function StrToFloatDef(const S: string; const Default: Extended;
const FormatSettings: TFormatSettings): Extended; overload;
{ FloatToText converts the given floating-point value to its decimal
representation using the specified format, precision, and digits. The
Value parameter must be a variable of type Extended or Currency, as
indicated by the ValueType parameter. The resulting string of characters
is stored in the given buffer, and the returned value is the number of
characters stored. The resulting string is not null-terminated. For
further details, see the description of the FloatToStrF function. }
function FloatToText(BufferArg: PChar; const Value; ValueType: TFloatValue;
Format: TFloatFormat; Precision, Digits: Integer): Integer; overload;
function FloatToText(BufferArg: PChar; const Value; ValueType: TFloatValue;
Format: TFloatFormat; Precision, Digits: Integer;
const FormatSettings: TFormatSettings): Integer; overload;
function FloatToCurr(const Value: Extended): Currency;
function TryFloatToCurr(const Value: Extended; out AResult: Currency): Boolean;
*)
{ StrToBool converts the given string to a boolean value. If the string
doesn't contain a valid value, an EConvertError exception is raised.
BoolToStr converts boolean to a string value that in turn can be converted
back into a boolean. BoolToStr will always pick the first element of
the TrueStrs/FalseStrs arrays. }
var
TrueBoolStrs: array of String;
FalseBoolStrs: array of String;
const
DefaultTrueBoolStr = 'True'; // DO NOT LOCALIZE
DefaultFalseBoolStr = 'False'; // DO NOT LOCALIZE
function StrToBool(const S: string): Boolean;
function StrToBoolDef(const S: string; const Default: Boolean): Boolean;
function TryStrToBool(const S: string; out Value: Boolean): Boolean;
function BoolToStr(B: Boolean; UseBoolStrs: Boolean = False): string;
{$IFNDEF D5H}
{ AnsiSameText compares S1 to S2, without case-sensitivity. The compare
operation is controlled by the current Windows locale. The return value
is True if AnsiCompareText would have returned 0. }
function AnsiSameText(const S1, S2: string): Boolean;
{$ENDIF}
procedure FreeAndNil(var Obj);
type
TValueSign = -1..1;
const
NegativeValue = Low(TValueSign);
ZeroValue = 0;
PositiveValue = High(TValueSign);
function Sign(const AValue: Integer): TValueSign; overload;
function Sign(const AValue: Int64): TValueSign; overload;
function Sign(const AValue: Double): TValueSign; overload;
const
{ Units of time }
HoursPerDay = 24;
MinsPerHour = 60;
SecsPerMin = 60;
MSecsPerSec = 1000;
MinsPerDay = HoursPerDay * MinsPerHour;
SecsPerDay = MinsPerDay * SecsPerMin;
MSecsPerDay = SecsPerDay * MSecsPerSec;
SMissingDateTimeField = '?';
SInvalidDateTime = '''''%s'''' is not a valid date and time';
{ Used in RecodeDate, RecodeTime and RecodeDateTime for those datetime }
{ fields you want to leave alone }
RecodeLeaveFieldAsIs = High(Word);
function EncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond,
AMilliSecond: Word): TDateTime;
function TryEncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond,
AMilliSecond: Word; out AValue: TDateTime): Boolean;
function TryEncodeDate(Year, Month, Day: Word; out Date: TDateTime): Boolean;
function TryEncodeTime(Hour, Min, Sec, MSec: Word; out Time: TDateTime): Boolean;
procedure InvalidDateTimeError(const AYear, AMonth, ADay, AHour, AMinute,
ASecond, AMilliSecond: Word; const ABaseDate: TDateTime = 0);
implementation
var
MemoryManager: TMemoryManager = (
GetMem: SysGetMem;
FreeMem: SysFreeMem;
ReallocMem: SysReallocMem);
{$I MYLDBGETMEM.INC }
function VariantClear(var V: Variant): Integer; stdcall;
external oleaut name 'VariantClear';
function SafeArrayPtrOfIndex(VarArray: PVarArray; Indices: Pointer;
var pvData: Pointer): HResult; stdcall;
external oleaut name 'SafeArrayPtrOfIndex';
function SafeArrayGetElement(VarArray: PVarArray; Indices,
Data: Pointer): Integer; stdcall;
external oleaut name 'SafeArrayGetElement';
function GetVarArray(const A: Variant): PVarArray;
begin
if TVarData(A).VType and varArray = 0 then
raise EMYLDBException.Create(10434,ErrorLVarNotArray);
if TVarData(A).VType and varByRef <> 0 then
Result := PVarArray(TVarData(A).VPointer^) else
Result := TVarData(A).VArray;
end;
procedure _FreeMem;
asm
TEST EAX,EAX
JE @@1
CALL MemoryManager.FreeMem
OR EAX,EAX
JNE @@2
@@1: RET
@@2: MOV AL,reInvalidPtr
JMP Error
end;
procedure Error(errorCode: Byte);
begin
raise EMYLDBException.Create(10437,ErrorLSystemError,[errorCode]);
end;
procedure _LStrClr(var S: AnsiString);
asm
{ -> EAX pointer to str }
MOV EDX,[EAX] { fetch str }
TEST EDX,EDX { if nil, nothing to do }
JE @@done
MOV dword ptr [EAX],0 { clear str }
MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
DEC ECX { if < 0: literal str }
JL @@done
LOCK DEC [EDX-skew].StrRec.refCnt { threadsafe dec refCount }
JNE @@done
PUSH EAX
LEA EAX,[EDX-skew].StrRec.refCnt { if refCnt now zero, deallocate}
CALL _FreeMem
POP EAX
@@done:
end;
procedure VarInvalidOp;
asm
MOV AL,reVarInvalidOp
JMP Error
end;
procedure _VarClear(var V : Variant);
asm
XOR EDX,EDX
MOV DX,[EAX].TVarData.VType
TEST EDX,varByRef
JNE @@2
CMP EDX,varOleStr
JB @@2
CMP EDX,varString
JE @@1
CMP EDX,varAny
JNE @@3
JMP [ClearAnyProc]
@@1: MOV [EAX].TVarData.VType,varEmpty
ADD EAX,OFFSET TVarData.VString
JMP _LStrClr
@@2: MOV [EAX].TVarData.VType,varEmpty
RET
@@3: PUSH EAX
CALL VariantClear
end;
function MYLDB_VarArrayGet(var A: Variant; IndexCount: Integer;
Indices: Integer): Variant; cdecl;
var
VarArrayPtr: PVarArray;
VarType: Integer;
P: Pointer;
begin
if TVarData(A).VType and varArray = 0 then
raise EMYLDBException.Create(10433,ErrorLVarNotArray);
VarArrayPtr := GetVarArray(A);
if VarArrayPtr^.DimCount <> IndexCount then
raise EMYLDBException.Create(10435,ErrorLVarArrayBounds,
[VarArrayPtr^.DimCount,IndexCount]);
VarType := TVarData(A).VType and varTypeMask;
_VarClear(Result);
if VarType = varVariant then
begin
if SafeArrayPtrOfIndex(VarArrayPtr, @Indices, P) <> 0 then
raise EMYLDBException.Create(10436,ErrorLVarArrayBounds,
[-1,-1]);
Result := PVariant(P)^;
end else
begin
if SafeArrayGetElement(VarArrayPtr, @Indices,
@TVarData(Result).VPointer) <> 0 then
raise EMYLDBException.Create(10438,ErrorLVarArrayBounds,
[-1,-1]);
TVarData(Result).VType := VarType;
end;
end; //MYLDB_VarArrayGet
function VarArrayGet(const A: Variant; const Indices: array of Integer): Variant;
asm
{ ->EAX Pointer to A }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -