Thanks Kevin.kcarmody wrote: I will put together a posting like this with my changes. There are several dozen changes, so it will be a big posting and will take a while to put together.
RichEditBox handling of Unicode text files now fixed
Moderator: Rathinagiri
- srvet_claudio
- Posts: 2193
- Joined: Thu Feb 25, 2010 8:43 pm
- Location: Uruguay
- Contact:
Re: RichEditBox handling of Unicode text files now fixed
Re: RichEditBox handling of Unicode text files now fixed
I'm submitting the following changes, all relating to the RichEditBox control. I've developed a patch, based on Claudio's current patch (patch 3), which incorporates these changes. This patch should be installed on top of Claudio's patch.
Individual modified source files are at http://kevincarmody.com/hmg/, and a zip of files in the patch is at http://kevincarmody.com/hmg/HMG.zip.
This patch also includes an overhauled Rich Edit demo, which uses all the source code changes (except for the SelPasteSpecial method). The new Rich Edit demo is at http://kevincarmody.com/hmg/SAMPLES/Con ... chEditBox/.
New manifest constants RTFTXTFILE_ANSI etc.
These constants are RTF and TXT file types returned by the new function GetRtfTxtFileType() and can be used by the RtfTxtLoadFile and RtfTxtSaveFile methods of the RichEditBox control.
http://kevincarmody.com/hmg/INCLUDE/i_richeditbox.ch - lines 159-169
Code: Select all
// Following 5 #defines added by Kevin Carmody, November 2014
*****************
* File type *
*****************
#define RTFTXTFILE_ANSI 1 // ANSI text file
#define RTFTXTFILE_UTF8 2 // UTF-8 text file
#define RTFTXTFILE_UTF16LE 3 // UTF-16 LE (little endian) text file
#define RTFTXTFILE_RTF 4 // RTF file
#define RTFTXTFILE_UTF16BE 5 // UTF-16 BE (big endian) text file
New function GetRtfTxtFileType( cFile, lUtf8Test ) --> nFileType
This function returns a file type (RTF, ANSI, UTF-16, UTF-8) which can be used in RtfTxtLoadFile and RtfTxtSaveFile methods of RichEditBox control.
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 508-576
Code: Select all
// Following function added by Kevin Carmody, November 2014
*-----------------------------------------------------------------------------*
FUNCTION GetRtfTxtFileType ( cFile, lUtf8Test )
*-----------------------------------------------------------------------------*
LOCAL hFile := FOPEN( cFile, FO_READ )
LOCAL cBuffer := SPACE( 5 )
LOCAL nBufRead := 0
LOCAL nType := 0
/*
The following code block tests for the presence of non-ASCII characters in
an unmarked text file. It assumes that such characters may be ANSI or
parts of UTF-8 sequences. In UTF-8 mode, Windows reads bytes which are not
part of a valid UTF-8 sequence as ANSI. It would be better to know if the
file contained UTF-8 sequences for non-ANSI characters, but since some ANSI
characters are not in the Latin-1 Supplement, testing for non-ANSI UTF-8
sequences is inefficient for large files.
*/
LOCAL bHasUnicodeChars := {||
LOCAL lHasUnicode := .N.
LOCAL cChar, cStr
cBuffer := SPACE( 0x400 )
nBufRead := 1
BEGIN SEQUENCE
WHILE nBufRead > 0
nBufRead := FREAD( hFile, @cBuffer, 0x400 )
IF nBufRead > 0
cStr := LEFT( cBuffer, nBufRead )
FOR EACH cChar IN cStr
IF cChar >= CHR(0x80)
lHasUnicode := .Y.
BREAK
ENDIF
NEXT
ENDIF
ENDDO
END SEQUENCE
RETURN lHasUnicode
}
BEGIN SEQUENCE
IF hFile < 0
BREAK
ENDIF
nBufRead := FREAD( hFile, @cBuffer, 5 )
DO CASE
CASE nBufRead >= 5 .AND. LEFT( cBuffer, 5 ) == "{\rtf"
nType := RTFTXTFILE_RTF
CASE nBufRead >= 3 .AND. LEFT( cBuffer, 3 ) == E"\xEF\xBB\xBF"
nType := RTFTXTFILE_UTF8
CASE nBufRead >= 2 .AND. LEFT( cBuffer, 2 ) == E"\xFF\xFE"
nType := RTFTXTFILE_UTF16LE
CASE nBufRead >= 2 .AND. LEFT( cBuffer, 2 ) == E"\xFE\xFF"
nType := RTFTXTFILE_UTF16BE
CASE ! EMPTY( lUtf8Test ) .AND. bHasUnicodeChars:EVAL( )
nType := RTFTXTFILE_UTF8
OTHERWISE
nType := RTFTXTFILE_ANSI
ENDCASE
END SEQUENCE
FCLOSE( hFile )
RETURN nType
Code: Select all
LOCAL nFormat := GETRTFTXTFILETYPE( cFileName, .Y. )
This function supports the UTF-16 BE (big endian) file type for the RtfTxtLoadFile and RtfTxtSaveFile methods of RichEditBox control.
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 579-621
Code: Select all
// Following function added by Kevin Carmody, November 2014
*-----------------------------------------------------------------------------*
FUNCTION Utf16ByteSwap( cInFile, cOutFile )
*-----------------------------------------------------------------------------*
LOCAL hInFile := FOPEN( cInFile , FO_READ )
LOCAL hOutFile := FCREATE( cOutFile )
LOCAL cInBuffer := SPACE( 0x400 )
LOCAL nBufRead := 1
LOCAL lSuccess := .N.
LOCAL cOutBuffer, cBytePair, nBufWrite, nByte
BEGIN SEQUENCE
IF hInFile < 0
BREAK
ENDIF
IF hOutFile < 0
BREAK
ENDIF
WHILE nBufRead > 0
cOutBuffer := ""
nBufRead := FREAD( hInFile, @cInBuffer, 0x400 )
IF nBufRead > 0
FOR nByte := 1 TO nBufRead STEP 2
cBytePair := SUBSTR( cInBuffer, nByte, 2 )
cOutBuffer += RIGHT( cBytePair, 1 ) + LEFT( cBytePair, 1 )
NEXT
nBufWrite := FWRITE( hOutFile, cOutBuffer )
IF nBufWrite < nBufRead
BREAK
ENDIF
ENDIF
ENDDO
lSuccess := .Y.
END SEQUENCE
FCLOSE( hInFile )
FCLOSE( hOutFile )
RETURN lSuccess
Fixed RichEditBox_StreamIn( hWndControl, cFileName, lSelection, nDataFormat ) --> lSuccess
This function now skips over a byte order mark (BOM) in a Unicode text file if one is present.
http://kevincarmody.com/hmg/SOURCE/c_richeditbox.c - lines 226-291
Code: Select all
// RichEditBox_StreamIn ( hWndControl, cFileName, lSelection, nDataFormat ) --> return lSuccess
HB_FUNC ( RICHEDITBOX_STREAMIN )
{
HWND hWndControl = (HWND) HMG_parnl (1);
TCHAR *cFileName = (TCHAR*) HMG_parc (2);
BOOL lSelection = (BOOL) hb_parl (3);
LONG nDataFormat = (LONG) hb_parnl (4);
HANDLE hFile;
// Following 3 lines added by Kevin Carmody, November 2014
BYTE bUtf8Bom[3];
BYTE bUtf16Bom[2];
DWORD dwRead;
EDITSTREAM es;
LONG Format;
switch( nDataFormat )
{
// Comments in this switch block modified by Kevin Carmody, November 2014
case 1: Format = SF_TEXT; break; // ANSI or UTF-8 with BOM or mixed (UTF-8 BOM removed, overlong UTF-8 accepted, invalid UTF-8 read as ANSI)
case 2: Format = ( CP_UTF8 << 16 ) | SF_USECODEPAGE | SF_TEXT; break; // UTF-8 without BOM (BOM not removed)
case 3: Format = SF_TEXT | SF_UNICODE; break; // UTF-16 LE without BOM (BOM not removed)
case 4: Format = SF_RTF; break;
// case 5, UTF-8 RTF, removed by Kevin Carmody, November 2014, because it can never occur
default: Format = SF_RTF; break;
}
if ( lSelection )
Format = Format | SFF_SELECTION;
if( ( hFile = CreateFile (cFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL )) == INVALID_HANDLE_VALUE )
{ hb_retl (FALSE);
return;
}
// Following switch block added by Kevin Carmody, November 2014
switch( nDataFormat )
{
case 1: break;
case 2:
if ( ! ReadFile (hFile, bUtf8Bom, 3, &dwRead, NULL) ) // read past BOM if present
hb_retl (FALSE);
if ( ! ( dwRead == 3 && bUtf8Bom[0] == 0xEF && bUtf8Bom[1] == 0xBB && bUtf8Bom[2] == 0xBF ) )
SetFilePointer (hFile, 0, 0, FILE_BEGIN);
break;
case 3:
if ( ! ReadFile (hFile, bUtf16Bom, 2, &dwRead, NULL) ) // read past BOM if present
hb_retl (FALSE);
if ( ! ( dwRead == 2 && bUtf16Bom[0] == 0xFF && bUtf16Bom[1] == 0xFE ) )
SetFilePointer (hFile, 0, 0, FILE_BEGIN);
break;
case 4: break;
default: break;
}
es.pfnCallback = EditStreamCallbackRead;
es.dwCookie = (DWORD_PTR) hFile;
es.dwError = 0;
SendMessage ( hWndControl, EM_STREAMIN, (WPARAM) Format, (LPARAM) &es );
CloseHandle (hFile);
if( es.dwError )
hb_retl (FALSE);
else
hb_retl (TRUE);
}
Fixed RichEditBox_StreamOut( hWndControl, cFileName, lSelection, nDataFormat ) --> lSuccess
This function now writes a byte order mark (BOM) to a Unicode text file.
http://kevincarmody.com/hmg/SOURCE/c_richeditbox.c - lines 305-360
Code: Select all
// RichEditBox_StreamOut ( hWndControl, cFileName, lSelection, nDataFormat ) --> return lSuccess
HB_FUNC ( RICHEDITBOX_STREAMOUT )
{
HWND hWndControl = (HWND) HMG_parnl (1);
TCHAR *cFileName = (TCHAR*) HMG_parc (2);
BOOL lSelection = (BOOL) hb_parl (3);
LONG nDataFormat = (LONG) hb_parnl (4);
HANDLE hFile;
// Following 3 lines added by Kevin Carmody, November 2014
BYTE bUtf8Bom[3] = {0xEF, 0xBB, 0xBF};
BYTE bUtf16Bom[2] = {0xFF, 0xFE};
DWORD dwWritten;
EDITSTREAM es;
LONG Format;
switch( nDataFormat )
{
// Comments in this switch block modified by Kevin Carmody, November 2014
case 1: Format = SF_TEXT; break; // ANSI (non-ANSI characters converted to question marks)
case 2: Format = ( CP_UTF8 << 16 ) | SF_USECODEPAGE | SF_TEXT; break; // UTF-8 without BOM
case 3: Format = SF_TEXT | SF_UNICODE; break; // UTF-16 LE without BOM
case 4: Format = SF_RTF; break;
// case 5, UTF-8 RTF, removed by Kevin Carmody, November 2014, because it can never occur
default: Format = SF_RTF; break;
}
if ( lSelection )
Format = Format | SFF_SELECTION;
if( ( hFile = CreateFile (cFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE )
{ hb_retl (FALSE);
return;
}
// Following switch block added by Kevin Carmody, November 2014
switch( nDataFormat )
{
case 1: break;
case 2: WriteFile( hFile, bUtf8Bom, 3, &dwWritten, NULL ); break; // write UTF-8 BOM at head of file
case 3: WriteFile( hFile, bUtf16Bom, 2, &dwWritten, NULL ); break; // write UTF-16 LE BOM at head of file
case 4: break;
default: break;
}
es.pfnCallback = EditStreamCallbackWrite;
es.dwCookie = (DWORD_PTR) hFile;
es.dwError = 0;
SendMessage ( hWndControl, EM_STREAMOUT, (WPARAM) Format, (LPARAM) &es );
CloseHandle (hFile);
if( es.dwError )
hb_retl (FALSE);
else
hb_retl (TRUE);
}
New RichEditBox property HasUnicodeChars (read only)
This property detects whether a rich edit control contains non-ASCII Unicode characters.
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9293-9296, at end of _RichEditBox_GetProperty()
Code: Select all
// Following case added by Kevin Carmody, November 2014
CASE Arg3 == "HASUNICODECHARS"
xData := RichEditBox_HasUnicodeChars ( hWndControl )
RetVal := .T.
Code: Select all
;; // Following line modified by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFTextMode,AutoURLDetect,Zoom,SelectRange,CaretPos,Value,GetSelectText,GetTextLength,ViewRect,HasUnicodeChars\> => GetProperty ( <"w">, \<"c"\> , \<"p"\> ) ;;
Code: Select all
// Following function added by Kevin Carmody, November 2014
/*
The following function tests for the presence of non-ASCII characters in
a rich edit control. It would be better to know if the control contained
non-ANSI characters, but since some ANSI characters are not in the Latin-1
Supplement, testing for non-ANSI characters is inefficient for large
documents.
*/
*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_HasUnicodeChars( hWndControl )
*-----------------------------------------------------------------------------*
LOCAL cBuffer := RichEditBox_GetText( hWndControl , .N. )
LOCAL lHasUnicode := .N.
LOCAL cChar
FOR EACH cChar IN cBuffer
IF cChar >= CHR(0x80)
lHasUnicode := .Y.
ENDIF
NEXT
RETURN lHasUnicode
Code: Select all
LOCAL lUnicode := wMain.ebDoc.HASUNICODECHARS
This method is a synonym for the RtfLoadFile method. It now uses the file type returned by GetRtfTxtFileType(). It skips over a byte order mark in a Unicode text file, and it supports UTF-16 BE (big endian Unicode text file).
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9467-9470
Code: Select all
// Following case modified by Kevin Carmody, November 2014
CASE Arg3 == "RTFLOADFILE" .OR. Arg3 == "RTFTXTLOADFILE"
xData := RichEditBox_RtfTxtLoadFile ( hWndControl, Arg4, Arg5, Arg6 ) // by default save in SF_RTF format
RetVal := .T.
Code: Select all
;; // Following 2 lines modified by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
Code: Select all
// Following function added by Kevin Carmody, November 2014
*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_RtfTxtLoadFile( hWndControl, cFile, lSelection, nType )
*-----------------------------------------------------------------------------*
LOCAL lSuccess := .N.
LOCAL cTempFile
IF ! HB_ISLOGICAL( lSelection )
lSelection := .N.
ENDIF
IF ! HB_ISNUMERIC( nType )
nType := RTFTXTFILE_RTF
ENDIF
IF lSelection
RichEditBox_UnSelectAll( hWndControl )
ENDIF
IF RichEditBox_RTFLoadResourceFile( hWndControl, cFile, lSelection )
lSuccess := .T.
ELSE
IF nType == RTFTXTFILE_UTF16BE
cTempFile := GETTEMPFOLDER() + "_RtfTxtLoadFile.txt"
lSuccess := Utf16ByteSwap( cFile, cTempFile )
IF lSuccess
lSuccess := RichEditBox_StreamIn( hWndControl, cTempFile, lSelection, RTFTXTFILE_UTF16LE )
ENDIF
DELETE FILE ( cTempFile )
ELSE
lSuccess := RichEditBox_StreamIn( hWndControl, cFile, lSelection, nType )
ENDIF
ENDIF
RETURN lSuccess
Code: Select all
IF ! wMain.ebDoc.RTFTXTLOADFILE( cFileName, .N., nFormat )
This method is a synonym for the RtfSaveFile method. It now uses the file type returned by GetRtfTxtFileType(), writes a byte order mark to a Unicode text file, and supports UTF-16 BE (big endian Unicode text file).
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9472-9475
Code: Select all
// Following case modified by Kevin Carmody, November 2014
CASE Arg3 == "RTFSAVEFILE" .OR. Arg3 == "RTFTXTSAVEFILE"
xData := RichEditBox_RtfTxtSaveFile ( hWndControl, Arg4, Arg5, Arg6 ) // by default save in SF_RTF format
RetVal := .T.
Code: Select all
;; // Following 2 lines modified by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
Code: Select all
// Following function added by Kevin Carmody, November 2014
*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_RtfTxtSaveFile( hWndControl, cFile, lSelection, nType )
*-----------------------------------------------------------------------------*
LOCAL lSuccess := .N.
LOCAL cTempFile
IF ! HB_ISLOGICAL( lSelection )
lSelection := .N.
ENDIF
IF ! HB_ISNUMERIC( nType )
nType := RTFTXTFILE_RTF
ENDIF
IF nType == RTFTXTFILE_UTF16BE
cTempFile := GETTEMPFOLDER() + "_RtfTxtLoadFile.txt"
lSuccess := RichEditBox_StreamOut( hWndControl, cTempFile, lSelection, RTFTXTFILE_UTF16LE )
IF lSuccess
lSuccess := Utf16ByteSwap( cTempFile, cFile )
ENDIF
DELETE FILE ( cTempFile )
ELSE
lSuccess := RichEditBox_StreamOut( hWndControl, cFile, lSelection, nType )
ENDIF
RETURN lSuccess
Code: Select all
IF ! wMain.ebDoc.RTFTXTSAVEFILE( cFileName, .N., nFormat )
Paste special - needs documentation of clipboard format argument.
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9485-9488
Code: Select all
// Following case added by Kevin Carmody, November 2014
CASE Arg3 == HMG_UPPER ("SelPasteSpecial")
RichEditBox_PasteSpecial ( hWndControl, Arg4 )
RetVal := .T.
Code: Select all
;; // Following line added by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:SelPasteSpecial\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
Enhanced RichEditBox method RtfLoadFile( cFile, lSelection, nType ) --> lSuccess
This method is a synonym for the RtfTxtLoadFile method described above.
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9467-9470
Code: Select all
// Following case modified by Kevin Carmody, November 2014
CASE Arg3 == "RTFLOADFILE" .OR. Arg3 == "RTFTXTLOADFILE"
xData := RichEditBox_RtfTxtLoadFile ( hWndControl, Arg4, Arg5, Arg6 ) // by default save in SF_RTF format
RetVal := .T.
Code: Select all
;; // Following 2 lines modified by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
Enhanced RichEditBox method RtfSaveFile( cFile, lSelection, nType ) --> lSuccess
This method is a synonym for the RtfTxtSaveFile method described above.
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 9472-9475
Code: Select all
// Following case modified by Kevin Carmody, November 2014
CASE Arg3 == "RTFSAVEFILE" .OR. Arg3 == "RTFTXTSAVEFILE"
xData := RichEditBox_RtfTxtSaveFile ( hWndControl, Arg4, Arg5, Arg6 ) // by default save in SF_RTF format
RetVal := .T.
Code: Select all
// Following 2 lines modified by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
// Following line added by Kevin Carmody, November 2014
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RtfTxtLoadFile,RtfTxtSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
Enhanced function GetFile( [aFilter], [cTitle], [cIniFolder], [lMultiSelect], [lNoChangeDir], [nFilterIndex] ) --> cFileName | aFileNames
Added nFilterInddex argument to control the default file filter. See viewtopic.php?f=8&t=4009
http://kevincarmody.com/hmg/SOURCE/c_dialogs.c - lines 173-174, 188-190, 221-222
Code: Select all
HB_FUNC ( C_GETFILE )
{
#define _MAXMULTISELECTFILE 1024
OPENFILENAME ofn;
TCHAR buffer [ _MAXMULTISELECTFILE * MAX_PATH ];
TCHAR cFullName [ _MAXMULTISELECTFILE ] [ MAX_PATH ];
TCHAR cCurDir [ MAX_PATH ];
TCHAR cFileName [ MAX_PATH ];
// Following line added by Kevin Carmody, November 2014
int iFilterIndex = 1;
int iPosition = 0;
int iNumSelected = 0;
int flags = OFN_FILEMUSTEXIST | OFN_EXPLORER;
memset ((void*)&buffer, 0, sizeof(buffer));
if ( hb_parl(4) )
flags = flags | OFN_ALLOWMULTISELECT ;
if ( hb_parl(5) )
flags = flags | OFN_NOCHANGEDIR ;
// Following if statement added by Kevin Carmody, November 2014
if ( hb_parni(6) )
iFilterIndex = hb_parni(6) ;
//******************************************************************************************************//
// ofn.lpstrFilter = A buffer containing pairs of null-terminated filter strings.
// The last string in the buffer must be terminated by two NULL characters.
// The following code converts a ANSI (CHAR) filter string into a UNICODE (UNSIGNED INT) filter string
#define _MAX_FILTER 5*1024
INT i, j=0, cont=0;
CHAR *p = (CHAR*) hb_parc(1);
TCHAR Filter [ _MAX_FILTER ];
memset((void*) &Filter, 0, sizeof(Filter));
for (i=0; *p != '\0'; i++)
{ cont = cont + strlen (p) + 1;
if (cont < _MAX_FILTER)
{ lstrcpy ( &Filter[j], HMG_CHAR_TO_WCHAR(p) );
j = j + lstrlen ( HMG_CHAR_TO_WCHAR (p) ) + 1;
p = p + strlen (p) + 1;
}
else
break;
}
//**********************************************************************//
memset( (void*) &ofn, 0, sizeof( OPENFILENAME ) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = GetActiveWindow();
ofn.lpstrFilter = (LPCTSTR) &Filter;
// Following statement modified by Kevin Carmody, November 2014
ofn.nFilterIndex = (DWORD) iFilterIndex;
ofn.lpstrFile = (LPTSTR) &buffer;
ofn.nMaxFile = sizeof(buffer) / sizeof(TCHAR);
ofn.lpstrInitialDir = (LPCTSTR) HMG_parc(3);
ofn.lpstrTitle = (LPCTSTR) HMG_parc(2);
ofn.Flags = flags;
if( GetOpenFileName (&ofn) )
{
if ( ofn.nFileExtension !=0 )
HMG_retc (ofn.lpstrFile);
else
{
wsprintf ( cCurDir, _TEXT("%s"), &buffer [iPosition] );
iPosition = iPosition + lstrlen (cCurDir) + 1;
do
{
iNumSelected ++;
wsprintf ( cFileName, _TEXT("%s"), &buffer [iPosition] );
iPosition = iPosition + lstrlen (cFileName) + 1;
wsprintf ( cFullName [iNumSelected], _TEXT("%s\\%s"), cCurDir, cFileName);
}
while (( lstrlen(cFileName) !=0 ) && ( iNumSelected < _MAXMULTISELECTFILE ));
if (iNumSelected > 1)
{
hb_reta (iNumSelected - 1);
for (i = 1; i < iNumSelected; i++)
HMG_storvc (cFullName[i], -1, i );
}
else
HMG_retc( &buffer[0] );
}
}
else
HMG_retc( _TEXT("") );
}
Code: Select all
*-----------------------------------------------------------------------------*
// Following line modified by Kevin Carmody, November 2014
Function GetFile( aFilter, title, cIniFolder, multiselect, nochangedir, nFilterIndex )
*-----------------------------------------------------------------------------*
local c := ''
local cfiles := ''
local fileslist := {}
local n
Local i
IF aFilter == Nil
aFilter := {}
EndIf
IF title == NIL
title := ""
ENDIF
IF cIniFolder == NIL
cIniFolder := ""
ENDIF
FOR n:=1 TO HMG_LEN(aFilter)
c := c + aFilter[n][1] + CHR(0) + aFilter[n][2] + CHR(0)
NEXT
c := c + CHR(0)
if valtype(multiselect) == 'U'
multiselect := .f.
endif
// Following if block added by Kevin Carmody, November 2014
if nFilterIndex == NIL
nFilterIndex := 1
endif
if .not. multiselect
// Following line modified by Kevin Carmody, November 2014
Return ( C_GetFile ( c , title, cIniFolder, multiselect, nochangedir, nFilterIndex ) )
else
// Following line modified by Kevin Carmody, November 2014
cfiles := C_GetFile ( c , title, cIniFolder, multiselect, nochangedir, nFilterIndex )
if HMG_LEN( cfiles ) > 0
if valtype( cfiles ) == "A"
fileslist := aclone( cfiles )
else
aadd( fileslist, cfiles )
endif
endif
For i := 1 To HMG_LEN ( FilesList)
FilesList [i] := HB_UTF8STRTRAN ( FilesList [i] , "\\" , "\" )
Next i
Return ( FilesList )
endif
Return Nil
Code: Select all
cAuxFileName := GETFILE( aReadFilter, 'Open', cFileFolder, NIL, NIL, nReadFilter )
Added nFilterInddex argument to control the default file filter. If passed by reference, nFilterIndex returns the index of file filter selected by user. See viewtopic.php?f=8&t=4009
http://kevincarmody.com/hmg/SOURCE/c_dialogs.c - lines 268-269, 276-280, 311-312, 327-331
Code: Select all
HB_FUNC ( C_PUTFILE )
{
OPENFILENAME ofn;
TCHAR buffer[1024];
// Following line added by Kevin Carmody, November 2014
int iFilterIndex = 1;
int flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER ;
if ( hb_parl(4) )
{
flags = flags | OFN_NOCHANGEDIR ;
}
// Following if statement added by Kevin Carmody, November 2014
if ( hb_parni(7) )
{
iFilterIndex = hb_parni(7) ;
}
//******************************************************************************************************//
// ofn.lpstrFilter = A buffer containing pairs of null-terminated filter strings.
// The last string in the buffer must be terminated by two NULL characters.
// The following code converts a ANSI (CHAR) filter string into a UNICODE (UNSIGNED INT) filter string
#define _MAX_FILTER 5*1024
INT i, j=0, cont=0;
CHAR *p = (CHAR*) hb_parc(1);
TCHAR Filter [_MAX_FILTER];
memset((void*) &Filter, 0, sizeof(Filter));
for (i=0; *p != '\0'; i++)
{ cont = cont + strlen (p) + 1;
if (cont < _MAX_FILTER)
{ lstrcpy ( &Filter[j], HMG_CHAR_TO_WCHAR (p) );
j = j + lstrlen ( HMG_CHAR_TO_WCHAR (p) ) + 1;
p = p + strlen (p) + 1;
}
else
break;
}
//**********************************************************************//
lstrcpy (buffer, HMG_parc(5));
memset( (void*) &ofn, 0, sizeof( OPENFILENAME ) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = GetActiveWindow() ;
ofn.lpstrFilter = (LPCTSTR) &Filter;
// Following statement modified by Kevin Carmody, November 2014
ofn.nFilterIndex = (DWORD) iFilterIndex;
ofn.lpstrFile = (LPTSTR) &buffer;
ofn.nMaxFile = sizeof(buffer) / sizeof(TCHAR);
ofn.lpstrInitialDir = (LPCTSTR) HMG_parc(3);
ofn.lpstrTitle = (LPCTSTR) HMG_parc(2);
ofn.Flags = flags;
ofn.lpstrDefExt = (LPCTSTR) HMG_parc(6);
if ( GetSaveFileName (&ofn) )
{ if (HB_ISBYREF(6))
{ if (ofn.nFileExtension > ofn.nFileOffset)
HMG_storc (&ofn.lpstrFile [ofn.nFileExtension], 6);
else
HMG_storc (_TEXT(""), 6);
}
// Following if statement added by Kevin Carmody, November 2014
if (HB_ISBYREF(7))
{
hb_stornl ((LONG) ofn.nFilterIndex, 7);
}
HMG_retc(ofn.lpstrFile);
}
else
HMG_retc( _TEXT("") );
}
Code: Select all
*--------------------------------------------------------------------------------------------*
// Following line modified by Kevin Carmody, November 2014
Function Putfile ( aFilter, cTitle, cIniFolder, lNoChangeDir, cDefaultFileName, cExtFile, nFilterIndex )
*--------------------------------------------------------------------------------------------*
LOCAL cFilter:='' , n, cFileName
IF aFilter == Nil
aFilter:={}
EndIf
IF cTitle == NIL
cTitle := ""
ENDIF
IF cIniFolder == NIL
cIniFolder := ""
ENDIF
IF cDefaultFileName == NIL
cDefaultFileName := ""
ENDIF
// Following if block added by Kevin Carmody, November 2014
IF nFilterIndex == NIL
nFilterIndex := 1
ENDIF
FOR n := 1 TO HMG_LEN ( aFilter )
cFilter = cFilter + aFilter [n] [1] + CHR(0) + aFilter [n] [2] + CHR(0)
NEXT
cFilter := cFilter + CHR(0)
// Following line modified by Kevin Carmody, November 2014
cFileName := C_PutFile ( cFilter, cTitle, cIniFolder, lNoChangeDir, cDefaultFileName, @cExtFile, @nFilterIndex )
Return cFileName
Code: Select all
cAuxFileName := PUTFILE( aWriteFilter, 'Save As', cFileFolder, ;
NIL, cFileName, @cFileExt, @nWriteFilter )
Enabled this function to return a value from a RichEditBox method.
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 7943-7944
Code: Select all
Function DoMethod ( Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 )
// Following line modified by Kevin Carmody, November 2014
Local xData, i, hWnd
Code: Select all
// Following 2 lines modified by Kevin Carmody, November 2014
IF _RichEditBox_DoMethod ( @xData, Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 ) == .T.
Return xData
ENDIF
Code: Select all
// Following line modified by Kevin Carmody, November 2014
Function _RichEditBox_DoMethod ( xData, Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 )
Code: Select all
IF ! wMain.ebDoc.RTFTXTLOADFILE( cFileName, .N., nFormat )
Code: Select all
IF ! wMain.ebDoc.RTFTXTSAVEFILE( cFileName, .N., nFormat )
- srvet_claudio
- Posts: 2193
- Joined: Thu Feb 25, 2010 8:43 pm
- Location: Uruguay
- Contact:
Re: RichEditBox handling of Unicode text files now fixed
Many of these changes will be for the next version because HMG.3.3.2 now is ready.
Re: RichEditBox handling of Unicode text files now fixed
Eagerly waiting for new versionsrvet_claudio wrote:Thanks Kevin.
Many of these changes will be for the next version because HMG.3.3.2 now is ready.
Great work done by Mr. Kevin in a very short period, Thank you for your contribution
Convert Dream into Reality through HMG
- serge_girard
- Posts: 3167
- Joined: Sun Nov 25, 2012 2:44 pm
- DBs Used: 1 MySQL - MariaDB
2 DBF - Location: Belgium
- Contact:
Re: RichEditBox handling of Unicode text files now fixed
Question: any idea about a function for converting to HTML...?
That would be so great!
Serge
Re: RichEditBox handling of Unicode text files now fixed
Some years ago I wrote a Harbour library called UnicodeLib that has functions for converting between ANSI, Unicode, RTF, and HTML. Some of these functions now have equivalents in Harbour, but I don't think the HTML conversions do. You can download UnicodeLib from http://kevincarmody.com/software/akshar ... unicodelib.serge_girard wrote:Question: any idea about a function for converting to HTML...?
That would be so great!
Kevin
- serge_girard
- Posts: 3167
- Joined: Sun Nov 25, 2012 2:44 pm
- DBs Used: 1 MySQL - MariaDB
2 DBF - Location: Belgium
- Contact:
Re: RichEditBox handling of Unicode text files now fixed
Serge