Today I finished the component to parse the e-books in .epub format:
http://en.wikipedia.org/wiki/Epub
I added this parser in SMWord suite Also I added this file format to Fast Document Viewer and ABA DocConvert
Today I finished the component to parse the e-books in .epub format:
http://en.wikipedia.org/wiki/Epub
I added this parser in SMWord suite Also I added this file format to Fast Document Viewer and ABA DocConvert
Yesterday I changed the default error dialog in SMLog suite

The format of log file now is text or XML (see the new Formatting property)
Also a few minor bugs fixed (list of all graphic adapters, computer name in Windows XP etc)
Today I added the new feature for TSMExportToHTML component – the possibility to generate the html file with embedded images. Unfortunately the old IE (5/6) do not support this feature but FireFox, Opera, Safari will open the file without any problem
A few links:
http://www.sweeting.org/mark/blog/2005/07/12/base64-encoded-images-embedded-in-html
http://rifers.org/blogs/gbevin/2005/4/11/embedding_images_inside_html
Note: large images will not displayed due some limits in browser for encoded string
function GetFormattedNumber(Value: Double): string;
function GetLastPos(const s: string): Integer;
begin
Result := Pos(DecimalSeparator, s)-1;
if (Result < 1) then
Result := Length(s)
end;
var
i: Integer;
begin
Result := FloatToStr(Value);
i := 3;
while (i < GetLastPos(Result)) do
begin
Insert(' ', Result, GetLastPos(Result)-i+1);
Inc(i, 4)
end;
end;
Sample to use:
lblTotal.Caption := GetFormattedNumber(123456.789);
Why I wrote this function? In Delphi I could use the FormatFloat(‘,###’, dbl) but FormatFloat uses the thousand separator which is defined in MS Windows (#160 by default). I need the space char always
In SMExport I added the new component to support the JavaScript Object Notation
The format of generated samples are available at http://www.json.org/example.html
For example:
{
“RECORD”: {
“Species No”: 90020
“Category”: “Fish”
“Common_Name”: “CommonFish 828”
“Species Name”: “Fish 275”
“Length (cm)”: 50
“Length_In”: 19,6850393700787
}
}
The dates encoded as the number of milliseconds since January 1st 1970. See the topic for this subject at
http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx
The binary values encoded in Base64 (same as in xml)
Added the new Actions property where developer have the control which options to enable/disable for end-user.
For example, exclude the saEditRelation flag and user could not edit the options of relation/link.
Or add the saDeleteItem flag to allow the delete the table/item in designer area
Created the new TAction for export support. Will be included in next SMExport
A few years ago Jens from OraTool.de wrote the dataengine component for cxGrid and I deployed this component as part of SMExport
But Developer Express also have the TcxTreeList and TcxDBTreeList components. In friday I wrote the dataengines for these components:
In Friday in our SIM (Shareware Information System) I added the possibility to drag’n’drop the mail content from external mailer (MS Outlook, Outlook Express etc)
To add this feature you need:
1. declare two new Cliboard formats that need to be registered:
var
CF_FILECONTENTS,
CF_FILEDESCRIPTOR: Integer;initialization
// Initialize the OLE libraries
OleInitialize(nil);
// Register the clipboard formats that we need to handle in the
// OLE drag drop operation
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
CF_FILEDESCRIPTOR := RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
finalization
OleUninitialize;
2. in OnCreate event for your form allow window to accept drop events. Just execute the next code:
OleCheck(RegisterDragDrop(Handle, Self));
3. for your form you need implement a few methods for IDropTarget interface:
type
TfrmOrderWizard = class(TForm, IDropTarget)
...
private
{ IDropTarget }
function DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult; stdcall;
function DragOver(grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult; stdcall;
function DragLeave: HResult; stdcall;
function Drop(const dataObj: IDataObject;
grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult; stdcall;
{ IUnknown
Ignore referance counting }
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
...
where:
function TfrmOrderWizard.DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult;
begin
dwEffect := DROPEFFECT_COPY;
Result := S_OK;
end;
function TfrmOrderWizard.DragOver(grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult;
begin
dwEffect := DROPEFFECT_COPY;
Result := S_OK;
end;
function TfrmOrderWizard.DragLeave: HResult;
begin
Result := S_OK;
end;
function TfrmOrderWizard._AddRef: Integer;
begin
Result := 1;
end;
function TfrmOrderWizard._Release: Integer;
begin
Result := 1;
end;
function TfrmOrderWizard.Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult;
const
PT_TSTRING = ULONG(30);
PT_UNICODE = ULONG(31);
PR_BODY = PT_TSTRING or ($1000 shl 16);
PR_BODY_W = PT_UNICODE or ($1000 shl 16);
var
aFmtEtc: TFORMATETC;
aStgMed, stgmitem: TSTGMEDIUM;
pData: PChar;
pfgd: PFileGroupDescriptor;
dwCount, dwfetch: Integer;
stat: STATSTG;
pstg: IStorage;
pstm: IStream;
begin
{Make certain the data rendering is available}
if (dataObj = nil) then
raise Exception.Create('IDataObject-Pointer is not valid!');
with aFmtEtc do
begin
cfFormat := CF_TEXT;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
{Get the data}
OleCheck(dataObj.GetData(aFmtEtc, aStgMed));
try
{Lock the global memory handle to get a pointer to the data}
pData := GlobalLock(aStgMed.hGlobal);
{ Replace Text }
MemoOrder.Text := pData;
finally
{Finished with the pointer}
GlobalUnlock(aStgMed.hGlobal);
{Free the memory}
ReleaseStgMedium(aStgMed);
end;
// Get the file descriptors
with aFmtEtc do
begin
cfFormat := CF_FILEDESCRIPTOR;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
OleCheck(dataObj.GetData(aFmtEtc, aStgMed));
try
pfgd := PFileGroupDescriptor(GlobalLock(aStgMed.hGlobal));
// Iterate each of the files
for dwCount := 0 to pfgd.cItems-1 do
begin
// Set up for getting the file data
with aFmtEtc do
begin
cfFormat := CF_FILECONTENTS;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := dwCount;
tymed := TYMED_ISTORAGE;
end;
if (dataObj.GetData(aFmtEtc, stgmitem) = S_OK) then
begin
// IStorage (handle the outlook item)
pstg := IStorage(stgmitem.stg);
// Hard coded to open the outlook message item stream
if (pstg.OpenStream('__substg1.0_1000001F', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) or
(pstg.OpenStream('__substg1.0_1000001E', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) then
begin
pstm.Stat(stat, STATFLAG_DEFAULT);
pData := AllocMem(stat.cbSize);
try
pstm.Read(pData, stat.cbSize, @dwFetch);
// Set the msg body
MemoOrder.Lines.Add(String(pData));
finally
// Free buffer memory
FreeMem(pData);
end;
// Free the stream
pstm := nil;
end;
// Free the storage
pstg := nil;
// Release the storage medium
ReleaseStgMedium(stgmitem);
end;
end;
finally
// Unlock the memory
GlobalUnLock(aStgMed.hGlobal);
// Release the storage medium
ReleaseStgMedium(aStgMed);
end;
Result := S_OK;
end;
{$IFDEF VER210}
{$DEFINE SMForDelphi3}
{$DEFINE SMForDelphi4}
{$DEFINE SMForDelphi5}
{$DEFINE SMForDelphi6}
{$DEFINE SMForDelphi7}
{$DEFINE SMForDelphi2005}
{$DEFINE SMForDelphi2006}
{$IFDEF BCB}
{$DEFINE SMForBCB2006}
{$DEFINE SMForBCB2007}
{$DEFINE SMForBCB2009}
{$DEFINE SMForBCB2010}
{$ENDIF}
{$DEFINE SMForDelphi2007}
{$DEFINE SMForRADStudio2007}
{$DEFINE SMForDelphi2009}
{$DEFINE SMForDelphi2010}
{$ENDIF}