News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

HTML to RTF

Started by guga, June 08, 2013, 01:56:26 PM

Previous topic - Next topic

jj2007

Quote from: ToutEnMasm on June 14, 2013, 12:23:04 AM

This one is a dll called by a c executable,masm if we want.
Use string,i had only "problems" with files(need perhaps some money?).
String is valuable and simple to use.
http://www.htmltortf.com/convert-html-to-rtf-withphp/component-html-text-to-rtf-withphp.php

OMG ::)
QuoteYou are permitted to copy the documentation only for your own use. You are permitted to make only one back-up copy. The sale and sub-licensing of the software are forbidden

114 files, 500k alone for the DLL... and string.exe uses IsDebuggerPresent - any idea why?

TouEnMasm


the IsDebuggerPresent don't appear in the source code.Must be an addin of the c++.Generally he is used to know if a chain could be send to the debugger or not.
Masm had not this.
Fa is a musical note to play with CL

guga

 :dazzled: I can´t make this shit stops crashing  :icon_confused:

JJ, i triedexactly what you did and nothing. On the callback, i tried to simply returnemptied and nothing....I don´t know what a f. i´m doing wrong here.

This seems to be a stack problem, but i´m unable to find out why.

Whenever it calls to that crappy ForeignToRtf32

I´m tired and pissed for this dont´work. Can someone please help ? I have no more ideas why this is not working:(
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

That´s weird. Your´s alsogenerate an exception, but instead crashing and exiting, after it pass the exception, it goes to the callback function
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Quote from: guga on June 14, 2013, 03:04:03 PM
That´s weird. Your´s (edit JJ: reply #25?) also generate an exception, but instead crashing and exiting, after it pass the exception, it goes to the callback function

Yes, I've noticed that. It's not so uncommon to see "internal" exceptions that are somewhat handled by the OS, e.g. in the OpenFile dialogs.

I tried your code posted above, it says C/C++ comment remover - is that intentional? My hard disk is at its limits, so some time ago I had to remove RosAsm, unfortunately... could you post the relevant parts of the source only?

guga

Hi JJ,

yes comment remover was only the skeleton i used to test this functions. I didn´t wanted to start from scratch, so i used an old app that already have a dialog and opens a rtf file for testing the converter routines.

On the main dialogproc i have:


        ..Else_If D@wParam = IDC_OPEN

                mov B$HeaderSaveFilter 0
                move D$ofn.hwndOwner D@Adressee
                move D$ofn.hInstance D$hInstance
                mov D$ofn.lpstrFilter HeaderFileFilter
                call 'comdlg32.GetOpenFileNameA' ofn
                (...)
                call OpenHeaderFile D@Adressee ; the file (html or rtf) is loaded in memory here
                (...)
                call 'KERNEL32.GlobalAlloc' 042, 010000 | mov D$OutbutBuff eax
                [color=red]call 'html.iec.ForeignToRtf32' HeaderSaveFilter, 0, D$OutbutBuff, ghszConvtrVersion, 0, RtfOut [/color]
                (...)
    ...Else_If D@Message = &WM_INITDIALOG
        move D$hwnd D@Adressee
        call 'kernel32.GetModuleFileNameA' D$hInstance, Sz_ModuleName, &MAX_PATH
        call InitConverter32 D$hInstance, Sz_ModuleName [color=red]; <------- same as: call 'html.iec.InitConverter32' D$hInstance, Sz_ModuleName[/color]
        call RegisterApp 02, &NULL[color=red] ; <----- simply a: call 'html.iec.RegisterApp' 02, &NULL. Return value is a pointer to the structure REGAPPRET[/color]
        call GetReadNames IPath, IDescription, IExtension[color=red] ; the functions i post before to enumerate the registry import. Not related to the converter[/color]
        call GetWriteNames EPath, EDescription, EExtension ; ... and export



; The bastard  :greensml:



Proc RtfOut:
    Arguments @cchBuff, @nPercentComplete;, @Shit

    ;If D@cchBuff = 0 ; I removed the If case, justto test if it will make any difference if i directly call the functions below...but....:(
        call 'KERNEL32.GlobalLock' D$OutbutBuff;D@cchBuff
        call LpszBltLpszCchMax HeaderSaveFilter, eax, 259 ; <---- internally on the dll there is a function named as this, and the functionality is as the one i ported
                                                                                         ; It was a desperate attempt to make this crap works without crashing, and understand which function is using this callback
        call 'KERNEL32.GlobalUnlock' D$OutbutBuff;D@cchBuff
    ;End_If

EndP
____________________________________________

Proc LpszBltLpszCchMax:
    Arguments @Input, @Output, @Flag1
    Uses edx, esi, edi, ecx

    .If D@Flag1 <> 0
        mov edx D@Input
        mov esi D@Output ; < --------- Here is always set to ZERO ????
        Do
            mov cl B$esi ; <--------------- and then.....Internally is where it crashes
            dec D@Flag1
            On cl = 0, jmp L1>

            mov cl B$edx
            inc edx
            inc esi
        Loop_Until D@Flag1 = 0   
    .End_If
L1:
   
EndP



I have no more clue why it is crashing :(
I tried to reproduce exactly what you did, and even if i use the same arguments, parameter, buffers, it still crashes badly.

For what i saw the ForeignToRtf32 uses as parameters the members of some structure. It points to a function named: FceForeignToRtf that adds 2 more fixed parameters "Char = value always 10" and "Integer = value always 871"  - Both values, btw are the same ones as returned by the structure REGAPPRET resultant from RegisterApp.



; int __stdcall FceForeignToRtf(HGLOBAL ghszFile, int pstgForeign, int ghBuff, int ghszClass, int ghszSubset, int lpfnOut, char Char, int Integer)
_FceForeignToRtf@32 proc near ; CODE XREF: ForeignToRtf32(x,x,x,x,x,x)+4Fp

Tmp_ghszFile = dword ptr -268h
Tmp_ghszSubset = dword ptr -264h
Tmp_ghszClass = dword ptr -260h
Tmp_pstgForeign = dword ptr -25Ch
var_258 = dword ptr -258h
pDst = byte ptr -150h
String = byte ptr -48h
DummyVar = dword ptr -4
ghszFile = dword ptr  8
pstgForeign = dword ptr  0Ch
ghBuff = dword ptr  10h
ghszClass = dword ptr  14h
ghszSubset = dword ptr  18h
lpfnOut = dword ptr  1Ch
Char = dword ptr  20h
Integer = dword ptr  24h

mov edi, edi
push ebp
mov ebp, esp
sub esp, 268h
mov eax, ___security_cookie
xor eax, ebp
mov [ebp+DummyVar], eax
mov eax, [ebp+pstgForeign]
mov [ebp+Tmp_pstgForeign], eax
mov eax, [ebp+ghBuff]
push ebx
mov ebx, [ebp+ghszFile]
mov [ebp+Tmp_ghszFile], eax
mov eax, [ebp+ghszClass]
push esi
mov [ebp+Tmp_ghszClass], eax
mov eax, [ebp+ghszSubset]
push edi
mov [ebp+Tmp_ghszSubset], eax
call _InitExceptions@0 ; InitExceptions()
call _FInitHeaps@0 ; FInitHeaps()
test eax, eax
jnz short loc_42B5D3
push 0FFFFFFF8h
call _ShutdownProc@4 ; ShutdownProc(x)

loc_42B5D3: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+4Bj
mov eax, [ebp+lpfnOut]
push 0
push 0
mov function, eax
call _SetImportPercentOptions@8 ; SetImportPercentOptions(x,x)
mov edi, [ebp+Integer]
mov eax, [ebp+Integer]
mov esi, [ebp+Char]
and edi, 80h
and eax, 400h
shl edi, 8
or edi, eax
mov eax, [ebp+Integer]
shl eax, 0Ch
not eax
shl edi, 4
and eax, 10000h
and esi, 1Ch
or edi, eax
shl esi, 7
test ebx, ebx
mov __fForeignToRtf, 1
jz short loc_42B671
push ebx ; hMem
lea eax, [ebp+pDst]
push eax ; Input
call _LpchBltLpszHx@8 ; LpchBltLpszHx(x,x)[color=red] <---------------- THIS IS WHERE IT CRASHES INTERNALLY, because "pDst" is always Zero.[/color]
test byte ptr _vcpref, 8
jnz short loc_42B647
lea eax, [ebp+pDst]
push eax ; pDst
push eax ; pSrc
call ds:__imp__OemToCharA@8 ; OemToCharA(x,x)

loc_42B647: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+B8j
xor eax, eax
push eax ; int
push eax ; int
push eax ; int
push eax ; int
push 104h ; int
lea eax, [ebp+var_258]
push eax ; int
lea eax, [ebp+pDst]
push eax ; lpString
call _FileNameSplit@28 ; FileNameSplit(x,x,x,x,x,x,x)
push [ebp+Char]
lea eax, [ebp+var_258]
push eax
jmp short loc_42B67F
; ---------------------------------------------------------------------------

loc_42B671: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+A2j
test byte ptr [ebp+Char], 1
jz short loc_42B68E
push [ebp+Char] ; char
push offset Class ; lpString

loc_42B67F: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+F0j
push _hInstance ; int
call _FInitConvIO@12 ; FInitConvIO(x,x,x)
test eax, eax
jnz short loc_42B695

loc_42B68E: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+F6j
push 0FFFFFFFFh
call _ShutdownProc@4 ; ShutdownProc(x)

loc_42B695: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+10Dj
test byte ptr [ebp+Integer], 1
jz loc_42B730
test byte ptr [ebp+Char], 1
mov ebx, 8001h
jz short loc_42B6E8
lea eax, [ebp+String]
push eax
call _CchFetchMainStream@4 ; CchFetchMainStream(x)
mov eax, esi
or eax, edi
or eax, ebx
cmp [ebp+Tmp_pstgForeign], 0
push eax ; int
lea eax, [ebp+String]
jz short loc_42B6D4
push [ebp+Tmp_pstgForeign] ; int
push eax ; lpMultiByteStr
call _FnOpenStmPstg@12 ; FnOpenStmPstg(x,x,x)
jmp short loc_42B6E3
; ---------------------------------------------------------------------------

loc_42B6D4: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+145j
push 0 ; int
push eax ; lpString
lea eax, [ebp+pDst]
push eax ; int
call _FnOpen@16 ; FnOpen(x,x,x,x)

loc_42B6E3: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+153j
mov dword_456388, eax

loc_42B6E8: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+129j
cmp dword_456388, 0FFFFFFFFh
jnz short loc_42B737
test byte ptr [ebp+Char], 2
jz short loc_42B716
or esi, edi
or esi, ebx
push esi ; int
push 0 ; int
push 0 ; lpString
lea eax, [ebp+pDst]
push eax ; int
call _FnOpen@16 ; FnOpen(x,x,x,x)
cmp eax, 0FFFFFFFFh
mov dword_456388, eax
jnz short loc_42B737

loc_42B716: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+176j
call _FeGetError@0 ; FeGetError()
sub eax, 6
neg eax
sbb eax, eax
and eax, 0Dh
add eax, 0FFFFFFF2h
push eax
call _ShutdownProc@4 ; ShutdownProc(x)
jmp short loc_42B737
; ---------------------------------------------------------------------------

loc_42B730: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+11Aj
or dword_456388, 0FFFFFFFFh

loc_42B737: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+170j
; FceForeignToRtf(x,x,x,x,x,x,x,x)+195j ...
push [ebp+Tmp_ghszClass] ; hMem
call _HxCloneHx@4 ; HxCloneHx(x)
push [ebp+Tmp_ghszClass] ; int
xor edi, edi
push edi ; hMem
push dword_456388 ; int
mov esi, eax
call _FFileRecognized32@12 ; FFileRecognized32(x,x,x)
test eax, eax
jnz short loc_42B763
push 0FFFFFFF2h
call _ShutdownProc@4 ; ShutdownProc(x)

loc_42B763: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+1DBj
push 202h
push offset _LcbWriteMoreRtf@16 ; LcbWriteMoreRtf(x,x,x,x)
lea eax, [ebp+Tmp_ghszFile]
push eax
call _FnOpenMemory@12 ; FnOpenMemory(x,x,x)
cmp eax, 0FFFFFFFFh
mov dword_45638C, eax
jnz short loc_42B78A
push 0FFFFFFF4h
call _ShutdownProc@4 ; ShutdownProc(x)

loc_42B78A: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+202j
mov eax, dword_456388
cmp eax, 0FFFFFFFFh
jz short loc_42B79C
push edi
push edi
push eax
call _FcSeekFn@12 ; FcSeekFn(x,x,x)

loc_42B79C: ; CODE XREF: FceForeignToRtf(x,x,x,x,x,x,x,x)+213j
push [ebp+Tmp_ghszSubset]
push esi
push dword_45638C
push dword_456388
call _ConvertForeignToRtf@16 ; ConvertForeignToRtf(x,x,x,x)
push esi ; hMem
call ds:__imp__GlobalFree@4 ; GlobalFree(x)
push dword_45638C
call _FCloseFn@4 ; FCloseFn(x)
call _UninitConvIO@0 ; UninitConvIO()
call _UnensureOleAvail@0 ; UnensureOleAvail()
call _UninitHeaps@0 ; UninitHeaps()
mov ecx, [ebp+DummyVar]
pop edi
pop esi
xor ecx, ebp
xor ax, ax
pop ebx
call @__security_check_cookie@4 ; __security_check_cookie(x)
leave
retn 32
_FceForeignToRtf@32 endp
; ---------------------------------------------------------------------------

Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

TouEnMasm


"Seems there is a stack problem"

Seems also there is different prototypes for 16 bits and 32 bits.
There is a sample provided who don't use the same numbers of paramaters (functions) than in the declarations prototypes.
Must gone of this.
When i see that i had just let it.


Fa is a musical note to play with CL

jj2007

call 'KERNEL32.GlobalLock' D$OutbutBuff;D@cchBuff
int 3

Post the exe with that interrupt - Olly answers many questions ;-)

But otherwise, it looks pretty identical to what I have used ::)

guga

here is the exe

yours also crashes, but it returns from the callback, at least 6 or 8 times before entering onto the RtfOut function. If you have Idapro, try debugging your version you see what is happenning. I debugged in RosAs, but i  didn´t make RosAsm shows the source when is debugging inside a external file (dll for example) - It would be needed a codelevel debbuging and not a source level debugging as it is current.

This cnv files seems a huge pile of crap due to those errors, but, once we are able to fix it, we can use all converters dispites those problems and make a correct documentation on how to use them. Damn M$!

I tried to add more parameters for that function, and nothing. The original  C code for this is:



/* F O R E I G N  T O  R T F  3  2 */
/*----------------------------------------------------------------------------
%%Function: ForeignToRtf32

Purpose:
Convert a file to Rtf using the format specified in ghszClass.

Parameters:
ghszFile : global handle to '\0'-terminated filename to be read
pstgForeign : pointer to IStorage of embedding being converted,
NULL for non-OLE2 docfile converters.
ghBuff : global handle to buffer in which chunks of Rtf are passed
to WinWord.
ghszClass: identifies which file format to translate.  This
string is the one selected by the user in the 'Confirm
Conversions' dialog box in Word.
ghszSubset: identifies which subset of the file is to be converted.
Typically used by spreadsheet converters to identify
subranges of the entire spreadsheet to import.
lpfnOut: callback function provided by WinWord to be called whenever
we have a chunk of Rtf to return.

Returns:
fce indicating success or failure and cause
----------------------------------------------------------------------------*/
FCE PASCAL ForeignToRtf32(HANDLE ghszFile, IStorage *pstgForeign, HANDLE ghBuff, HANDLE ghszClass, HANDLE ghszSubset, PFN_RTF lpfnOut)
{
#ifndef CANT_IMPORT
HANDLE hFile;
char FAR *lpBuff;
char szFileName[260];
long cbFile;
long cbOrig;
short cbPass;
FCE fceRet = fceNoErr;
char rgb[cchFilePrefix];
long cbr;

AssertSz(((ghszFile == NULL) ^ (pstgForeign == NULL)),
"Need exactly one of ghszFile and pstgForeign");

if (pstgForeign)
return fceInvalidDoc;

// copy filename locally; file open doesn't want a global handle
AssertSz(ghszFile != NULL, "NULL filename in ForeignToRtf");
if (!PchBltSzHx(szFileName, ghszFile))
return fceNoMemory;
// translate filename from the oem character set to the windows set
if (!lfRegApp.fDontNeedOemConvert)
OemToChar((LPCSTR)szFileName, (LPSTR)szFileName);

// open file and read sufficient bytes to identify file type.
// Note that we cannot assume that IsFormatCorrect was previously called;
// we must check ourselves, again.
if ((hFile = CreateFile((LPSTR)szFileName, GENERIC_READ,
FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)0,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
(HANDLE)NULL)) == INVALID_HANDLE_VALUE)
{
return fceOpenInFileErr;
}
ReadFile(hFile, rgb, cchFilePrefix, &cbr, NULL);
if (strncmp(szFilePrefix, rgb, cchFilePrefix) != 0)
{
CloseHandle(hFile);
return fceInvalidFile;
}

// determine file size and restore current file position
cbOrig = cbFile = SetFilePointer(hFile, 0L, NULL, FILE_END) - (long)cchFilePrefix;
SetFilePointer(hFile, cchFilePrefix, NULL, FILE_BEGIN);

// do the actual file import conversion.  We've already read the prefix,
// all that remains is to copy the remainder of the file.
for (; cbFile > 0 && fceRet >= 0; cbFile -= (long)cbPass)
{
// write at most 2K of Rtf on each WinWord callback
cbPass = (cbFile > 2048L) ? 2048 : (short)cbFile;

// we must resize the buffer, each time, ourselves.
if (GlobalReAlloc(ghBuff, (long)cbPass, GMEM_MOVEABLE) == NULL)
{
CloseHandle(hFile);
return fceNoMemory;
}

if ((lpBuff = (char FAR *)GlobalLock(ghBuff)) == NULL)
{
CloseHandle(hFile);
return fceNoMemory;
}

ReadFile(hFile, lpBuff, cbPass, &cbr, NULL);
GlobalUnlock(ghBuff);

// pass the Rtf to WinWord.  Word will check for a user abort and
// may return any of our fce values to us.  If negative, we need to
// ourselves abort and return that same fce.
fceRet = (FCE)((lpfnOut)(cbPass, (long)((cbOrig - cbFile) * 100 / cbOrig)));
}

CloseHandle(hFile);

return fceRet;
#else
AssertSz(fFalse, "ForeignToRtf32: This converter can't import.");
return fceOpenConvErr;
#endif // !CANT_IMPORT
}


#ifndef CANT_EXPORT


/* R T F  T O  F O R E I G N  3  2 */


I tried to compile this, but Visual Studio refuses it.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Dubby

Hi all,

been download jj' file and guga's..
and analyze them...

the problem I found is the return from GlobalLock which is always zero from guga's file.. inside the internal function..
but the jj's is not..

from what I understand after analyze them:
the function expect the file name to be allocated from GlobalAlloc (the 1st argument). try it. it might work...
put an eye how the 1st argument is being transferred inside the calls..

but don't ask me how jj's escape from GlobalLock... no idea about it..  :dazzled:

goodluck  :t

jj2007

Quote from: guga on June 15, 2013, 02:19:10 AM
here is the exe

When I press Open, I get a file dialog for .c files. Can you call the converter directly in WM_CREATE with a predefined html name, so that I can jump straight to the int 3? Thanks.

> return from GlobalLock which is always zero from guga's file
@Dubby: In case you are using Olly: What does it show as last error? invalid handle?
@Guga: call 'KERNEL32.GlobalAlloc' 042, 010000: 42h=GHND, but is it really radix 16?? You know RosAsm much better ;-)

TouEnMasm


Here is my own translator.
A simple richedit who accept images.
Just made a copy from the html page
Add the images by copy and you got the sample provided,That's all.
Fa is a musical note to play with CL

Dubby

@jj:
yes, the last error shows invalid handle.

jj2007

10025F19                8BEC                     mov ebp, esp
10025F1B                68 03010000              push 103
10025F20                FF75 0C                  push dword ptr [ebp+0C] <<<<<<<<<<<
10025F23                FF15 0C110010            call near [<&KERNEL32.GlobalLock>]


What gets pushed here (somewhere deep inside the DLL) is a pointer to a DWORD that contains the address in the .data section of the HTM file name. And the lock fails. Guga, how do you pass the file name to the proc? Try using GlobalAlloc, GPTR, 100h for the buffer that contains the source file name.

guga

#74
I´m reproducing exactly the same you did:

....opendialog....ofn.lpstrFile = pointer to c:\temp\bbb.html
..ghszConvtrVersion pointer to a buffer to hold the path ? [ghszConvtrVersion: B$ 0 #019C]
call 'KERNEL32.GlobalAlloc' 042, 010000 | mov D$OutbutBuff eax
call 'html.iec.ForeignToRtf32' ofn.lpstrFile, 0, D$OutbutBuff, ghszConvtrVersion, 0, RtfOut

; it returns on the 10th time (on yours, not in mine)
Proc RtfOut:
    Arguments @cchBuff, @nPercentComplete;, @Shit

    ;If D@nPercentComplete = 0
        call 'KERNEL32.GlobalLock' D$OutbutBuff;D@cchBuff
        call LpszBltLpszCchMax ofn.lpstrFile, D$eax, 259 ; crashes :(
;        call LpszBltLpszCchMax ofn.lpstrFile, eax, 259 ; crashes :
        call 'KERNEL32.GlobalUnlock' D$OutbutBuff;D@cchBuff
    ;End_If

EndP


The only thing i know for sure is that LpszBltLpszCchMax is not being pointing to the path of the html file. There is a serious stack error internally on that function. The parameters seems to be pointers to a structure. I have no more clue what i´m doing wrong here.


For instance, yours RtfOut loops back 10 times, before passing through GlobalLock function. I mean, the 1st time of the callback, nPercentComplete = 0, then it will jmp over and return....the next time it return, it always return to RtfOut, untill the 10th time, where nPercentComplete = 0400, making it don´t jmp and go throught GlobalLock


It is a stack problem, because the function RTFOut have 2 parameters @cchBuff, @nPercentComplete, while ForeignToRtf32 have only 6 (8, if you count the2 additionals ones from RtfOut).So, there is no reason why it is coming back 10 times to the callback, if the total count of arguments is at most 8 !!!


The modified version does exactly the same as yours, but....it crashes....(The opendialog,now contains only html/rtf to you open)


Btw: GlobalAlloc, GPTR, 100h still crashed


The problem seems to be that the original function puts some many junk on the stack (unaligned data) that when it will points to the path, it looses the pointer. They placed a structure to hold it with 612 bytes, but they should use a global variable to hold it and not a local one. The only solution i see for that crap is do the same as they did. I´ll be forced to put a structure on the stack before ForeignToRtf32, zero it and let ForeignToRtf32 do it´s mess alone. I´ll give a try and see what happens.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com