This post contains a couple of simple programs that demonstrate how to use the C file functions within x86 assembly language code. The assembler used is FASM – the Flat Assembler. Both of the programs are Win32 programs with a dialog box as the main window.
The first program is a simple text to html converter and uses the functions: fopen(), fclose(), fgets() and fputs().
The second program is a Base64 encoder and uses: fopen(), fclose(), fread() and fwrite().
Related Post
FASM – A Simple Win32 Hex Editor
Importing The C Functions
In windows, all of the standard C functions are available through the MS Visual C Runtime DLL – MSVCRT.DLL.
FASM code includes an import data section where the libraries and the functions that will be imported from them are defined. For example to import from MSVCRT.DLL, first the library instruction is used:
library msvcrt,'MSVCRT.DLL' |
Then a table of the functions to be imported is defined using the import instruction:
import msvcrt,\ memset,'memset',\ fopen,'fopen',\ fclose,'fclose',\ fgets,'fgets',\ fputs,'fputs' |
For each entry in the table, the value in quotes is the exact name of the function as exported by the DLL. The other value labels a pointer which addresses the exported function. The function is then able to be called by referencing this pointer in the code.
Cinvoke
The imported functions, being standard C functions that use the cdecl calling convention, are called using the cinvoke macro:
cinvoke fopen,…
Or alternatively:
ccall [fopen],…
Remember that fopen is a pointer to the address of the exported function ‘fopen’.
The imported Win32 API functions, on the other hand, use the stdcall calling convention, so are called using either invoke or stdcall.
invoke MessageBox,…
stdcall [MessageBox],…
Using The C File Functions
This C pseudo-code outlines how the functions fopen(), fclose(), fgets(), and fputs() might be used within a C prgram:
FILE *fp; char file_name[MAX_PATH]; char buffer[1000]; ... fp = fopen(file_name,"r+"); if(fp) { // read a string from the file fgets(buffer,1000,fp); ... // write a string to the file fputs(buffer,fp); fclose(fp); } |
The equivalent in FASM:
cinvoke fopen,szFileName,szMode test eax,eax jz .ERROR_HANDLING mov [fp],eax cinvoke fgets,szBuffer,1000,[fp] ... cinvoke fputs,szBuffer,[fp] cinvoke fclose,[fp] |
By convention, functions return their result in the EAX register. So after fopen has been called, EAX is tested to see whether the file open operation was succesful. If EAX contains a valid pointer, then it is copied to the location addressed by fp, so that it can be referenced by any of the other functions that need to access the open file.
Base64 Encoding
The Base64 program uses the MIME Base64 encoding scheme. Data from the input file is read 3 bytes at a time. The 24 bits are broken up into four groups of 6 bits, which are then encoded to generate the 4 output bytes. A 6 bit value is encoded by using it as an index into the string:
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789+/ |
So for example: string[111110] = ‘+’
In the case where the number of input bytes is not a multiple of 3, then at the end of the encoding process there will be either 1 or 2 bytes remaining.
If only 1 byte remains, then 4 zero bits are appended to obtain two 6 bit values. These are Base64 encoded and then two equals sign characters are appended to get the 4 output bytes.
If 2 bytes remain, then 2 zero bits are appended to obtain three 6 bit values. These are Base64 encoded and then one equals sign character is appended to get the 4 output bytes.
Example One – TEXT 2 HTML – FASM Code
To grab this code, select with the mouse and then copy and paste directly into the FASM IDE.
; ------------------------------------------------------------------------------------- format PE GUI 4.0 entry start include 'win32a.inc' ; ------------------------------------------------------------------------------------- IDD_MY_DIALOG = 102 IDC_TXT_FILE = 1000 IDC_HTM_FILE = 1001 IDC_BTN_TXT = 1002 IDC_BTN_HTM = 1003 IDC_BTN_CONVERT = 1004 ; ------------------------------------------------------------------------------------- section '.code' code readable executable start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_MY_DIALOG,0,DialogProc,0 exit: invoke ExitProcess,0 ; ------------------------------------------------------------------------------------- proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .quit .wminitdialog: invoke SetDlgItemText,[hwnddlg],IDC_TXT_FILE,"" invoke SetDlgItemText,[hwnddlg],IDC_HTM_FILE,"" jmp .done .wmcommand: cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_TXT je .TXT_PATH cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_HTM je .HTM_PATH cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_CONVERT je .CONVERT jmp .done .TXT_PATH: ; get the path for the input text file stdcall File_Open,[hwnddlg] test eax,eax jz .done invoke SetDlgItemText,[hwnddlg],IDC_TXT_FILE,szTextPath jmp .done .HTM_PATH: ; get the path for the output html file stdcall File_Save_As,[hwnddlg] test eax,eax jz .done invoke SetDlgItemText,[hwnddlg],IDC_HTM_FILE,szHtmlPath jmp .done .CONVERT: ; do the conversion stdcall Text_2_Html,[hwnddlg] jmp .done .wmclose: invoke EndDialog,[hwnddlg],0 .done: mov eax,1 .quit: ret endp ; ------------------------------------------------------------------------------------- proc File_Open,hwnd ; display the GetOpenFileName dialog to get the text file path ; zero ofn - the OPENFILENAME struct mov eax,sizeof.OPENFILENAME cinvoke memset,ofn,0,eax ; initialise the members of ofn mov eax,sizeof.OPENFILENAME mov [ofn.lStructSize],eax mov eax,[hwnd] mov [ofn.hwndOwner],eax ; the filter mov eax,szTxtFilter mov [ofn.lpstrFilter],eax lea eax,[szTextPath] mov [ofn.lpstrFile],eax mov eax,MAX_PATH mov [ofn.nMaxFile],eax mov eax,OFN_EXPLORER or eax,OFN_FILEMUSTEXIST or eax,OFN_HIDEREADONLY mov [ofn.Flags],eax mov eax,szTxt mov [ofn.lpstrDefExt],eax ; display the dialog to get szTextPath invoke GetOpenFileName,ofn ret endp ; ------------------------------------------------------------------------------------- proc File_Save_As,hwnd ; display the GetSaveFileName dialog to get the html file path ; zero ofn - the OPENFILENAME struct mov eax,sizeof.OPENFILENAME cinvoke memset,ofn,0,eax ; initialise the members of ofn mov eax,sizeof.OPENFILENAME mov [ofn.lStructSize],eax mov eax,[hwnd] mov [ofn.hwndOwner],eax ; the filter mov eax,szHtmlFilter mov [ofn.lpstrFilter],eax lea eax,[szHtmlPath] mov [ofn.lpstrFile],eax mov eax,MAX_PATH mov [ofn.nMaxFile],eax mov eax,OFN_EXPLORER or eax,OFN_PATHMUSTEXIST or eax,OFN_HIDEREADONLY or eax,OFN_OVERWRITEPROMPT mov [ofn.Flags],eax mov eax,szHtml mov [ofn.lpstrDefExt],eax ; display the dialog to get szHtmlPath invoke GetSaveFileName,ofn ret endp ; ------------------------------------------------------------------------------------- proc Text_2_Html,hwnd ; read the text file line by line, enclose each line in P tags, ; and write to the output html file ; check that szTextPath is not an empty string invoke GetDlgItemText,[hwnd],IDC_TXT_FILE,szTextPath,MAX_PATH test eax,eax jz .INVALID_PATH ; check that szHtmlPath is not an empty string invoke GetDlgItemText,[hwnd],IDC_HTM_FILE,szHtmlPath,MAX_PATH test eax,eax jz .INVALID_PATH ; open the text file ; set the mode to "r" - open for reading lea esi,[szMode] mov [esi],byte 'r' mov [esi+1],byte 0 ; FILE* fp_txt = fopen(szTextPath,"r") cinvoke fopen,szTextPath,szMode mov [fp_txt],eax test eax,eax jz .ERR_FOPEN_TXT ; open the html file ; set the mode to "w" - open for writing lea esi,[szMode] mov [esi],byte 'w' mov [esi+1],byte 0 ; FILE* fp_htm = fopen(szHtmlPath,"w") cinvoke fopen,szHtmlPath,szMode mov [fp_htm],eax test eax,eax jz .ERR_FOPEN_HTM ; write the html file opening tags ; fputs(szHeader,fp_htm) cinvoke fputs,szHeader,[fp_htm] .GET_LINE: ; read a line from the text file ; fgets(szLine,10000,fp_text) cinvoke fgets,szLine,10000,[fp_txt] ; returns NULL when EOF test eax,eax jz .FINAL ; if the line is empty, discard it stdcall IsLineEmpty test eax,eax jz .GET_LINE ; enclose the line of text just read in p tags, ; and write to the output file cinvoke fputs,szPTag,[fp_htm] cinvoke fputs,szLine,[fp_htm] cinvoke fputs,szPCloseTag,[fp_htm] jmp .GET_LINE .FINAL: ; write the html file closing tags cinvoke fputs,szFinal,[fp_htm] cinvoke fclose,[fp_htm] .FCLOSE_TXT: cinvoke fclose,[fp_txt] jmp .DONE .ERR_FOPEN_TXT: invoke MessageBox,NULL,szFopenError,szTextPath,MB_ICONERROR+MB_OK jmp .DONE .ERR_FOPEN_HTM: invoke MessageBox,NULL,szFopenError,szHtmlPath,MB_ICONERROR+MB_OK jmp .FCLOSE_TXT .INVALID_PATH: invoke MessageBox,NULL,szPathError,szTitle,MB_ICONERROR+MB_OK .DONE: ret endp ; ------------------------------------------------------------------------------------- proc IsLineEmpty ; return 0 if the line contains nothing but whitespace xor eax,eax lea esi,[szLine] .TEST: mov dl,[esi] inc esi cmp dl,0 je .DONE cmp dl,13 je .DONE cmp dl,10 je .DONE cmp dl,32 jle .TEST mov eax,1 .DONE: ret endp ; ------------------------------------------------------------------------------------- section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL',\ comdlg32,'COMDLG32.DLL',\ msvcrt,'MSVCRT.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ DialogBoxParam,'DialogBoxParamA',\ SetDlgItemText,'SetDlgItemTextA',\ GetDlgItemText,'GetDlgItemTextA',\ MessageBox,'MessageBoxA',\ EndDialog,'EndDialog' import comdlg32,\ GetOpenFileName,'GetOpenFileNameA',\ GetSaveFileName,'GetSaveFileNameA' import msvcrt,\ memset,'memset',\ fopen,'fopen',\ fclose,'fclose',\ fgets,'fgets',\ fputs,'fputs' ; ------------------------------------------------------------------------------------- section '.text' readable writeable szTextPath rb MAX_PATH szHtmlPath rb MAX_PATH szTxt TCHAR "txt",0 szHtml TCHAR "html",0 szMode rb 4 ; Note that the filter strings are double null terminated: szTxtFilter TCHAR "Text Files",0,"*.txt",0,"All Files",0,"*.*",0,0 szHtmlFilter TCHAR "Html Files",0,"*.html",0,"All Files",0,"*.*",0,0 szTitle TCHAR "Error",0 szPathError TCHAR "Invalid file path!",0 szFopenError TCHAR "Call to fopen failed!",0 ofn OPENFILENAME fp_txt dd 0 fp_htm dd 0 szLine rb 10000 szHeader TCHAR " “,10,”Text 2 Html”,10,\ “”,10,10,””,10,10,0 szFinal TCHAR “”,10,” ",10,0 szPTag TCHAR " “,10,0 szPCloseTag TCHAR ” ",10,10,0 ; ------------------------------------------------------------------------------------- section '.rc' resource data readable directory RT_DIALOG,dialogs resource dialogs,\ IDD_MY_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,my_dialog dialog my_dialog,\ 'TXT 2 HTML',30,30,300,108,\ DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\ 0,0,"Lucida Console",11 dialogitem 'BUTTON','Input Text File',-1,5,5,290,36,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON',"Output Html File",-1,5,46,290,36,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_TXT_FILE,10,17,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_HTM_FILE,10,57,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'BUTTON',"...",IDC_BTN_TXT,256,17,30,16,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"...",IDC_BTN_HTM,256,57,30,16,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"TXT to HTML",IDC_BTN_CONVERT,5,86,80,16,BS_PUSHBUTTON+WS_VISIBLE,0 enddialog ; ------------------------------------------------------------------------------------- |
Example Two – Base64 – FASM Code
To grab this code, select with the mouse and then copy and paste directly into the FASM IDE.
; ------------------------------------------------------------------------------------- format PE GUI 4.0 entry start include 'win32a.inc' ; ------------------------------------------------------------------------------------- IDD_MY_DIALOG = 102 IDC_BIN_FILE = 1000 IDC_B64_FILE = 1001 IDC_BTN_BIN = 1002 IDC_BTN_B64 = 1003 IDC_BTN_CONVERT = 1004 ; ------------------------------------------------------------------------------------- section '.code' code readable executable start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_MY_DIALOG,0,DialogProc,0 exit: invoke ExitProcess,0 ; ------------------------------------------------------------------------------------- proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .quit .wminitdialog: invoke SetDlgItemText,[hwnddlg],IDC_BIN_FILE,"" invoke SetDlgItemText,[hwnddlg],IDC_B64_FILE,"" jmp .done .wmcommand: cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_BIN je .BIN_PATH cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_B64 je .B64_PATH cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_CONVERT je .CONVERT jmp .done .BIN_PATH: ; get the path for the input binary file stdcall File_Open,[hwnddlg] test eax,eax jz .done invoke SetDlgItemText,[hwnddlg],IDC_BIN_FILE,szBinaryPath jmp .done .B64_PATH: ; get the path for the output Base64 file stdcall File_Save_As,[hwnddlg] test eax,eax jz .done invoke SetDlgItemText,[hwnddlg],IDC_B64_FILE,szBase64Path jmp .done .CONVERT: ; do the conversion stdcall EncodeBase64,[hwnddlg] jmp .done .wmclose: invoke EndDialog,[hwnddlg],0 .done: mov eax,1 .quit: ret endp ; ------------------------------------------------------------------------------------- proc File_Open,hwnd ; display the GetOpenFileName dialog to get the binary file path ; zero ofn - the OPENFILENAME struct mov eax,sizeof.OPENFILENAME cinvoke memset,ofn,0,eax ; initialise the members of ofn mov eax,sizeof.OPENFILENAME mov [ofn.lStructSize],eax mov eax,[hwnd] mov [ofn.hwndOwner],eax ; the filter mov eax,szBinFilter mov [ofn.lpstrFilter],eax lea eax,[szBinaryPath] mov [ofn.lpstrFile],eax mov eax,MAX_PATH mov [ofn.nMaxFile],eax mov eax,OFN_EXPLORER or eax,OFN_FILEMUSTEXIST or eax,OFN_HIDEREADONLY mov [ofn.Flags],eax mov eax,szTxt mov [ofn.lpstrDefExt],eax ; display the dialog to get szBinaryPath invoke GetOpenFileName,ofn ret endp ; ------------------------------------------------------------------------------------- proc File_Save_As,hwnd ; display the GetSaveFileName dialog to get the base64 file path ; zero ofn - the OPENFILENAME struct mov eax,sizeof.OPENFILENAME cinvoke memset,ofn,0,eax ; initialise the members of ofn mov eax,sizeof.OPENFILENAME mov [ofn.lStructSize],eax mov eax,[hwnd] mov [ofn.hwndOwner],eax ; the filter mov eax,szTxtFilter mov [ofn.lpstrFilter],eax lea eax,[szBase64Path] mov [ofn.lpstrFile],eax mov eax,MAX_PATH mov [ofn.nMaxFile],eax mov eax,OFN_EXPLORER or eax,OFN_PATHMUSTEXIST or eax,OFN_HIDEREADONLY or eax,OFN_OVERWRITEPROMPT mov [ofn.Flags],eax mov eax,szTxt mov [ofn.lpstrDefExt],eax ; display the dialog to get szBase64Path invoke GetSaveFileName,ofn ret endp ; ------------------------------------------------------------------------------------- proc EncodeBase64,hwnd ; read the input binary file bytes, encode to base64, ; and write the result to the output file ; check that szBinaryPath is not an empty string invoke GetDlgItemText,[hwnd],IDC_BIN_FILE,szBinaryPath,MAX_PATH test eax,eax jz .INVALID_PATH ; check that szBase64Path is not an empty string invoke GetDlgItemText,[hwnd],IDC_B64_FILE,szBase64Path,MAX_PATH test eax,eax jz .INVALID_PATH ; open the input file ; set the mode to "rb" - open for reading as a binary file lea esi,[szMode] mov [esi],byte 'r' mov [esi+1],byte 'b' mov [esi+2],byte 0 ; FILE* fp_bin = fopen(szBinaryPath,"rb") cinvoke fopen,szBinaryPath,szMode mov [fp_bin],eax test eax,eax jz .ERR_FOPEN_BIN ; open the output file ; set the mode to "wb" - open for writing as a binary file lea esi,[szMode] mov [esi],byte 'w' mov [esi+1],byte 'b' mov [esi+2],byte 0 ; FILE* fp_b64 = fopen(szBase64Path,"wb") cinvoke fopen,szBase64Path,szMode mov [fp_b64],eax test eax,eax jz .ERR_FOPEN_B64 ; the input and output buffer lea esi,[Buffer] .GET_BYTES: ; read 3 bytes from the input file ; fread(&Buffer,1,3,fp_bin) cinvoke fread,esi,1,3,[fp_bin] ; if 0 bytes were read, then exit test eax,eax jz .FCLOSE_B64 ; if 1 byte was read: test eax,2 jz .PAD_1 ; if 2 bytes were read: test eax,1 jz .PAD_2 ; 3 bytes were read: xor eax,eax ; reverse the byte order mov dl,[esi] mov dh,[esi+2] mov [esi],dh mov [esi+2],dl ; load the 3 bytes into EDX mov edx,[esi] ; get the lower 6 bits of DL mov al,dl and al,0x3f ; encode the 6 bits stdcall BitsToChar ; copy the base64 char to the IO buffer mov [esi+3],al ; get the next 6 bits and encode shr edx,6 mov al,dl and al,0x3f stdcall BitsToChar mov [esi+2],al ; get the next 6 bits and encode shr edx,6 mov al,dl and al,0x3f stdcall BitsToChar mov [esi+1],al ; get the next 6 bits and encode shr edx,6 mov al,dl and al,0x3f stdcall BitsToChar mov [esi],al jmp .WRITE .PAD_1: ; only 1 byte was returned by fread() xor eax,eax mov dl,[esi] mov al,dl ; get the upper 6 bits and encode shr al,2 stdcall BitsToChar mov [esi],al ; get the lower 2 bits mov al,dl ; pad with 4 zero bits and encode shl al,4 and al,0x30 stdcall BitsToChar mov [esi+1],al ; pad the IO buffer with the '=' char mov [esi+2],byte '=' mov [esi+3],byte '=' jmp .WRITE .PAD_2: ; only 2 bytes were returned by fread() xor eax,eax mov dl,[esi+1] mov dh,[esi] ; pad the 2 input bytes with 2 zero bits shl edx,2 ; there are now 18 bits to be encoded ; encode the first 6 bits mov al,dl and al,0x3f stdcall BitsToChar mov [esi+2],al ; get the next 6 bits and encode shr edx,6 mov al,dl and al,0x3f stdcall BitsToChar mov [esi+1],al ; get the next 6 bits and encode shr edx,6 mov al,dl and al,0x3f stdcall BitsToChar mov [esi],al ; pad the IO buffer with the '=' char mov [esi+3],byte '=' .WRITE: ; write the 4 encoded bytes to the output file ; fwrite(&Buffer,1,4,fp_b64) cinvoke fwrite,esi,1,4,[fp_b64] jmp .GET_BYTES .FCLOSE_B64: cinvoke fclose,[fp_b64] .FCLOSE_BIN: cinvoke fclose,[fp_bin] jmp .DONE .ERR_FOPEN_BIN: invoke MessageBox,NULL,szFopenError,szBinaryPath,MB_ICONERROR+MB_OK jmp .DONE .ERR_FOPEN_B64: invoke MessageBox,NULL,szFopenError,szBase64Path,MB_ICONERROR+MB_OK jmp .FCLOSE_BIN .INVALID_PATH: invoke MessageBox,NULL,szPathError,szTitle,MB_ICONERROR+MB_OK .DONE: ret endp ; ------------------------------------------------------------------------------------- proc BitsToChar ; the 6 bit value is passed in AL ; use AL as an index into the string szBase64 to encode ; return the base64 char in AL lea edi,[szBase64] add edi,eax mov al,[edi] ret endp ; ------------------------------------------------------------------------------------- section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL',\ comdlg32,'COMDLG32.DLL',\ msvcrt,'MSVCRT.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ DialogBoxParam,'DialogBoxParamA',\ SetDlgItemText,'SetDlgItemTextA',\ GetDlgItemText,'GetDlgItemTextA',\ MessageBox,'MessageBoxA',\ EndDialog,'EndDialog' import comdlg32,\ GetOpenFileName,'GetOpenFileNameA',\ GetSaveFileName,'GetSaveFileNameA' import msvcrt,\ memset,'memset',\ fopen,'fopen',\ fclose,'fclose',\ fread,'fread',\ fwrite,'fwrite' ; ------------------------------------------------------------------------------------- section '.text' readable writeable szBinaryPath rb MAX_PATH szBase64Path rb MAX_PATH szTxt TCHAR "txt",0 szMode rb 4 ; Note that the filter strings are double null terminated: szTxtFilter TCHAR "Text Files",0,"*.txt",0,"All Files",0,"*.*",0,0 szBinFilter TCHAR "All Files",0,"*.*",0,0 szTitle TCHAR "Error",0 szPathError TCHAR "Invalid file path!",0 szFopenError TCHAR "Call to fopen failed!",0 ofn OPENFILENAME fp_bin dd 0 fp_b64 dd 0 szBase64 TCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",0 Buffer dd 0 ; ------------------------------------------------------------------------------------- section '.rc' resource data readable directory RT_DIALOG,dialogs resource dialogs,\ IDD_MY_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,my_dialog dialog my_dialog,\ 'Base64',30,30,300,108,\ DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\ 0,0,"Lucida Console",11 dialogitem 'BUTTON','Input Binary File',-1,5,5,290,36,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON',"Output Base64 File",-1,5,46,290,36,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_BIN_FILE,10,17,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_B64_FILE,10,57,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'BUTTON',"...",IDC_BTN_BIN,256,17,30,16,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"...",IDC_BTN_B64,256,57,30,16,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Encode Base64",IDC_BTN_CONVERT,5,86,80,16,BS_PUSHBUTTON+WS_VISIBLE,0 enddialog ; ------------------------------------------------------------------------------------- |