For a program that I am working on I had to be able to silently merge a file to the registry. I wanted a reliable way to do it and because of the annoying "Are you sure" dialog I opted not to use the ShellExecute with the "open" verb. I also wanted to have some control over whether I waited for RegEdit to finish or not. Well after trying a few things I came up with this solution. It uses CreateProcess and the /s (silent) switch, you must always put the switch first for RegEdit or it will assume it is a file and try to merge it.

This procedure will verify that the filename is quoted and add quotes if not, it will append the silent switch and do a bit of error checking along the way. It is very stable and will return an application defined error code if there is a problem executing or setting up for RegEdit and the exit code of RegEdit otherwise (0 = success).

ZeroMem zeros a range of memory, the other functions act like their MASM32 counterparts. The code is fairly straight forward and should be easy enough to translate from GoAsm to any other assembler. Note that in MASM some of the OFFSET directives will have to be changed to ADDR or the LEA equivalent.

MergeToRegistry FRAME pRegFile

uses ebx
LOCAL RegExitCode :D
LOCAL RegCmdLine[MAX_PATH] :B

invoke ZeroMem,OFFSET RegCmdLine,MAX_PATH

invoke GetWindowsDirectory,OFFSET RegCmdLine,MAX_PATH

invoke szCatStr,OFFSET RegCmdLine,OFFSET RegString
mov al,[pRegFile]
cmp al,22h
je >
invoke StrLen,OFFSET RegCmdLine
lea edx,RegCmdLine
add eax,edx
mov B[eax],22h
:
invoke szCatStr,OFFSET RegCmdLine,[pRegFile]
invoke StrLen,OFFSET RegCmdLine
lea edx,RegCmdLine
add eax,edx
mov cl,[eax-1]
cmp cl,22h
je >
mov B[eax],22h
:
mov D[sui.cb],SIZEOF STARTUPINFO
invoke GetStartupInfo,OFFSET sui
xor eax,eax
invoke CreateProcess,NULL,OFFSET RegCmdLine,eax,eax,\
TRUE,eax,eax,eax,OFFSET sui,OFFSET pi
or eax,eax
jz >.ERROR

; wait until the app has finished before continuing
; Hopefully RegEdit will never return STILL_ACTIVE as
; a valid exit code
:
invoke GetExitCodeProcess,[pi.hProcess],OFFSET RegExitCode
or eax,eax
jz >.ERROR2
cmp D[RegExitCode],STILL_ACTIVE
je <

invoke CloseHandle,[pi.hProcess]
invoke CloseHandle,[pi.hThread]

mov eax,[RegExitCode]
ret
.ERROR
mov eax,-0B0h
ret
.ERROR2
invoke CloseHandle,[pi.hProcess]
invoke CloseHandle,[pi.hThread]
mov eax,-0B1h
ret

RegString: DB "\RegEdit.exe /S ",0

ENDF
Posted on 2004-02-09 15:33:53 by donkey
Posted on 2004-02-10 15:47:21 by QvasiModo
Problem is that RegRestoreKey only works under NT and the others require that you know the name of the destination key and subkey before you restore it. That requires parsing the file (it is only a unicode text file). I needed something that would restore an to an unknown subkey under an unknown key. Using those APIs I would have to first find out which main key it is stored under, find the actual subkey name and then restore the values. I had started an application like this but it quickly got out of hand with all the permutations that could arise and I could not get the key sent to the right spot. Though they are fine if you know exactly where the key has to end up, in my case I do not. Also please note that all but a couple of lines are gauranteeing the file name format meets specifications, it is just CreateProcess that actually restores the key.
Posted on 2004-02-10 16:15:35 by donkey
You're right of course, I didn't think of that problem... :o
It just bothers me that there's no way to do this without launching an external program. And because of Unicode files, we can't just use the GetPrivateProfile* APIs either... :sweat:

EDIT: How about converting Unicode files to plain text, and then parsing it like an INI file? It might work (or I might be missing something, as usual :grin: )
Posted on 2004-02-10 16:26:33 by QvasiModo
Well, you know the API is just another external program, only in DLL instead of EXE format. For me as long as it is a base utility of Windows I have no problem with it. For such a minor function, though it is critical that my app can do this, it is easier to let the dedicated Windows app do the work. Also it allows me to restore to HKEY_CURRENT_USER without backup priviledges, this is not allowed with the API at all. GetPrivateProfileStringW does do a fine job of reading it and since I use GoAsm unicode is not a problem at all, but the keys are in the format:

Windows Registry Editor Version 5.00


[HKEY_CURRENT_USER\Software\Donkey\UpdateManager]

[HKEY_CURRENT_USER\Software\Donkey\UpdateManager\Options]
"WindowPos"=hex:39,00,00,00,54,00,00,00,db,02,00,00,f6,01,00,00
"HeaderOrder"=hex:00,00,00,00,04,00,00,00,01,00,00,00,02,00,00,00,03,00,00,00
"HeaderWidth"=hex:61,00,00,00,54,00,00,00,63,00,00,00,63,00,00,00,64,00,00,00
"TVRatio"=dword:00000022
"DefKey"=dword:00000004
"MRU"="C:\\MyApplication\\InternetUpdates\\01012004\\MyApp01012004.udp"
"Preferences"=dword:000001be


So they are a pain to parse.
Posted on 2004-02-10 16:47:07 by donkey
Yeah, we could hack REG files, and if MS ever changes the file format we would loose compatibility; but one can expect regedit.exe to be always there. So I guess it's fine to do it that way.
(It still seems more "elegant" to parse the files ourselves, but who cares anyway ;) )
Posted on 2004-02-10 17:14:05 by QvasiModo
That's pretty much how I feel about it. I had gotten to the point where I had all the main keys and subkey names and was about to start doing the merge when I realized I was at 100 lines of code for a simple convenience in my app. The only thing I didn't want was to use ShellExecute, I was afraid that some of the third party registry editors would not react as I wanted so I used CreateProcess and forced the file to RegEdit.exe
Posted on 2004-02-10 17:30:58 by donkey