퀵레포트4.03에 대해 문의 합니다.
퀵레포트 4에서는 새롭게 추가된 사항이
preview 에서 text search 기능이 추가 되었습니다.
그런데 문제는 한글 search가 되지 않더군요.
그래서 관련 소스인 qrprev.pas, qrextra.pas qrprntr.pas를 보니
결국 퀵레포트도 메타파일을 받아서 다시 이 메타파일에서
메타레코드를 추출해 이것의 type을 분석해 문자열을 추출한후
이 추출한 문자열을 가지고 찾을 문자열과 비교하고 있다는 것을 알게 되었습니다.
그래서 해당소스를 보니 EnumEnhMetafile 이라는 win32 api와 이것의 콜백함수를 가지고
처리를 하고 있던 터라 이 콜백함수부분에서 문자열 추출이 완료되는 시점에서
문자열추출이 완료된 직후 break 나 showmessage를 걸어 해당 값을 화면으로 보면
한글은 모두 깨져서 출력이 됩니다.
그래서 델파이 6버전 부터 UTF8과 관련한 CHARATER SET CONVERT 처리 함수가 추가되어 있어서
제가 찾고자 하는 문자열을 직접 UTF8로 바꾸어 화면으로 본 결과 콜백함수부분에서 문자열 추출이
완료되는 시점에서 문자열추출이 완료된 직후의 값과 틀린 값이 나왔습니다.
메타파일에서 문자열이 어떠한 규칙으로 처리되는 지 아시는 분이 있으신지요..
아래는 QUICK REPORT 4.03에서 SEARTCH 부분을 처리하는 부분들을 추출한 자료입니다.
---------------------------------
qrprev unit에서
procedure TQRStandardPreview.FindButtonClick(Sender: TObject);
var
FindStr : string;
MatchCase : boolean;
I : integer;
APage : TMetafile;
Dummy : TList;
begin
if GetTextSearch(MatchCase, FindStr) then
begin
SearchResultBox.Enabled := true;
SearchTextLabel.Caption := FindStr;
SearchResultBox.Items.Clear;
for I := 1 to QRPrinter.PageCount do
begin
APage := QRPrinter.GetPage(I);
try
if StrInMetafile(FindStr, APage, MatchCase) then
SearchResultBox.Items.Add('Page ' + IntToStr(I));
finally
APage.Free;
end;
end;
if SearchResultBox.Items.Count = 0 then
begin
SearchResultBox.Items.Add('일치하는 결과가 없습니다.');
SearchResultBox.Enabled := false;
end;
end;
end;
-----------------------------------------------------
qrextra unit에서
type
MFBar = array of Char;
var
MFSearchStr : string;
MFFound : boolean;
MFMatchCase : boolean;
MFSearchBusy : boolean;
function MetaEnum(DC : THandle; HandleTable : pointer; MetaRec : Pointer; Count : word; dummy : pointer) : shortint stdcall;
var
aStr : string;
Ofs : integer;
Len : integer;
I : integer;
begin
aStr := '';
with tagENHMETARECORD(MetaRec^) do
begin
case iType of
EMR_EXTTEXTOUTW,
EMR_EXTTEXTOUTA : begin
aStr := '';
Ofs := (tagEMREXTTEXTOUTA(Metarec^).EMRText.offString);
Len := (tagEMREXTTEXTOUTA(Metarec^).EMRText.nChars);
SetLength(aStr, Len);
for I := 0 to len - 1 do
// aStr[I+1] := char(MFBar(MetaRec^)[ofs + (I*2)]);
aStr[I+1] := MFBar(MetaRec)[ofs + (I*2)];
Showmessage(aStr);
end;
end;
end;
if not MFMatchCase then aStr := AnsiUppercase(AStr);
if Pos(MFSearchStr, aStr) > 0 then
begin
Result := 0;
MFFound := true;
end else
Result := 1;
end;
function StrInMetafile(AString : string; AMetafile : TMetafile; MatchCase : boolean) : boolean;
begin
while MFSearchBusy do Application.ProcessMessages;
MFSearchBusy := true;
if MatchCase then
MFSearchStr := AString
else
MFSearchStr := AnsiUppercase(AString);
MFFound := false;
MFMatchCase := MatchCase;
EnumEnhMetafile(0, AMetafile.handle, @MetaEnum, nil, rect(0,0,0,0));
Result := MFFound;
MFSearchBusy := false;
end;
----------------------------------------------
qrprntr unit에서
type
bar = array of Char;
var
MFSearchStr : string;
MFFound : boolean;
MFMatchCase : boolean;
function MetaEnum(DC : THandle; HandleTable : pointer; MetaRec : Pointer; Count : word; dummy : pointer) : shortint stdcall;
var
aStr : string;
Ofs : integer;
Len : integer;
I : integer;
begin
with tagENHMETARECORD(MetaRec^) do
begin
case iType of
EMR_EXTTEXTOUTW,
EMR_EXTTEXTOUTA : begin
aStr := '';
Ofs := (tagEMREXTTEXTOUTA(Metarec^).EMRText.offString);
Len := (tagEMREXTTEXTOUTA(Metarec^).EMRText.nChars);
SetLength(aStr, Len);
for I := 0 to len - 1 do
aStr[I+1] := char(bar(MetaRec^)[ofs + (I*2)]);
end;
end;
end;
if not MFMatchCase then aStr := AnsiUppercase(AStr);
if Pos(MFSearchStr, aStr) > 0 then
begin
Result := 0;
MFFound := true;
end else
Result := 1;
end;
function StrInMetafile(AString : string; AMetafile : TMetafile; MatchCase : boolean) : boolean;
begin
if MatchCase then
MFSearchStr := AString
else
MFSearchStr := AnsiUppercase(AString);
MFFound := false;
MFMatchCase := MatchCase;
EnumEnhMetafile(0, AMetafile.handle, @MetaEnum, nil, rect(0,0,0,0));
Result := MFFound;
end;
-----------------------------------------------------------------------
기타 windows 유닛에서
PEnhMetaRecord = ^TEnhMetaRecord;
{$EXTERNALSYM tagENHMETARECORD}
tagENHMETARECORD = packed record
iType: DWORD; { Record type EMR_XXX}
nSize: DWORD; { Record size in bytes}
dParm: array[0..0] of DWORD; { Parameters}
end;
TEnhMetaRecord = tagENHMETARECORD;
{$EXTERNALSYM ENHMETARECORD}
ENHMETARECORD = tagENHMETARECORD;
{$EXTERNALSYM EMR_EXTTEXTOUTA}
EMR_EXTTEXTOUTA = 83;
{$EXTERNALSYM EMR_EXTTEXTOUTW}
EMR_EXTTEXTOUTW = 84;
{$EXTERNALSYM tagEMREXTTEXTOUTA}
tagEMREXTTEXTOUTA = packed record
emr: TEMR;
rclBounds: TRect; { Inclusive-inclusive bounds in device units}
iGraphicsMode: DWORD; { Current graphics mode}
exScale: Single; { X and Y scales from Page units to .01mm units}
eyScale: Single; { if graphics mode is GM_COMPATIBLE.}
emrtext: TEMRText; { This is followed by the string and spacing array}
end;
TEMRExtTextOut = tagEMREXTTEXTOUTA;
{$EXTERNALSYM EMREXTTEXTOUTA}
EMREXTTEXTOUTA = tagEMREXTTEXTOUTA;
{ Base text record type for the enhanced metafile.}
PEMRText = ^TEMRText;
{$EXTERNALSYM tagEMRTEXT}
tagEMRTEXT = packed record
ptlReference: TPoint;
nChars: DWORD;
offString: DWORD; { Offset to the string}
fOptions: DWORD;
rcl: TRect;
offDx: DWORD; { Offset to the inter-character spacing array.}
{ This is always given.}
end;
TEMRText = tagEMRTEXT;
{$EXTERNALSYM EMRTEXT}
EMRTEXT = tagEMRTEXT;
{$EXTERNALSYM tagEMR}
tagEMR = packed record
iType: DWORD; { Enhanced metafile record type}
nSize: DWORD; { Length of the record in bytes.}
{ This must be a multiple of 4.}
end;
TEMR = tagEMR;
{$EXTERNALSYM EMR}
EMR = tagEMR;
|