ReadCustomerData: Difference between revisions
No edit summary |
(No difference)
|
Revision as of 23:06, 27 October 2005
| Author: andreyvit (talk, contrib) |
The problem
You want to personalize (customize, preconfigure etc) each copy of installer you give out. But, of course, you do not want to recompile the installer every time.
The solution
Append the customization data directly to the installer EXE file, prefixed with some fixed string. For example, you can use "CUSTDATA:" prefix, and then the whole customization data could read like "CUSTDATA:12;Andrey Tarantsov;www.somesite.com/myhandler".
Implementing this solution
ReadCustomerData function does exactly what you expect: it scans through the end of the installer EXE file, finds your magic string ("CUSTDATA:"), and then returns everything after this string up to the end of the file.
; ReadCustomerData ( data_prefix -> customer_data ) ; Reads string data appended to the end of the installer EXE. ; The data must be preceded by a known string. ; Only last 1Kb of EXE is searched for the prefix ; (but this can be easily change, see comment below). ; Inputs: ; data_prefix (string) -- the string after which customer data begins ; Outputs: ; customer_data (string) -- the data after the prefix (does NOT include the prefix), ; empty if prefix not found ; Author: ; Andrey Tarantsov <andreyvit@gmail.com> -- please e-mail me useful modifications you make ; Example: ; Push "CUSTDATA:" ; Call ReadCustomerData ; Pop $1 ; StrCmp $1 "" 0 +2 ; MessageBox MB_OK "No data found" ; Abort ; MessageBox MB_OK "Customer data: '$1'" Function ReadCustomerData ; arguments Exch $R1 ; customer data magic value ; locals Push $1 ; file name or (later) file handle Push $2 ; current trial offset Push $3 ; current trial string (which will match $R1 when customer data is found) Push $4 ; length of $R1 ; get intaller file name System::Call 'kernel32::GetModuleFileNameA(i 0, t .r1, i 1024) i r2' FileOpen $1 $1 r ; change 1024 here to, e.g., 2048 to scan the last 2Kb of EXE file IntOp $2 0 - 1024 StrLen $4 $R1 loop: FileSeek $1 $2 END FileRead $1 $3 $4 StrCmp $3 $R1 found IntOp $2 $2 + 1 IntCmp $2 0 loop loop StrCpy $R1 "" goto fin found: IntOp $2 $2 + $4 FileSeek $1 $2 END FileRead $1 $3 StrCpy $R1 $3 fin: Pop $4 Pop $3 Pop $2 Pop $1 Exch $R1 FunctionEnd
How to parse the returned data
ReadCustomerData returns simply a string. When I need to split it into individual fields, I first declare variables to hold these fields:
var customer_name var customer_account var customer_cookie var customer_role var server_url
and then use the following code. (It calls ReadCSV and Trim functions, more on them below.)
; ParseCustomerData ( customer_data -> ) ; Parses semicolon-separated customer data into individual fields Function ParseCustomerData Exch $R1 ; customer data, then item count Push $1 ; current item index (0-based) Push $2 ; current item Push $R1 Call ReadCSV Pop $R1 StrCpy $1 0 loop: IntCmp $1 $R1 done Call Trim Pop $2 ; TODO: add dispatching code here IntCmp $1 0 item0 IntCmp $1 1 item1 IntCmp $1 2 item2 IntCmp $1 3 item3 IntCmp $1 4 item4 MessageBox MB_OK|MB_ICONEXCLAMATION "There are too many items in customer data; extra items ignored." goto done ; TODO: add saving code here item0: StrCpy $customer_name $2 goto ok item1: StrCpy $customer_account $2 goto ok item2: StrCpy $customer_cookie $2 goto ok item3: StrCpy $customer_role $2 goto ok item4: StrCpy $server_url $2 goto ok ok: IntOp $1 $1 + 1 Goto loop done: Pop $2 Pop $1 Pop $R1 FunctionEnd
ReadCSV and Trim functions
They used to be described in this Wiki, but somehow seem to be gone now. This is very unfortunate, as these are very convenient functions. So I just reproduce them here. I'm am NOT an author of these functions, and I would be glad to remove the code and replace it with links to them.
; Trim ; Removes leading & trailing whitespace from a string ; Usage: ; Push ; Call Trim ; Pop Function Trim Exch $R1 ; Original string Push $R2 Loop: StrCpy $R2 "$R1" 1 StrCmp "$R2" " " TrimLeft StrCmp "$R2" "$\r" TrimLeft StrCmp "$R2" "$\n" TrimLeft StrCmp "$R2" " " TrimLeft ; this is a tab. GoTo Loop2 TrimLeft: StrCpy $R1 "$R1" "" 1 Goto Loop Loop2: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " TrimRight StrCmp "$R2" "$\r" TrimRight StrCmp "$R2" "$\n" TrimRight StrCmp "$R2" " " TrimRight ; this is a tab GoTo Done TrimRight: StrCpy $R1 "$R1" -1 Goto Loop2 Done: Pop $R2 Exch $R1 FunctionEnd
Function ReadCSV Exch $1 # input string (csv) Push $2 # substring of $1: length 1, checked for commata Push $3 # substring of $1: single value, returned to stack (below $r2) Push $r1 # counter: length of $1, number letters to check Push $r2 # counter: values found, returned to top of stack Push $r3 # length: to determinate length of current value StrLen $r1 $1 StrCpy $r2 0 StrLen $r3 $1 loop: IntOp $r1 $r1 - 1 IntCmp $r1 -1 text done StrCpy $2 $1 1 $r1 StrCmp $2 ";" text Goto loop text: Push $r1 IntOp $r1 $r1 + 1 IntOp $r3 $r3 - $r1 StrCpy $3 $1 $r3 $r1 Pop $r1 StrCpy $r3 $r1 IntOp $r2 $r2 + 1 Push $3 Exch 6 Exch 5 Exch 4 Exch 3 Exch Goto loop done: StrCpy $1 $r2 Pop $r3 Pop $r2 Pop $r1 Pop $3 Pop $2 Exch $1 FunctionEnd