Changelog: Andreas Mohr programs/wineboot * Initial implementation
--- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/.cvsignore 2000-11-04 01:00:35.000000000 +0200 @@ -0,0 +1,4 @@ +Makefile +rsrc.res +uninstaller +uninstaller.spec.c --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/GUI.txt 2001-11-28 22:53:47.000000000 +0200 @@ -0,0 +1,84 @@ +Array: +"WinInitIni_Execute", + +Settings: +[x] Run +[x] Run without asking individually + +BootupConfig_Enable +BootupConfig_DryRun +BootupConfig_GUI_Enable = "Y" (default) +BootupConfig_TTY_Verbose = "N"(default) +BootupConfig_TTY_Quiet = "N" (default) + +wininit.ini: +WininitIni_Execute +Do you want to execute wininit.ini (file move operations) ? +Yes/No, ([x] make choice permanent) +No permanent --> WininitIni_Execute = FALSE +Yes permanent --> WininitIni_GUI_Ask = FALSE + +Generell fragen, einzeln fragen: WininitIni_Execute Y, WininitIni_GUI_AskWhole Y, WininitIni_GUI_AskSingle Y +Generell fragen: WininitIni_Execute Y, WininitIni_GUI_AskWhole Y, WininitIni_GUI_AskSingle N + + +WininitIni_GUI_Ask + + +WininitIni_GUI_AskSingle +weiteres setting: make permanent (in der Session) + +Moeglichkeiten: +- wininit.ini ausfuehren ja/nein +- + +RunServicesOnce +RunServicesOnce_Execute +RunServicesOnce_GUI_Enable +RunServicesOnce_GUI_Single + +HKLM RunServices +RunServicesHKLM_Execute +RunServicesHKLM_GUI_Enable +RunServicesHKLM_GUI_Single + +RenameFiles +RenameFiles_Execute +RenameFiles_GUI_Enable +RenameFiles_GUI_Single (= "N") + +HKLM RunOnce +RunOnceHKLM_Execute +RunOnceHKLM_GUI_Enable +RunOnceHKLM_GUI_Single + +Run this particular one-time program execution ? +[x] apply to all RunOnce, not just this one +[x] (almost) permanently store current choice + +RunOnceEx + +win.ini Load= +WinIniLoad_Execute +WinIniLoad_GUI_Enable +WinIniLoad_GUI_Single + +Run the win.ini Load= line '%s' ? +[x] (almost) permanently store current choice + +win.ini Run= +WinIniRun_Execute +WinIniRun_GUI_Enable +WinIniRun_GUI_Single + +HKLM Run +RunHKLM_Execute +RunHKLM_GUI_Enable +RunHKLM_GUI_Single + +HKCU Run +Common Startup folder +StartupFolderCommon_Execute +User Startup folder +StartupFolderUser_Execute +HKCU RunOnce --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/Makefile 2002-12-17 20:57:04.000000000 +0200 @@ -0,0 +1,369 @@ +TOPSRCDIR = ../.. +TOPOBJDIR = ../.. +SRCDIR = . + +MODULE = wineboot.exe +APPMODE = cui +IMPORTS = user32 advapi32 kernel32 ntdll + +C_SRCS = \ + wineboot.c + +RC_SRCS = rsrc.rc + + +# Global rules for building a Winelib program -*-Makefile-*- +# +# Each individual makefile should define the following variables: +# MODULE : name of the main module being built +# APPMODE : program mode (cui,gui,cuiw,guiw) +# EXTRALIBS : extra libraries to link in (optional) +# EXTRADEFS : extra symbol definitions, like -DWINELIB (optional) +# +# plus all variables required by the global Make.rules.in +# + +DEFS = -fPIC -DNONAMELESSUNION -DNONAMELESSSTRUCT $(EXTRADEFS) +LDDLLFLAGS = -Wl,-Bsymbolic,-z,defs +ALL_OBJS = $(OBJS) $(MODULE).dbg.o +ALL_LIBS = $(LIBWINE) $(EXTRALIBS) $(LIBS) +BASEMODULE = $(MODULE:.exe=) +TESTIMPORTS = $(DELAYIMPORTS) $(IMPORTS) +RUNTESTFLAGS= -q -P wine -T $(TOPOBJDIR) $(PLTESTPROGRAM:%=-p %) + + +# Global rules shared by all makefiles -*-Makefile-*- +# +# Each individual makefile must define the following variables: +# TOPSRCDIR : top-level source directory +# TOPOBJDIR : top-level object directory +# SRCDIR : source directory for this module +# MODULE : name of the module being built +# +# Each individual makefile may define the following additional variables: +# C_SRCS : C sources for the module +# C_SRCS16 : 16-bit C sources for the module +# RC_SRCS : resource source files +# SPEC_SRCS : interface definition files +# EXTRA_SRCS : extra source files for make depend +# EXTRA_OBJS : extra object files +# IMPORTS : dlls to import +# DELAYIMPORTS : dlls to import in delayed mode +# SUBDIRS : subdirectories that contain a Makefile +# EXTRASUBDIRS : subdirectories that do not contain a Makefile +# INSTALLSUBDIRS : subdirectories to run make install/uninstall into + +# First some useful definitions + +SHELL = /bin/sh +CC = gcc +CPP = gcc -E +CFLAGS = -g -O2 -Wall -mpreferred-stack-boundary=2 $(EXTRACFLAGS) +OPTIONS = -D_REENTRANT +LIBS = -lm +YACC = bison -y +LEX = flex +LEXLIB = -lfl +EXEEXT = +OBJEXT = o +LIBEXT = so +DLLEXT = .so +IMPLIBEXT = def +CROSSCC = false +LDSHARED = $(CC) -shared $(SONAME:%=-Wl,-soname,%) +DLLTOOL = false +DLLWRAP = +DLLWRAPFLAGS = --add-stdcall-alias +AR = ar rc +RANLIB = ranlib +STRIP = strip +WINDRES = false +LN = ln +LN_S = ln -s +TOOLSDIR = $(TOPOBJDIR) +DIVINCL = -I$(SRCDIR) -I. -I$(TOPSRCDIR)/include -I$(TOPOBJDIR)/include $(EXTRAINCL) +ALLCFLAGS = $(DIVINCL) $(CFLAGS) $(DEFS) $(OPTIONS) +LD = ld +LDFLAGS = +LDCOMBINE = $(LD) -r +RM = rm -f +MV = mv +C2MAN = c2man +MANSPECS = -w $(TOPSRCDIR)/dlls/gdi/gdi32.spec \ + -w $(TOPSRCDIR)/dlls/user/user32.spec \ + -w $(TOPSRCDIR)/dlls/comctl32/comctl32.spec \ + -w $(TOPSRCDIR)/dlls/commdlg/comdlg32.spec \ + -w $(TOPSRCDIR)/dlls/kernel/kernel32.spec +LINT = +LINTFLAGS = +ALLLINTFLAGS = $(LINTFLAGS) $(DEFS) $(OPTIONS) $(DIVINCL) +MKINSTALLDIRS= $(TOPSRCDIR)/tools/mkinstalldirs +WINAPI_CHECK = $(TOPSRCDIR)/tools/winapi_check/winapi_check +WINEWRAPPER = $(TOPSRCDIR)/tools/winewrapper +RUNTEST = $(TOPSRCDIR)/tools/runtest +WINEBUILD = $(TOOLSDIR)/tools/winebuild/winebuild +MAKEDEP = $(TOOLSDIR)/tools/makedep +WRC = $(TOOLSDIR)/tools/wrc/wrc +WMC = $(TOOLSDIR)/tools/wmc/wmc +WIDL = $(TOOLSDIR)/tools/widl/widl +WRCFLAGS = -J -m $(EXTRAWRCFLAGS) +LDPATH = LD_LIBRARY_PATH="$(TOOLSDIR)/library:$(TOOLSDIR)/unicode:$$LD_LIBRARY_PATH" +DLLDIR = $(TOPOBJDIR)/dlls +LIBWINE = -L$(TOPOBJDIR)/library -lwine +LIBUNICODE = -L$(TOPOBJDIR)/unicode -lwine_unicode +LIBUUID = -L$(TOPOBJDIR)/ole -lwine_uuid + + + +# Installation infos + +INSTALL = /usr/bin/install -c $(INSTALL_FLAGS) +INSTALL_PROGRAM = ${INSTALL} $(INSTALL_PROGRAM_FLAGS) +INSTALL_SCRIPT = ${INSTALL} $(INSTALL_SCRIPT_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 $(INSTALL_DATA_FLAGS) +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +libdir = ${exec_prefix}/lib +datadir = ${prefix}/share +infodir = ${prefix}/info +mandir = ${prefix}/man +sysconfdir = ${prefix}/etc +includedir = ${prefix}/include/wine +dlldir = ${exec_prefix}/lib/wine +prog_manext = 1 +conf_manext = 5 +CLEAN_FILES = *.o *.a *.so *.ln *.$(LIBEXT) \\\#*\\\# *~ *% .\\\#* *.bak *.orig *.rej \ + *.flc *.spec.c *.spec.def *.glue.c *.dbg.c y.tab.c y.tab.h lex.yy.c core + +OBJS = $(C_SRCS:.c=.o) $(EXTRA_OBJS) + +RCOBJS = $(RC_SRCS:.rc=.res.o) +LINTS = $(C_SRCS:.c=.ln) + +# Implicit rules + +.SUFFIXES: .mc .rc .mc.rc .res .res.o .spec .spec.c .spec.def .ok .cross.o + +.c.o: + $(CC) -c $(ALLCFLAGS) -o $@ $< + +.c.cross.o: + $(CROSSCC) -c $(ALLCFLAGS) -o $@ $< + +.s.o: + $(AS) -o $@ $< + +.mc.mc.rc: + $(LDPATH) $(WMC) -i -U -H /dev/null -o $@ $< + +.rc.res: + $(LDPATH) $(WRC) $(WRCFLAGS) $(DIVINCL) -o $@ -r $< + +.res.res.o: + $(WINDRES) -i $< -o $@ + +.spec.spec.c: + $(LDPATH) $(WINEBUILD) $(DEFS) -o $@ -M $(MODULE) --spec $< + +.spec.spec.def: + $(LDPATH) $(WINEBUILD) $(DEFS) -o $@ --def $< + +.c.ln: + $(LINT) -c $(ALLLINTFLAGS) $< || ( $(RM) $@ && exit 1 ) + +.c.ok: + $(RUNTEST) $(RUNTESTFLAGS) $< && touch $@ + +# 'all' target first in case the enclosing Makefile didn't define any target + +all: Makefile + +filter: + @$(TOPSRCDIR)/tools/winapi/make_filter --make $(MAKE) all + +.PHONY: all filter + +# Rule for main module debug channels + +$(MODULE).dbg.c: $(C_SRCS) $(C_SRCS16) $(WINEBUILD) + $(LDPATH) $(WINEBUILD) $(DEFS) -o $@ --debug -C$(SRCDIR) $(C_SRCS) $(C_SRCS16) + +# Rule to rebuild the tools + +$(MAKEDEP) $(WINEBUILD) $(WMC) $(WRC): + cd $(TOOLSDIR)/tools && $(MAKE) `basename $@` + +# Rules for makefile + +Makefile: Makefile.in $(TOPSRCDIR)/configure + @echo Makefile is older than $?, please rerun $(TOPSRCDIR)/configure + @exit 1 + +# Rules for auto documentation + +$(SUBDIRS:%=%/__man__): dummy + cd `dirname $@` && $(MAKE) man + +man: $(C_SRCS) $(SUBDIRS:%=%/__man__) + if [ -n "$(C_SRCS)" ]; then $(MKINSTALLDIRS) $(TOPOBJDIR)/documentation/man3w; for i in $(C_SRCS); do $(C2MAN) -L -o $(TOPOBJDIR)/documentation/man3w -S3w $(DIVINCL) -D__WINE__ $(MANSPECS) $$i; done; fi + +$(SUBDIRS:%=%/__doc_html__): dummy + cd `dirname $@` && $(MAKE) doc-html + +doc-html: $(C_SRCS) $(SUBDIRS:%=%/__doc_html__) + if [ -n "$(C_SRCS)" ]; then $(MKINSTALLDIRS) $(TOPOBJDIR)/documentation/html; for i in $(C_SRCS); do $(C2MAN) -L -o $(TOPOBJDIR)/documentation/html -Th -iwindows.h $(DIVINCL) -D__WINE__ $(MANSPECS) $$i; done; fi + +.PHONY: man doc-html $(SUBDIRS:%=%/__man__) $(SUBDIRS:%=%/__doc_html__) + +# Rule for linting + +$(MODULE).ln : $(LINTS) + if test "$(LINTS)" ; \ + then \ + $(LINT) $(ALLLINTFLAGS) -o$(MODULE) $(LINTS) ; \ + $(MV) llib-l$(MODULE).ln $(MODULE).ln ; \ + else \ + $(LINT) $(ALLLINTFLAGS) -C$(MODULE) /dev/null ; \ + fi + +lint:: $(MODULE).ln + +# Rules for Windows API checking + +winapi_check:: dummy + $(WINAPI_CHECK) $(WINAPI_CHECK_FLAGS) $(WINAPI_CHECK_EXTRA_FLAGS) . + +.PHONY: winapi_check + +# Rules for dependencies + +$(SUBDIRS:%=%/__depend__): $(MAKEDEP) dummy + cd `dirname $@` && $(MAKE) depend + +depend: $(MAKEDEP) $(SUBDIRS:%=%/__depend__) + $(MAKEDEP) $(DIVINCL) -C$(SRCDIR) $(C_SRCS) $(C_SRCS16) $(RC_SRCS) $(RC_SRCS16) $(MC_SRCS) $(EXTRA_SRCS) + +.PHONY: depend $(SUBDIRS:%=%/__depend__) + +# Rules for cleaning + +$(SUBDIRS:%=%/__clean__): dummy + cd `dirname $@` && $(MAKE) clean + +$(SUBDIRS:%=%/__testclean__): dummy + cd `dirname $@` && $(MAKE) testclean + +$(EXTRASUBDIRS:%=%/__clean__): dummy + -cd `dirname $@` && $(RM) $(CLEAN_FILES) + +testclean:: $(SUBDIRS:%=%/__testclean__) + +clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__) + $(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(RC_SRCS16:.rc=.res) $(MC_SRCS:.mc=.mc.rc) $(PROGRAMS) + +.PHONY: clean testclean $(SUBDIRS:%=%/__clean__) $(SUBDIRS:%=%/__testclean__) $(EXTRASUBDIRS:%=%/__clean__) + +# Rules for installing + +$(INSTALLSUBDIRS:%=%/__install__): dummy + cd `dirname $@` && $(MAKE) install + +$(INSTALLSUBDIRS:%=%/__uninstall__): dummy + cd `dirname $@` && $(MAKE) uninstall + +install:: $(INSTALLSUBDIRS:%=%/__install__) + +uninstall:: $(INSTALLSUBDIRS:%=%/__uninstall__) + +.PHONY: install install-lib install-dev uninstall \ + $(INSTALLSUBDIRS:%=%/__install__) $(INSTALLSUBDIRS:%=%/__uninstall__) + +# Rules for checking that no imports are missing + +$(SUBDIRS:%=%/__checklink__): dummy + @cd `dirname $@` && $(MAKE) checklink + +.PHONY: checklink $(SUBDIRS:%=%/__checklink__) + +# Rules for testing + +$(SUBDIRS:%=%/__test__): dummy + @cd `dirname $@` && $(MAKE) test + +$(SUBDIRS:%=%/__crosstest__): dummy + @cd `dirname $@` && $(MAKE) crosstest + +.PHONY: check test crosstest $(SUBDIRS:%=%/__test__) $(SUBDIRS:%=%/__crosstest__) + +# Misc. rules + +$(SPEC_SRCS:.spec=.spec.c): $(WINEBUILD) + +$(RC_SRCS:.rc=.res): $(WRC) + +$(RC_SRCS16:.rc=.res): $(WRC) + +$(MC_SRCS:.mc=.mc.rc): $(WMC) + +$(SUBDIRS): dummy + @cd $@ && $(MAKE) + +dummy: + +.PHONY: dummy $(SUBDIRS) + +# End of global rules + +all: $(MODULE)$(DLLEXT) $(BASEMODULE)$(EXEEXT) + +# Rule for main module spec file + +$(MODULE).spec.c: $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(WINEBUILD) + $(LDPATH) $(WINEBUILD) $(DEFS) -o $@ --exe $(MODULE) $(APPMODE:%=-m%) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%) + +# Rules for .so main module + +$(MODULE).so: $(MODULE).spec.o $(ALL_OBJS) Makefile.in + $(LDSHARED) $(LDDLLFLAGS) $(MODULE).spec.o $(ALL_OBJS) -o $@ $(ALL_LIBS) -lc + +$(BASEMODULE): $(WINEWRAPPER) + $(RM) $@ && $(LN_S) $(WINEWRAPPER) $@ + +# Rules for .exe main module + +$(MODULE): $(ALL_OBJS) $(RCOBJS) Makefile.in + $(CC) $(ALL_OBJS) $(RCOBJS) -o $@ $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(ALL_LIBS) + +# Rules for testing + +check test:: $(SUBDIRS:%=%/__test__) + +$(TESTRESULTS): $(MODULE)$(DLLEXT) + +# Rules for installation + +.PHONY: install_prog install_prog.so uninstall_prog uninstall_prog.so + +install_prog.so: $(MODULE).so dummy + $(MKINSTALLDIRS) $(dlldir) + $(INSTALL_PROGRAM) $(MODULE).so $(dlldir)/$(MODULE).so + +install_prog: $(MODULE) dummy + $(MKINSTALLDIRS) $(bindir) + $(INSTALL_PROGRAM) $(MODULE) $(bindir)/$(MODULE) + +uninstall_prog.so: dummy + $(RM) $(dlldir)/$(MODULE).so + +uninstall_prog: dummy + $(RM) $(bindir)/$(MODULE) + +install:: install_prog$(DLLEXT) + +uninstall:: uninstall_prog$(DLLEXT) + +clean:: + $(RM) $(BASEMODULE) $(MODULE) + +### Dependencies: --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/Makefile.in 2002-05-24 22:31:01.000000000 +0300 @@ -0,0 +1,16 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = wineboot.exe +APPMODE = cui +IMPORTS = user32 advapi32 kernel32 ntdll + +C_SRCS = \ + wineboot.c + +RC_SRCS = rsrc.rc + +@MAKE_PROG_RULES@ + +### Dependencies: --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/README 2002-04-06 12:58:17.000000000 +0300 @@ -0,0 +1,17 @@ +wineboot README + +wineboot, copyright 2001, Andreas Mohr +wineboot is to be distributed under the Wine License +See the Wine License for further information. + +This is a Winelib application that's executed by Wine on startup of the +first wine process of a particular user. + +TODO: + - a lot + +KNOWN BUGS: + - nothing + +UNKNOWN BUGS: + ??? --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/rsrc.rc 2002-04-06 12:57:30.000000000 +0300 @@ -0,0 +1,88 @@ +/* + * wineboot (rsrc.rc) + * + * Copyright 2001 Andreas Mohr <andi@lisas.de> + * To be distributed under the Wine License + */ + +#include <windows.h> +#include "wineboot.h" + +WINEBOOTUP ICON MOVEABLE +{ + '00 00 01 00 01 00 20 20 10 00 00 00 00 00 E8 02' + '00 00 16 00 00 00 28 00 00 00 20 00 00 00 40 00' + '00 00 01 00 04 00 00 00 00 00 00 02 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 80 00 00 80 00 00 00 80 80 00 80 00' + '00 00 80 00 80 00 80 80 00 00 80 80 80 00 C0 C0' + 'C0 00 00 00 FF 00 00 FF 00 00 00 FF FF 00 FF 00' + '00 00 FF 00 FF 00 FF FF 00 00 FF FF FF 00 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22' + '22 22 22 22 20 00 00 02 22 22 22 22 22 22 22 22' + '22 22 22 22 22 00 00 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 20 07 77 70 07 77 70 02 22 22 22 22 22 22' + '22 22 20 07 77 00 07 77 70 02 22 22 22 22 22 22' + '22 22 27 70 00 00 00 00 07 72 22 22 22 22 22 22' + '22 22 27 70 00 00 00 00 07 72 22 22 22 22 22 22' + '20 22 27 70 00 00 00 00 07 72 22 02 22 22 22 22' + '00 02 27 00 00 00 00 00 07 72 20 00 22 22 22 20' + '00 00 00 00 00 00 00 00 00 00 00 00 02 22 22 20' + '00 00 00 00 00 00 00 00 00 00 00 00 02 22 22 22' + '00 02 27 00 00 00 0F F0 08 82 20 00 22 22 22 22' + '20 22 27 70 00 00 0F F0 08 82 20 02 22 22 22 22' + '22 22 27 70 00 00 00 F0 08 82 22 22 22 22 22 22' + '22 22 27 70 00 00 00 00 08 82 22 22 22 22 22 22' + '22 22 20 07 77 00 00 88 80 02 22 22 22 22 22 22' + '22 22 20 07 78 80 08 88 80 02 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 20 02 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 00 00 22 22 22 22 22 22 22 22 22' + '22 22 22 22 20 00 00 02 22 22 22 22 22 22 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22' + '22 22 22 22 22 22 22 22 22 22 22 22 22 22 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00' +} + +/* English-US Resources */ +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE { + IDS_APPNAME, "wineboot" + +} + +LANGUAGE 0,0 + +BOOTUPNOTIFY DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 300, 125 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_SYSMENU | WS_VISIBLE | WS_CAPTION +CAPTION "Wine boot notification" +FONT 9, "MS Sans Serif" +BEGIN + LTEXT "msgtext", IDMSG, 15, 10, 220, 65 + PUSHBUTTON "Btn 1", IDBUTTON1, 240, 10, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "Btn 2", IDBUTTON2, 240, 30, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "Btn 3", IDBUTTON3, 240, 50, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "About", IDABOUT, 240, 80, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "Setup", IDSETUP, 240, 100, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "Check 1", IDCHK1, 5, 90, 210, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX + PUSHBUTTON "Check 2", IDCHK2, 5, 105, 210, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX +END + +/* End of English-US Resources */ --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/wineboot.c 2002-11-21 23:16:07.000000000 +0200 @@ -0,0 +1,995 @@ +/* + * Wine bootup handler application + * + * Copyright 2001 Andreas Mohr + * To be distributed under the Wine License + * + * Used for running several Windows startup processes, e.g.: + * - wininit.ini processing + * - registry RenameFiles entries + * - RunServices* / RunOnce* / Run registry keys + * - win.ini Load= / Run= entries + * - StartUp folder processing + * - probably other stuff that's NIY + * + * For a description of some parts of the Windows bootup process, + * see the following MS KB articles: + * + * Q137367 Definition of the RunOnce Keys in the Registry + * Q179365 Run, RunOnce, RunServices, RunServicesOnce and Startup + * Q232487 Description of RunOnceEx Registry Key + * Q232509 Syntax for the RunOnceEx Registry Key + * + * And for StartUp folder stuff, see: + * http://cpcug.org/user/clemenzi/technical/Win_95_Registry.htm + * + * The autorun registry keys are all located in the following subkey string: + * Software\Microsoft\Windows\CurrentVersion + * ("KEY_CV" from now on) + * + * The bootup order is as follows: + * + * - < DOS bootup > + * + * - wininit.ini (done by DOS program wininit.exe) + * + * - < GUI init > + * + * - HKLM RunServicesOnce + * HKLM\KEY_CV\RunServicesOnce + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * - HKLM RunServices + * HKLM\KEY_CV\RunServices + * CWD: dir where windows got started from (usually C:\) + * + * *** stuff done by win32 program runonce.exe *** + * + * - RenameFiles + * + * - HKLM RunOnce (not in NT 3.51 ! Waiting for program exit) + * HKLM\KEY_CV\RunOnce + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * *** end runonce.exe *** + * + * - HKLM RunOnceEx (from Win98 / "Windows Desktop Update" on only. Waiting + * for program exit) + * HKLM\KEY_CV\RunOnceEx + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * - < Logon Prompt > + * + * - win.ini [Windows] Load= line (minimized loading !) + * CWD: program dir + * + * - win.ini [Windows] Run= line (normal loading !) + * CWD: program dir + * + * - HKLM Run + * HKLM\KEY_CV\Run + * CWD: C:\WINDOWS + * + * - HKCU Run + * HKCU\KEY_CV\Run + * CWD: C:\WINDOWS + * + * - Common Startup folder + * HKLM\KEY_CV\Explorer\Shell Folders\Common Startup + * CWD: program dir + * + * - User Startup folder + * HKCU\KEY_CV\Explorer\Shell Folders\Startup + * CWD: FIXME ! + * + * - HKCU RunOnce + * HKCU\KEY_CV\RunOnce + * CWD: C:\WINDOWS + * + * known runonce.exe switches: + * -a + * unknown behaviour, FIXME. + * -m + * used by Windows on bootup: + * C:\WINDOWS\SYSTEM\runonce.exe -m + * CWD is C:\ (hmm, or rather windows startup dir ? FIXME) + * maybe -m means msgsvr32 ?? (when calling runonce.exe without -m, + * it complains that it's not being called via msgsvr32) + * -q + * unknown behaviour, FIXME. + * + * FIXME: + * - what about NT key "HKLM\CurrentControlSet\Control\Session Manager" ? + * - PendingRenameOperations:REG_MULTI_SZ key ? + * Where exactly should this one be processed ? + * - Where is DeleteFiles and PreConvRenameFiles being started ? + * - What about HKCU RunServicesOnce ? + * - RunOnce and RunOnceEx entries seem to be able to contain non-program + * entries, too, e.g.: "FlushRegistry" + * + * TODO (in order of importance): + * - wininit.ini case insensitive !! + * - every key getting deleted properly ? + * - verify everything + * - test verbose, quiet mode + * - add some config variables to be able to specify external shell scripts + * for GUI mode interaction ? should be a cool idea. + * - use proper CWDs when executing stuff + * - execute native runonce.exe if available ? (at NO_RUNONCE_BINARY define) + * - test misc. switches of runonce.exe + * - check #includes needed + * - grep for FIXME !! + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <windows.h> +#include "wineboot.h" +#include "regstr.h" +#include "file.h" + +/* Work around a Wine bug which defines handles as UINT rather than LPVOID */ +#ifdef WINE_STRICT +#define NULL_HANDLE NULL +#else +#define NULL_HANDLE 0 +#endif + +/* this needs to remain in this file due to unsupported yet variable argument + * macros in wrc. ugh. */ +#define MESSAGE(x...) fprintf(stderr, x) +#define TRACE(x...) if (BF_Verbose) fprintf(stderr, x) +#define WARN(x...) fprintf(stderr, x) +#define FIXME(x...) fprintf(stderr, x) +#define ERR(x...) fprintf(stderr, x) + + /* Filename for Profile_WinInit */ +static const char *wininitini = "wininit.ini"; +static const char *wininitbak = "wininit.bak"; + +static HKEY hkeyCfg = 0; +static HKEY hkeyHKLM_CV = 0; +static HKEY hkeyHKCU_CV = 0; + +static char *do_it; +#if BOOT_PROFILING +static DWORD BOOT_startticks; +#endif +static BOOL BOOT_started = FALSE; +static BOOL BOOT_viruswarn = FALSE; + +#define CFGS_0 0x0000 +#define CFGS_LOADED 0x0001 +#define CFGS_NOTAVAIL 0x0002 +#define CFGS_MODIFIED 0x0004 + +typedef struct { + LPSTR name; + BOOL value; + DWORD status; +} BOOT_CONFIG; + +BOOT_CONFIG BOOT_Config[] = +{ + /* enable the whole thing */ + {"BootConfig_Enable", TRUE, CFGS_0 }, + + /* do a dry run, i.e. show what to do, but don't act */ + {"BootConfig_DryRun", FALSE, CFGS_0 }, + + /* extra verbosity on console */ + {"BootConfig_TTY_Verbose", FALSE, CFGS_0 }, + + /* extra quiet on console */ + {"BootConfig_TTY_Quiet", FALSE, CFGS_0 }, + + /* process wininit.ini ? */ + {"WininitIni_Execute", TRUE, CFGS_0 }, + + {"RunServicesOnce_Execute", TRUE, CFGS_0 }, + {"RunServicesHKLM_Execute", TRUE, CFGS_0 }, + {"RenameFiles_Execute", TRUE, CFGS_0 }, + {"RunOnceHKLM_Execute", TRUE, CFGS_0 }, + {"RunOnceEx_Execute", TRUE, CFGS_0 }, + {"WinIniLoad_Execute", TRUE, CFGS_0 }, + {"WinIniRun_Execute", TRUE, CFGS_0 }, + {"RunHKLM_Execute", TRUE, CFGS_0 }, + {"RunHKCU_Execute", TRUE, CFGS_0 }, + {"StartupFolderCommon_Execute", FALSE, CFGS_0 }, + {"StartupFolderUser_Execute", FALSE, CFGS_0 }, + {"RunOnceHKCU_Execute", TRUE, CFGS_0 }, +}; + +enum { + CFG_ENABLE = 0, + CFG_DRYRUN, + CFG_TTY_VERBOSE, + CFG_TTY_QUIET, + CFG_WININIT_EXECUTE, + CFG_RSO_EXECUTE, + CFG_RSHKLM_EXECUTE, + CFG_RENAMEFILES_EXECUTE, + CFG_ROHKLM_EXECUTE, + CFG_ROEX_EXECUTE, + CFG_WININILOAD_EXECUTE, + CFG_WININIRUN_EXECUTE, + CFG_RUNHKLM_EXECUTE, + CFG_RUNHKCU_EXECUTE, + CFG_SFC_EXECUTE, + CFG_SFU_EXECUTE, + CFG_ROHKCU_EXECUTE, +}; + +static BOOL BF_DryRun; +static BOOL BF_Verbose; +static BOOL BF_Quiet; + +typedef struct { + LPSTR text_msg; + LPSTR text_shutup; + DWORD flags; + DWORD retval; +} NB_DATA; + +DWORD BOOT_NotifyBox_Show(LPSTR, LPSTR, DWORD); + +/**************************** generic stuff start *****************************/ +static BOOL BOOT_ReadConfig(DWORD what) +{ + char buffer[16]; + DWORD type, count = sizeof(buffer); + BOOL active = FALSE; + + if (!hkeyCfg) + if(RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\wineboot", &hkeyCfg) != ERROR_SUCCESS) + { + TRACE("Failed to open wineboot config registry key !!\n"); + return 0; + } + buffer[0] = '\0'; + if (RegQueryValueExA(hkeyCfg, BOOT_Config[what].name, 0, &type, buffer, &count) == ERROR_SUCCESS) + { + switch (toupper(buffer[0])) + { + case 'N': + case 'F': + case '0': + active = FALSE; + break; + case 'Y': + case 'T': + case '1': + active = TRUE; + break; + } + BOOT_Config[what].value = active; + BOOT_Config[what].status |= CFGS_LOADED; + } + else + BOOT_Config[what].status |= CFGS_NOTAVAIL; + TRACE("Got config param '%s': '%s'\n", BOOT_Config[what].name, buffer); + return BOOT_Config[what].value; +} + +static void BOOT_WriteConfig(DWORD what, BOOL value) +{ + char buffer[2]; + + buffer[0] = (value) ? 'Y' : 'N'; + buffer[1] = '\0'; + + if (RegSetValueExA(hkeyCfg, BOOT_Config[what].name, 0, REG_SZ, buffer, 2) != ERROR_SUCCESS) + ERR("writing Config item '%s' failed !!\n", BOOT_Config[what].name); +} + +static void BOOT_StartMessages(BOOL do_virus) +{ + if (!BOOT_started) + { +#if BOOT_PROFILING + BOOT_startticks = GetTickCount(); +#endif + if (!(BF_Quiet)) + MESSAGE("************************ Wine bootup processing starting ***********************\n"); + BOOT_started = TRUE; + } + + /* we don't want Wine to become the primary choice of myriads of virii + * after all the Outlock and IIS crap that happened in the last decade... + */ + if ((!BOOT_viruswarn) && (do_virus)) + { + /* yeah, yell at people in order to hopefully make a slight difference + * between possibly thousands of bootup messages... */ + MESSAGE("BOOT: WARNING: at least one permanent Run/RunServices/Run=/Load=/StartUp Autorun entry detected !\n*** MAKE SURE THAT THE PROGRAMS STARTED HERE ARE NO VIRII ! ***\nIn case you're suspicious, search e.g. www.google.com for the executable name."); + BOOT_viruswarn = TRUE; + } +} + +static void BOOT_FinishMessage(void) +{ + if (!(BF_Quiet)) +#if BOOT_PROFILING + MESSAGE("************ Wine bootup processing finished (%08ld milliseconds) ***********\n", GetTickCount() - BOOT_startticks); +#else + MESSAGE("*********************** Wine bootup processing finished ************************\n"); +#endif +} + +/* BOOT_RegStuff_AddToKill() + * When enumerating keys, we may not disrupt our current enumeration's key + * infrastructure. Thus we must delay deletion */ +static void *del_buffer = NULL; +static DWORD del_buffer_size = 0; +static DWORD del_buffer_filled = 0; +void BOOT_RegStuff_AddToKill(HKEY hkeyParent, BOOL is_key, LPSTR what) +{ +#define DEL_BUFFER_STEP 4096 + DWORD nextsize; + char *p; + + TRACE("registering %s '%s' of hkey %p for delayed deletion.\n", + is_key ? "subkey" : "value", what, hkeyParent); + nextsize = del_buffer_filled + sizeof(hkeyParent) + sizeof(is_key) + strlen(what)+1; + if (del_buffer_size < nextsize) + { + del_buffer = HeapReAlloc(GetProcessHeap(), 0, del_buffer, nextsize + DEL_BUFFER_STEP); + if (!del_buffer) + { + ERR("HeapReAlloc of del_buffer failed !!!\n"); + del_buffer_size = del_buffer_filled = 0; + return; + } + else + del_buffer_size = nextsize + DEL_BUFFER_STEP; + } + p = del_buffer; + p += del_buffer_filled; + + *(HKEY *)p = hkeyParent; + p += sizeof(HKEY); + *(BOOL *)p = is_key; + p += sizeof(BOOL); + strcpy(p, what); + p += strlen(what)+1; + + del_buffer_filled = nextsize; +} + +void BOOT_RegStuff_KillDelayed() +{ + char *p; + HKEY hkeyParent; + BOOL is_key; + + if ((BF_DryRun) || (!del_buffer)) + return; + + p = del_buffer; + do { + hkeyParent = *(HKEY *)p; + p += sizeof(HKEY); + is_key = *(BOOL *)p; + p += sizeof(BOOL); + TRACE("delayed deletion of %s '%s' of hkey %p.\n", + is_key ? "subkey" : "value", p, hkeyParent); + if (is_key) + RegDeleteKeyA(hkeyParent, p); + else + RegDeleteValueA(hkeyParent, p); + p += strlen(p)+1; + } while (p < (char *)(del_buffer + del_buffer_filled)); + + del_buffer_filled = 0; +} + +void BOOT_RegStuff_Cleanup() +{ + if (del_buffer) + HeapFree(GetProcessHeap(), 0, del_buffer); +} + +static BOOL BOOT_CreateProcess(LPSTR filename, LPSTR dir, BOOL wait, BOOL minimized) +{ + BOOL res; + STARTUPINFOA si; + PROCESS_INFORMATION info; + DWORD exit_code; + + if (BF_DryRun) + return TRUE; + + memset(&si, 0, sizeof(si)); + memset(&info, 0, sizeof(info)); + res = CreateProcessA(NULL, filename, NULL, NULL, FALSE, 0, NULL, dir, &si, &info); + if ((wait) && (res == TRUE)) + { /* wait for the process to exit */ + WaitForSingleObject(info.hProcess, INFINITE); + res = GetExitCodeProcess(info.hProcess, &exit_code); + return exit_code; + } + if ((!res) && (!(BF_Quiet))) + MESSAGE("BOOT: failed to run '%s' !\n", filename); + + return res; +} + +#define USE_HKCU TRUE +#define USE_HKLM FALSE + +static inline BOOL BOOT_OpenReg_CurrVer(BOOL hkcu) +{ + HKEY hkeyroot; + HKEY *phkey; + + if ((hkcu && !hkeyHKCU_CV) || (!hkcu && !hkeyHKLM_CV)) + { + hkeyroot = hkcu ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; + phkey = hkcu ? &hkeyHKCU_CV : &hkeyHKLM_CV; + + return (RegOpenKeyA(hkeyroot, "Software\\Microsoft\\Windows\\CurrentVersion", phkey) == ERROR_SUCCESS); + } + return TRUE; +} + +static void BOOT_CloseRegistry(void) +{ + int i; + + for (i=0; i < (sizeof(BOOT_Config)/sizeof(BOOT_CONFIG)); i++) + WRITE_CONFIG(i); + + if (hkeyHKLM_CV) RegCloseKey(hkeyHKLM_CV); + if (hkeyHKCU_CV) RegCloseKey(hkeyHKCU_CV); + if (hkeyCfg) RegCloseKey(hkeyCfg); +} +/**************************** generic stuff end *******************************/ + + +/************************************************** + * BOOT_ProcessWininitIni + * + * Process wininit.ini hopefully like wininit.exe does + * Originally created by Uwe Bonnes + */ +static void BOOT_WininitIni(void) +{ + int i,j=0,k=0; + char *buffer=NULL,*p; + char inifile[MAX_PATHNAME_LEN],bakfile[MAX_PATHNAME_LEN]; + + TRACE("%sProcessing wininit.ini\n", do_it); + buffer = HeapReAlloc( GetProcessHeap(), 0, buffer,(j++ +1)*1024 ); + while (1) + { + if ((k) && !(BF_Quiet)) + FIXME("Some previous programs produced wininit.ini in different case\n"); + i = GetPrivateProfileStringA(NULL,NULL,"",buffer,(j)*1024,wininitini); + if(i<2) + { + TRACE("No (more) %s present\n",wininitini); + break; + } + BOOT_StartMessages(VIRUS_NOWARN); + + /* Check if there are other sections in the ini file beside the rename section */ + for (p=buffer; *p; p= p + lstrlenA(p) +1) + { + if (strcasecmp(p,"rename")) + { + WARN("Unknown section [%s]\n",p); + WARN("Processing anyway\n"); + } + } + /* Maybe the section is damn long. Try to cope with that */ + while (1) + { + i = GetPrivateProfileStringA("rename",NULL,"",buffer,(j)*1024,wininitini); + if (i < ((j)*1024)-1) + break; + buffer = HeapReAlloc( GetProcessHeap(), 0, buffer,(j++ +1)*1024 ); + if (!buffer) + { + ERR("Failed to allocate needed space for scanning %s\n",wininitini); + return; + } + } + /* NUL means delete, otherwise move */ + for (p=buffer; *p; p= p + lstrlenA(p) +1) + { + i = GetPrivateProfileStringA("rename",p,"",inifile,MAX_PATHNAME_LEN,wininitini); + if (i > MAX_PATHNAME_LEN - 1) + WARN("Filename too long\n"); + else + { + BOOL delete = (!strcasecmp(p,"NUL")); + + if (delete) + { + TRACE("%sdeleting %s\n",do_it,inifile); + if (!(BF_DryRun)) + DeleteFileA(inifile); + } + else + { + TRACE("%srenaming %s to %s\n",do_it,inifile,p); + if (!(BF_DryRun)) + MoveFileExA(inifile,p,MOVEFILE_REPLACE_EXISTING); + } + } + } + GetWindowsDirectoryA(inifile,MAX_PATHNAME_LEN); + lstrcpynA(inifile+lstrlenA(inifile),"\\",MAX_PATHNAME_LEN-lstrlenA(inifile)); + lstrcpynA(bakfile,inifile,MAX_PATHNAME_LEN); + lstrcpynA(inifile+lstrlenA(inifile),wininitini,MAX_PATHNAME_LEN-1-lstrlenA(inifile)); + lstrcpynA(bakfile+lstrlenA(bakfile),wininitbak,MAX_PATHNAME_LEN-1-lstrlenA(bakfile)); + if (k) + sprintf(bakfile,"%s%d",bakfile,k); + TRACE(" %sMoving %s to %s\n",do_it,inifile,bakfile); + if (!(BF_DryRun)) + MoveFileExA(inifile,bakfile,MOVEFILE_REPLACE_EXISTING); + k++; + } + TRACE("BOOT: %s processing finished.\n", wininitini); + return; +} + +static void BOOT_Registry_FileOps(void) +{ + HKEY hkeyRF, hkey; + DWORD type, count; + CHAR subkey_buf[256], name_buf[256], value_buf[256]; + CHAR path[MAX_PATHNAME_LEN], src[MAX_PATHNAME_LEN], dest[MAX_PATHNAME_LEN]; + DWORD name_len, value_len, subkey_len; + DWORD dwIndex, postpath = 0, flags, res; + FILETIME ft; + int i; + LPSTR p; + + BOOT_OpenReg_CurrVer(USE_HKLM); + + if (RegOpenKeyA(hkeyHKLM_CV, "RenameFiles", &hkeyRF) != ERROR_SUCCESS) + { + TRACE("RenameFiles key not found, nothing to do.\n"); + return; + } + + BOOT_StartMessages(VIRUS_NOWARN); + + subkey_len = sizeof(subkey_buf); + /* Traverse all RenameFiles subkey entries we have available */ + for( dwIndex=0; + (res = RegEnumKeyExA( hkeyRF, dwIndex, subkey_buf, &subkey_len, + NULL, NULL, NULL, &ft )) != ERROR_NO_MORE_ITEMS; + ++dwIndex, subkey_len = sizeof(subkey_buf) ) + { + TRACE("BOOT: found RenameFiles subkey '%s', res %lx\n", subkey_buf, res); + + if (RegOpenKeyA(hkeyRF, subkey_buf, &hkey) != ERROR_SUCCESS) + { + MESSAGE("BOOT: can't open RenameFiles '%s' subkey !!\n", subkey_buf); + continue; + } + + count = sizeof(path); + if ((RegQueryValueExA(hkey, NULL, 0, &type, path, &count) != ERROR_SUCCESS) + || (type != REG_SZ)) + { + FIXME("RenameFiles subkey '%s': path setting not found. What to do ???\n", subkey_buf); + *path = '\0'; + } + else + { + MESSAGE("found path setting '%s'.\n", path); + postpath = strlen(path); + if (postpath) + { + path[postpath++] = '\\'; + path[postpath] = '\0'; + } + strcpy(src, path); + strcpy(dest, path); + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + if (*name_buf == '\0') + goto next_entry; + + if (!(BF_Quiet)) + MESSAGE("BOOT: %sprocessing RenameFiles subkey '%s' entry: '%s': '%s'\n", + do_it, subkey_buf, name_buf, value_buf); + + if ((p = strchr(value_buf, ','))) + { + *p = '\0'; + p++; + flags = atoi(p); /* file attribute flags: FILE_ATTRIBUTE_xxx */ + TRACE("found file attribute flags: 0x%lx !\n", flags); + } + else + flags = 0; + strcpy(&src[postpath], name_buf); + if (value_buf[0] != '\0') + strcpy(&dest[postpath], value_buf); + else + strcpy(&dest[postpath], name_buf); + + if (!(BF_DryRun)) + { + if (!MoveFileExA(src,dest,MOVEFILE_REPLACE_EXISTING)) + if (!(BF_Quiet)) + ERR("Can't rename file '%s' as '%s' (GLE %ld) ! Please investigate.\n", src, dest, GetLastError()); + if (flags) + SetFileAttributesA(dest, flags); + } + +next_entry: + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + RegCloseKey(hkey); + + BOOT_RegStuff_AddToKill(hkeyRF, TRUE, subkey_buf); + } + BOOT_RegStuff_KillDelayed(); + + RegCloseKey(hkeyRF); + RegDeleteKeyA(hkeyHKLM_CV, "RenameFiles"); +} + +static void BOOT_Registry_RunStuff(BOOL hkcu, BOOL runonce, BOOL services, BOOL wait_exit) +{ + HKEY hkey, hkeyCV; + CHAR name_buf[256], value_buf[256], *run_what, *what_root, cwd[MAX_PATHNAME_LEN]; + DWORD name_len, value_len; + DWORD type; + int i; + + BOOT_OpenReg_CurrVer(hkcu); + + if (services) + { + if (runonce) + run_what = "RunServicesOnce"; + else + run_what = "RunServices"; + } + else + { + if (runonce) + run_what = "RunOnce"; + else + run_what = "Run"; + } + + hkeyCV = hkcu ? hkeyHKCU_CV : hkeyHKLM_CV; + what_root = hkcu ? "HKCU" : "HKLM"; + if ((!services) && (!runonce)) /* Run */ + GetWindowsDirectoryA(cwd, sizeof(cwd)); + else + strcpy(cwd, "C:\\"); + + if (RegOpenKeyA(hkeyCV, run_what, &hkey)) + { + TRACE("'%s' key not found, nothing to do.\n", run_what); + return; + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + if (type == REG_SZ) + { + value_buf[sizeof(value_buf) - 1] = '\0'; + + BOOT_StartMessages(VIRUS_WARN); + + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning '%s %s' entry '%s': '%s'\n", + do_it, what_root, run_what, name_buf, value_buf); + BOOT_CreateProcess(value_buf, cwd, wait_exit, PROCESS_MAXIMIZED); + } + if (runonce) + /* tests indicate that deletion probably is unconditionally */ + BOOT_RegStuff_AddToKill(hkey, FALSE, name_buf); + + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + + /* now that we're finished, kill accumulated entries */ + BOOT_RegStuff_KillDelayed(); + + RegCloseKey(hkey); +} + +static void BOOT_Registry_RunOnceEx(void) +{ + HKEY hkeyROEx, hkey, hkeyDepend = 0; + DWORD type, count; + CHAR name_buf[256], value_buf[256], subkey_buf[256]; + DWORD ROEx_flags = 0; + CHAR ROEx_title[256]; /* FIXME ? */ + DWORD name_len, value_len, subkey_len; + DWORD dwIndex; + FILETIME ft; + int i; + + TRACE("BOOT: FIXME: a lot of non-basic RunOnceEx functionality NIY !\n"); + + BOOT_OpenReg_CurrVer(USE_HKLM); + + if (RegOpenKeyA(hkeyHKLM_CV, "RunOnceEx", &hkeyROEx)) + { + TRACE("BOOT: no RunOnceEx registry entries to process.\n"); + return; + } + + BOOT_StartMessages(VIRUS_NOWARN); + + type = REG_DWORD; + count = sizeof(ROEx_flags); + if (RegQueryValueExA(hkeyROEx, "Flags", 0, &type, (LPBYTE)&ROEx_flags, &count) == ERROR_SUCCESS) + TRACE("BOOT: got RunOnceEx \"Flags\" 0x%lx\n", ROEx_flags); + + type = REG_SZ; + count = sizeof(ROEx_title); + if (RegQueryValueExA(hkeyROEx, "Flags", 0, &type, ROEx_title, &count) == ERROR_SUCCESS) + TRACE("BOOT: got RunOnceEx \"Title\" '%s'\n", ROEx_title); + + if (RegOpenKeyA(hkeyROEx, "Depend", &hkeyDepend)) + TRACE("BOOT: found RunOnceEx \"Depend\" section.\n"); + + subkey_len = sizeof(subkey_buf); + + /* Traverse all ROEx subkey entries that we have available */ + for( dwIndex=0; + RegEnumKeyExA( hkeyROEx, dwIndex, subkey_buf, &subkey_len, + NULL, NULL, NULL, &ft ) != ERROR_NO_MORE_ITEMS; + ++dwIndex, subkey_len = sizeof(subkey_buf) ) + { + /* skip "Depend" key */ + if (!(strcasecmp(name_buf, "Depend"))) + continue; + + TRACE("BOOT: found '%s'\n", subkey_buf); + + if (RegOpenKeyA(hkeyROEx, subkey_buf, &hkey) != ERROR_SUCCESS) + { + MESSAGE("BOOT: can't open RunOnceEx '%s' subkey !!\n", subkey_buf); + continue; + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + /* we assume entries without '|' are normal program entries */ + if (!(strchr(value_buf, '|'))) + { + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning RunOnceEx entry '%s': '%s'\n", + do_it, name_buf, value_buf); + BOOT_CreateProcess(value_buf, "C:\\", PROCESS_WAITEXIT, PROCESS_MAXIMIZED); + } + else + MESSAGE("BOOT: FIXME: HKLM RunOnceEx value '%s' ('%s') execution NIY !\n", name_buf, value_buf); + + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + RegCloseKey(hkey); + + BOOT_RegStuff_AddToKill(hkeyROEx, TRUE, subkey_buf); + } + BOOT_RegStuff_KillDelayed(); + + if (hkeyDepend) + RegCloseKey(hkeyDepend); + + RegCloseKey(hkeyROEx); +} + +static void BOOT_WinIni_Execute(BOOL do_load) +{ + char line_buf[1024]; /* FIXME ? */ + DWORD numchars; + char buf[MAX_PATH]; /* FIXME ? */ + char *p1, *p2; + + numchars = GetProfileStringA("windows", do_load ? "Load" : "Run", "", + line_buf, sizeof(line_buf)); + if (numchars) + { + BOOT_StartMessages(VIRUS_WARN); + p1 = p2 = line_buf; + + /* split the program entries in this line and run them */ + while (1) + { + while ((*p2 != ' ') && (*p2 != '\0') && (*p2 != '\t')) + p2++; + if ((int)p2 - (int)p1 > sizeof(buf) - 1) + FIXME("buffer problem !!\n"); + strncpy(buf, p1, (int)p2 - (int)p1); + buf[(int)p2 - (int)p1] = '\0'; + + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning win.ini %s= program entry '%s'\n", + do_it, do_load ? "Load" : "Run", buf); + + BOOT_CreateProcess(buf, NULL, PROCESS_NOWAITEXIT, do_load); + + if (*p2 == '\0') /* abort if end of line */ + break; + p2++; + p1 = p2; + } + } + return; +} + +static void BOOT_StartUpFolder(BOOL common_startup) +{ + HKEY hkey = 0, hkeyCV; + char *what_folder = (common_startup) ? "Common StartUp" : "StartUp"; + char startupdir[MAX_PATHNAME_LEN], buffer[MAX_PATHNAME_LEN]; /* FIXME: that ok ? */ + DWORD type, count; + + BOOT_OpenReg_CurrVer( common_startup ? USE_HKLM : USE_HKCU); + + hkeyCV = common_startup ? hkeyHKLM_CV : hkeyHKCU_CV; + + if(RegOpenKeyA(hkeyCV, "Explorer\\Shell Folders", &hkey) != ERROR_SUCCESS) + goto cleanup; + + count = sizeof(startupdir); + if (RegQueryValueExA(hkey, what_folder, 0, &type, startupdir, &count) != ERROR_SUCCESS) + goto cleanup; + + strcpy(buffer, startupdir); + + /* check whether \\*.* can be added to string */ + if (strlen(buffer)+1 < sizeof(buffer)-4) + { + HANDLE hFF; + WIN32_FIND_DATAA fd; + char *file_part, *p; + + /* add a marker for the file part */ + file_part = buffer+strlen(buffer); + *file_part = '\\'; file_part++; + + *file_part = '\0'; strcat(file_part, "*.*"); + + hFF = FindFirstFileA(buffer, &fd); + if (hFF != INVALID_HANDLE_VALUE) + do + { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + p = strrchr(fd.cFileName, '.'); + + if (p) + { + p++; + + if (!(strcasecmp(p, "exe"))) + { + BOOT_StartMessages(VIRUS_WARN); + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning file '%s' in %s folder\n", do_it, fd.cFileName, what_folder); + *file_part = '\0'; strcat(file_part, fd.cFileName); + + BOOT_CreateProcess(buffer, startupdir, PROCESS_NOWAITEXIT, PROCESS_MAXIMIZED); + } + else + if (!(BF_Quiet)) + FIXME("Processing of %s folder file '%s' NIY !\n", what_folder, fd.cFileName); + } + } + } + while (FindNextFileA(hFF, &fd)); + } + else + FIXME("buffer size problem !!\n"); + +cleanup: + if (hkey) RegCloseKey(hkey); + + return; +} + +int main (int argc, char *argv[]) +{ + +/* FIXME */ +#if 0 + /*------------------------------------------------------------------------ + ** Do the magic check + **----------------------------------------------------------------------*/ + if ((!cmdline) || (strlen(cmdline) < 9) || (memcmp(cmdline, "--yesdoit", 9))) + { + MESSAGE("Sorry, no go.\nThis program is intended to be called by Wine on bootup in order to do a lot of program startup tasks.\nIf you still intend to run this program standalone, then run it using 'wineboot -- --yesdoit'.\n"); + return 0; + } +#endif + + if (!GET_CONFIG(CFG_ENABLE)) + { + MESSAGE("Boot handling disabled in wine registry, won't proceed.\n"); + return 0; + } + + BF_DryRun = GET_CONFIG(CFG_DRYRUN); + BF_Verbose = GET_CONFIG(CFG_TTY_VERBOSE); + BF_Quiet = GET_CONFIG(CFG_TTY_QUIET); + + do_it = (BF_DryRun) ? "Not " : ""; + + if (GET_CONFIG(CFG_TTY_VERBOSE)) + BOOT_StartMessages(VIRUS_NOWARN); + + + if (GET_CONFIG(CFG_WININIT_EXECUTE)) + BOOT_WininitIni(); + + if (GET_CONFIG(CFG_RSO_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUNONCE, TRUE, PROCESS_NOWAITEXIT); + if (GET_CONFIG(CFG_RSHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUN, TRUE, PROCESS_NOWAITEXIT); + +#if NO_RUNONCE_BINARY + /* builtin runonce.exe begin */ + if (GET_CONFIG(CFG_RENAMEFILES_EXECUTE)) + BOOT_Registry_FileOps(); + + if (GET_CONFIG(CFG_ROHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUNONCE, FALSE, PROCESS_WAITEXIT); + /* runonce.exe end */ +#else + /* execute "runonce.exe -m", native Windows binary */ +#endif + + if (GET_CONFIG(CFG_ROEX_EXECUTE)) + BOOT_Registry_RunOnceEx(); + + if (GET_CONFIG(CFG_WININILOAD_EXECUTE)) + BOOT_WinIni_Execute(WININI_LOAD); + if (GET_CONFIG(CFG_WININIRUN_EXECUTE)) + BOOT_WinIni_Execute(WININI_RUN); + + if (GET_CONFIG(CFG_RUNHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUN, FALSE, PROCESS_NOWAITEXIT); + if (GET_CONFIG(CFG_RUNHKCU_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKCU, REG_RUN, FALSE, PROCESS_NOWAITEXIT); + + if (GET_CONFIG(CFG_SFC_EXECUTE)) + BOOT_StartUpFolder(STARTUP_COMMON); + if (GET_CONFIG(CFG_SFU_EXECUTE)) + BOOT_StartUpFolder(STARTUP_USER); + + if (GET_CONFIG(CFG_ROHKCU_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKCU, REG_RUNONCE, FALSE, PROCESS_NOWAITEXIT); + + BOOT_RegStuff_Cleanup(); + + BOOT_CloseRegistry(); + + if (BOOT_started) + BOOT_FinishMessage(); + + return 1; +} --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/wineboot.c.gui 2002-04-21 16:33:36.000000000 +0300 @@ -0,0 +1,1295 @@ +/* + * Wine bootup handler application + * + * Copyright 2001 Andreas Mohr + * To be distributed under the Wine License + * + * Used for running several Windows startup processes, e.g.: + * - wininit.ini processing + * - registry RenameFiles entries + * - RunServices* / RunOnce* / Run registry keys + * - win.ini Load= / Run= entries + * - StartUp folder processing + * - probably other stuff that's NIY + * + * For a description of some parts of the Windows bootup process, + * see the following MS KB articles: + * + * Q137367 Definition of the RunOnce Keys in the Registry + * Q179365 Run, RunOnce, RunServices, RunServicesOnce and Startup + * Q232487 Description of RunOnceEx Registry Key + * Q232509 Syntax for the RunOnceEx Registry Key + * + * And for StartUp folder stuff, see: + * http://cpcug.org/user/clemenzi/technical/Win_95_Registry.htm + * + * The autorun registry keys are all located in the following subkey string: + * Software\Microsoft\Windows\CurrentVersion + * ("KEY_CV" from now on) + * + * The bootup order is as follows: + * + * - < DOS bootup > + * + * - wininit.ini (done by DOS program wininit.exe) + * + * - < GUI init > + * + * - HKLM RunServicesOnce + * HKLM\KEY_CV\RunServicesOnce + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * - HKLM RunServices + * HKLM\KEY_CV\RunServices + * CWD: dir where windows got started from (usually C:\) + * + * *** stuff done by win32 program runonce.exe *** + * + * - RenameFiles + * + * - HKLM RunOnce (not in NT 3.51 ! Waiting for program exit) + * HKLM\KEY_CV\RunOnce + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * *** end runonce.exe *** + * + * - HKLM RunOnceEx (from Win98 / "Windows Desktop Update" on only. Waiting + * for program exit) + * HKLM\KEY_CV\RunOnceEx + * CWD: C:\ (hmm, or rather windows startup dir ? FIXME) + * + * - < Logon Prompt > + * + * - win.ini [Windows] Load= line (minimized loading !) + * CWD: program dir + * + * - win.ini [Windows] Run= line (normal loading !) + * CWD: program dir + * + * - HKLM Run + * HKLM\KEY_CV\Run + * CWD: C:\WINDOWS + * + * - HKCU Run + * HKCU\KEY_CV\Run + * CWD: C:\WINDOWS + * + * - Common Startup folder + * HKLM\KEY_CV\Explorer\Shell Folders\Common Startup + * CWD: program dir + * + * - User Startup folder + * HKCU\KEY_CV\Explorer\Shell Folders\Startup + * CWD: FIXME ! + * + * - HKCU RunOnce + * HKCU\KEY_CV\RunOnce + * CWD: C:\WINDOWS + * + * known runonce.exe switches: + * -a + * unknown behaviour, FIXME. + * -m + * used by Windows on bootup: + * C:\WINDOWS\SYSTEM\runonce.exe -m + * CWD is C:\ (hmm, or rather windows startup dir ? FIXME) + * maybe -m means msgsvr32 ?? (when calling runonce.exe without -m, + * it complains that it's not being called via msgsvr32) + * -q + * unknown behaviour, FIXME. + * + * FIXME: + * - what about NT key "HKLM\CurrentControlSet\Control\Session Manager" ? + * - PendingRenameOperations:REG_MULTI_SZ key ? + * Where exactly should this one be processed ? + * - Where is DeleteFiles and PreConvRenameFiles being started ? + * - What about HKCU RunServicesOnce ? + * - RunOnce and RunOnceEx entries seem to be able to contain non-program + * entries, too, e.g.: "FlushRegistry" + * + * TODO (in order of importance): + * - every key getting deleted properly ? + * - move stuff into wineboot.h + * - completely reformat packaging.sgml + * - wininit.ini case insensitive !! + * - verify everything + * - test verbose, quiet mode + * - use proper CWDs when executing stuff + * - execute native runonce.exe if available ? (at NO_RUNONCE_BINARY define) + * - test misc. switches of runonce.exe + * - check #includes needed + * - grep for FIXME !! + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <windows.h> +#include "wineboot.h" +#include "regstr.h" +#include "file.h" + +/* Work around a Wine bug which defines handles as UINT rather than LPVOID */ +#ifdef WINE_STRICT +#define NULL_HANDLE NULL +#else +#define NULL_HANDLE 0 +#endif + +/* this needs to remain in this file due to unsupported yet variable argument + * macros in wrc. ugh. */ +#define MESSAGE(x...) fprintf(stderr, x) +#define TRACE(x...) if (BF_Verbose) fprintf(stderr, x) +#define WARN(x...) fprintf(stderr, x) +#define FIXME(x...) fprintf(stderr, x) +#define ERR(x...) fprintf(stderr, x) + + /* Filename for Profile_WinInit */ +#define WININITINI "wininit.ini" +#define WININITBAK "wininit.bak" + +static HKEY hkeyCfg = 0; +static HKEY hkeyHKLM_CV = 0; +static HKEY hkeyHKCU_CV = 0; + +static char *do_it; +#if BOOT_PROFILING +static DWORD BOOT_startticks; +#endif +static BOOL BOOT_started = FALSE; +static BOOL BOOT_viruswarn = FALSE; + +#define CFGS_0 0x0000 +#define CFGS_LOADED 0x0001 +#define CFGS_NOTAVAIL 0x0002 +#define CFGS_MODIFIED 0x0004 + +typedef struct { + LPSTR name; + BOOL value; + DWORD status; +} BOOT_CONFIG; + +BOOT_CONFIG BOOT_Config[] = +{ + /* enable the whole thing */ + {"BootConfig_Enable", TRUE, CFGS_0 }, + + /* do a dry run, i.e. show what to do, but don't act */ + {"BootConfig_DryRun", FALSE, CFGS_0 }, + + /* extra verbosity on console */ + {"BootConfig_TTY_Verbose", FALSE, CFGS_0 }, + + /* extra quiet on console */ + {"BootConfig_TTY_Quiet", FALSE, CFGS_0 }, + + /* process wininit.ini ? */ + {"WininitIni_Execute", TRUE, CFGS_0 }, + + {"RunServicesOnce_Execute", TRUE, CFGS_0 }, + {"RunServicesHKLM_Execute", TRUE, CFGS_0 }, + {"RenameFiles_Execute", TRUE, CFGS_0 }, + {"RunOnceHKLM_Execute", TRUE, CFGS_0 }, + {"RunOnceEx_Execute", TRUE, CFGS_0 }, + {"WinIniLoad_Execute", TRUE, CFGS_0 }, + {"WinIniRun_Execute", TRUE, CFGS_0 }, + {"RunHKLM_Execute", TRUE, CFGS_0 }, + {"RunHKCU_Execute", TRUE, CFGS_0 }, + {"StartupFolderCommon_Execute", FALSE, CFGS_0 }, + {"StartupFolderUser_Execute", FALSE, CFGS_0 }, + {"RunOnceHKCU_Execute", TRUE, CFGS_0 }, +}; + +enum { + CFG_ENABLE = 0, + CFG_DRYRUN, + CFG_TTY_VERBOSE, + CFG_TTY_QUIET, + CFG_WININIT_EXECUTE, + CFG_RSO_EXECUTE, + CFG_RSHKLM_EXECUTE, + CFG_RENAMEFILES_EXECUTE, + CFG_ROHKLM_EXECUTE, + CFG_ROEX_EXECUTE, + CFG_WININILOAD_EXECUTE, + CFG_WININIRUN_EXECUTE, + CFG_RUNHKLM_EXECUTE, + CFG_RUNHKCU_EXECUTE, + CFG_SFC_EXECUTE, + CFG_SFU_EXECUTE, + CFG_ROHKCU_EXECUTE, +}; + +static BOOL BF_DryRun; +static BOOL BF_Verbose; +static BOOL BF_Quiet; + +static char about_string[] = + "wineboot, the Wine boot program execution app\n\n(c) 2001 Andreas Mohr"; + +typedef struct { + LPSTR text_msg; + LPSTR text_shutup; + DWORD flags; + DWORD retval; +} NB_DATA; + +DWORD BOOT_NotifyBox_Show(LPSTR, LPSTR, DWORD); + +/**************************** generic stuff start *****************************/ +static BOOL BOOT_ReadConfig(DWORD what) +{ + char buffer[16]; + DWORD type, count = sizeof(buffer); + BOOL active = FALSE; + + if (!hkeyCfg) + if(RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Boot", &hkeyCfg) != ERROR_SUCCESS) + { + ERR("Failed to open Config registry key !!\n"); + return 0; + } + buffer[0] = '\0'; + if (RegQueryValueExA(hkeyCfg, BOOT_Config[what].name, 0, &type, buffer, &count) == ERROR_SUCCESS) + { + switch (toupper(buffer[0])) + { + case 'N': + case 'F': + case '0': + active = FALSE; + break; + case 'Y': + case 'T': + case '1': + active = TRUE; + break; + } + BOOT_Config[what].value = active; + BOOT_Config[what].status |= CFGS_LOADED; + } + else + BOOT_Config[what].status |= CFGS_NOTAVAIL; + TRACE("Got config param '%s': '%s'\n", BOOT_Config[what].name, buffer); + return BOOT_Config[what].value; +} + +static void BOOT_WriteConfig(DWORD what, BOOL value) +{ + char buffer[2]; + + buffer[0] = (value) ? 'Y' : 'N'; + buffer[1] = '\0'; + + if (RegSetValueExA(hkeyCfg, BOOT_Config[what].name, 0, REG_SZ, buffer, 2) != ERROR_SUCCESS) + ERR("writing Config item '%s' failed !!\n", BOOT_Config[what].name); +} + +static void BOOT_StartMessages(BOOL do_virus) +{ + if (!BOOT_started) + { +#if BOOT_PROFILING + BOOT_startticks = GetTickCount(); +#endif + if (!(BF_Quiet)) + MESSAGE("************************ Wine bootup processing starting ***********************\n"); + BOOT_started = TRUE; + } + + /* we don't want Wine to become the primary choice of myriads of virii + * after all the Outlock and IIS crap that happened in the last decade... + */ + if ((!BOOT_viruswarn) && (do_virus)) + { + /* yeah, yell at people in order to make a slight difference between + * possibly thousands of bootup messages... */ + MESSAGE("BOOT: WARNING: at least one permanent Run/RunServices/Run=/Load=/StartUp Autorun entry detected !\n*** MAKE SURE THAT THE PROGRAMS STARTED HERE ARE NO VIRII ! ***\nIn case you're suspicious, search e.g. www.google.com for the executable name."); + BOOT_viruswarn = TRUE; + } +} + +static void BOOT_FinishMessage(void) +{ + if (!(BF_Quiet)) +#if BOOT_PROFILING + MESSAGE("************ Wine bootup processing finished (%08ld milliseconds) ***********\n", GetTickCount() - BOOT_startticks); +#else + MESSAGE("*********************** Wine bootup processing finished ************************\n"); +#endif +} + +/* BOOT_RegStuff_AddToKill() + * When enumerating keys, we may not disrupt our current enumeration's key + * infrastructure. Thus we must delay deletion */ +static void *del_buffer = NULL; +static DWORD del_buffer_size = 0; +static DWORD del_buffer_filled = 0; +void BOOT_RegStuff_AddToKill(HKEY hkeyParent, BOOL is_key, LPSTR what) +{ +#define DEL_BUFFER_STEP 4096 + DWORD nextsize; + char *p; + + TRACE("registering %s '%s' of hkey %p for delayed deletion.\n", + is_key ? "subkey" : "value", what, hkeyParent); + nextsize = del_buffer_filled + sizeof(hkeyParent) + sizeof(is_key) + strlen(what)+1; + if (del_buffer_size < nextsize) + { + del_buffer = HeapReAlloc(GetProcessHeap(), 0, del_buffer, nextsize + DEL_BUFFER_STEP); + if (!del_buffer) + { + ERR("HeapReAlloc of del_buffer failed !!!\n"); + del_buffer_size = del_buffer_filled = 0; + return; + } + else + del_buffer_size = nextsize + DEL_BUFFER_STEP; + } + p = del_buffer; + p += del_buffer_filled; + + *(HKEY *)p = hkeyParent; + p += sizeof(HKEY); + *(BOOL *)p = is_key; + p += sizeof(BOOL); + strcpy(p, what); + p += strlen(what)+1; + + del_buffer_filled = nextsize; +} + +void BOOT_RegStuff_Kill() +{ + char *p; + HKEY hkeyParent; + BOOL is_key; + + if ((BF_DryRun) || (!del_buffer)) + return; + + p = del_buffer; + do { + hkeyParent = *(HKEY *)p; + p += sizeof(HKEY); + is_key = *(BOOL *)p; + p += sizeof(BOOL); + TRACE("delayed deletion of %s '%s' of hkey %p.\n", + is_key ? "subkey" : "value", p, hkeyParent); + if (is_key) + RegDeleteKeyA(hkeyParent, p); + else + RegDeleteValueA(hkeyParent, p); + p += strlen(p)+1; + } while (p < (char *)(del_buffer + del_buffer_filled)); + + del_buffer_filled = 0; +} + +void BOOT_RegStuff_Cleanup() +{ + if (del_buffer) + HeapFree(GetProcessHeap(), 0, del_buffer); +} + +static BOOL CALLBACK BOOT_NotifyBox_DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + BOOL retval = FALSE; + NB_DATA *nb_data; + BOOL bt1 = TRUE, bt2 = TRUE, bt3 = TRUE; + LPSTR bt1_text = NULL, bt2_text = NULL, bt3_text = NULL; + + if (iMsg == WM_INITDIALOG) + { + nb_data = (NB_DATA *) lParam; + nb_data->retval = 0; + SetWindowLongA(hDlg, DWL_USER, lParam); + switch(nb_data->flags & 0xf) + { + case MB_OK: + bt2 = bt3 = FALSE; + bt1_text = "Aie, Sir !"; + break; + case MB_OKCANCEL: + bt3 = FALSE; + bt1_text = "OK"; + bt2_text = "Cancel"; + break; + case MB_ABORTRETRYIGNORE: + bt1_text = "Abort"; + bt2_text = "Retry"; + bt3_text = "Ignore"; + break; + case MB_YESNO: + case MB_YESNODEL: + bt3 = FALSE; + bt1_text = "Yes"; + bt2_text = "No"; + if ((nb_data->flags & 0xf) == MB_YESNODEL) + { + bt3 = TRUE; + bt3_text = "Delete entry"; + } + break; + case MB_YESNOCANCEL: + bt1_text = "Yes"; + bt2_text = "No"; + bt3_text = "Cancel"; + break; + case MB_RETRYCANCEL: + bt3 = FALSE; + bt1_text = "Retry"; + bt2_text = "Cancel"; + break; + } + + SetDlgItemTextA(hDlg, IDMSG, nb_data->text_msg); + + if (bt1) + SetDlgItemTextA(hDlg, IDBUTTON1, bt1_text); + else + ShowWindow(GetDlgItem(hDlg, IDBUTTON1), SW_HIDE); + + if (bt2) + SetDlgItemTextA(hDlg, IDBUTTON2, bt2_text); + else + ShowWindow(GetDlgItem(hDlg, IDBUTTON2), SW_HIDE); + + if (bt3) + SetDlgItemTextA(hDlg, IDBUTTON3, bt3_text); + else + ShowWindow(GetDlgItem(hDlg, IDBUTTON3), SW_HIDE); + + if (nb_data->flags & SHOW_SHUTUP) + { + SetDlgItemTextA( hDlg, + (nb_data->flags & SHOW_REALLYSHUTUP) ? + IDCHK1 : IDCHK2, + nb_data->text_shutup); + SetDlgItemTextA(hDlg, IDCHK2, "keep setting (almost) forever, not only during this wine session"); + if (nb_data->flags & SHOW_REALLYSHUTUP) + /* disable it on startup */ + EnableWindow(GetDlgItem(hDlg, IDCHK2), FALSE); + else + ShowWindow(GetDlgItem(hDlg, IDCHK2), SW_HIDE); + } + else + { + ShowWindow(GetDlgItem(hDlg, IDCHK1), SW_HIDE); + ShowWindow(GetDlgItem(hDlg, IDCHK2), SW_HIDE); + } + + + ShowWindow(hDlg, SW_SHOWNORMAL); + UpdateWindow(hDlg); + retval = TRUE; + } + else + { + nb_data = (NB_DATA *) GetWindowLongA(hDlg, DWL_USER); + if (!nb_data) + return FALSE; + } + switch(iMsg) + { + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCHK1: + { + BOOL checked = IsDlgButtonChecked(hDlg, IDCHK1); + + /* disable check mark of second box if first is not + * even checked */ + if (!checked) + SendDlgItemMessageA( hDlg, IDCHK2, BM_SETCHECK, FALSE, 0 ); + /* enable second checkbox if first is checked */ + EnableWindow(GetDlgItem(hDlg, IDCHK2), checked); + } + break; + case IDBUTTON1: + nb_data->retval = NBRET_BTN1; + break; + case IDBUTTON2: + nb_data->retval = NBRET_BTN2; + break; + case IDBUTTON3: + nb_data->retval = NBRET_BTN3; + break; + case IDCANCEL: + nb_data->retval = 0x80000000; /* bogus nonzero value */ + break; + case IDABOUT: + MessageBoxA(hDlg, about_string, "About wineboot", MB_OK); + break; + case IDSETUP: + MessageBoxA(hDlg, "\nSorry, graphical configuration not implemented yet !\n\nPlease modify/add parameters in [bootup] section in wine config file (usually '~/.wine/config') instead.\n", "Sorry", MB_OK); + break; + } + if (nb_data->retval) /* button pressed ? */ + { + if (IsDlgButtonChecked(hDlg, IDCHK1)) + nb_data->retval |= NBRET_SHUTUP; + if (IsDlgButtonChecked(hDlg, IDCHK2)) + { + MessageBoxA(hDlg, "You won't get notified in case of this particular issue in future, because you activated the 'permanent' checkbox. To reenable notification, edit wine config file variable \"BootFlagsGUI\".", "Wine bootup notification", MB_OK); + nb_data->retval |= NBRET_REALLYSHUTUP; + } + nb_data->retval &= ~0x80000000; + EndDialog(hDlg, nb_data->retval); + } + break; + } + return retval; +} + +BOOL BOOT_NotifyBox_GetDialogTemplate(LPCVOID *template32) +{ + HANDLE hResInfo, hDlgTmpl32; + + if (!(hResInfo = FindResourceA(0, MAKEINTRESOURCEA(BOOTNOTIFY), RT_DIALOGA))) + return FALSE; + if (!(hDlgTmpl32 = LoadResource(0, hResInfo )) || + !(*template32 = LockResource( hDlgTmpl32 ))) + return FALSE; + return TRUE; +} + +void BOOT_NotifyBox_ShowBox(LPSTR text_msg, LPSTR text_shutup, DWORD flags, DWORD BootFlagGUI) +{ + BOOT_NotifyBox_Show(text_msg, text_shutup, flags); +} + +DWORD BOOT_NotifyBox_Show(LPSTR text_msg, LPSTR text_shutup, DWORD flags) +{ + LPCVOID template32; + NB_DATA nb_data; + DWORD res; + + nb_data.text_msg = text_msg; + nb_data.text_shutup = text_shutup; + nb_data.flags = flags; + + if (!(BOOT_NotifyBox_GetDialogTemplate(&template32))) + return 0xffffffff; + + res = DialogBoxIndirectParamA(0, template32, 0, BOOT_NotifyBox_DlgProc, (LPARAM)&nb_data); + + return (DWORD)res; +} + +static BOOL BOOT_CreateProcess(LPSTR filename, LPSTR dir, BOOL wait, BOOL minimized) +{ + BOOL res; + STARTUPINFOA si; + PROCESS_INFORMATION info; + DWORD exit_code; + + if (BF_DryRun) + return TRUE; + + memset(&si, 0, sizeof(si)); + memset(&info, 0, sizeof(info)); + res = CreateProcessA(NULL, filename, NULL, NULL, FALSE, 0, NULL, dir, &si, &info); + if ((wait) && (res == TRUE)) + { /* wait for the process to exit */ + WaitForSingleObject(info.hProcess, INFINITE); + res = GetExitCodeProcess(info.hProcess, &exit_code); + return exit_code; + } + if ((!res) && (!(BF_Quiet))) + MESSAGE("BOOT: failed to run '%s' !\n", filename); + + return res; +} + +#define OPENREG_CURRVER(use_hkcu) \ + if ((use_hkcu && !hkeyHKCU_CV) || (!use_hkcu && !hkeyHKLM_CV)) \ + if (!BOOT_OpenReg_CurrVer(use_hkcu)) \ + return; +#define USE_HKCU TRUE +#define USE_HKLM FALSE + +static BOOL BOOT_OpenReg_CurrVer(BOOL hkcu) +{ + HKEY hkeyroot = hkcu ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; + HKEY *phkey = hkcu ? &hkeyHKCU_CV : &hkeyHKLM_CV; + + return (RegOpenKeyA(hkeyroot, "Software\\Microsoft\\Windows\\CurrentVersion", phkey) == ERROR_SUCCESS); +} + +static void BOOT_CloseRegistry(void) +{ + int i; + + for (i=0; i < (sizeof(BOOT_Config)/sizeof(BOOT_CONFIG)); i++) + WRITE_CONFIG(i); + + if (hkeyHKLM_CV) RegCloseKey(hkeyHKLM_CV); + if (hkeyHKCU_CV) RegCloseKey(hkeyHKCU_CV); + if (hkeyCfg) RegCloseKey(hkeyCfg); +} +/**************************** generic stuff end *******************************/ + + +/************************************************** + * BOOT_ProcessWininitIni + * + * Process wininit.ini hopefully like wininit.exe does + * Originally created by Uwe Bonnes + */ +static void BOOT_WininitIni(void) +{ + int i,j=0,k=0; + char *buffer=NULL,*p; + char inifile[MAX_PATHNAME_LEN],bakfile[MAX_PATHNAME_LEN]; + BOOL asked = FALSE, gui_asksingle = GET_CONFIG(CFG_WININIT_GUI_ASKSINGLE); + + TRACE("%sProcessing wininit.ini\n", do_it); + buffer = HeapReAlloc( GetProcessHeap(), 0, buffer,(j++ +1)*1024 ); + while (1) + { + if ((k) && !(BF_Quiet)) + FIXME("Some previous programs produced wininit.ini in different case\n"); + i = GetPrivateProfileStringA(NULL,NULL,"",buffer,(j)*1024,WININITINI); + if(i<2) + { + TRACE("No (more) %s present\n",WININITINI); + break; + } + BOOT_StartMessages(VIRUS_NOWARN); + + /* FIXME: ugly hack with 'asked' variable. + * This function should be reorganized to not need this any more */ + if ((!asked) && GET_CONFIG(CFG_WININIT_GUI_ASKWHOLE)) + { + BOOT_NotifyBox_Show("Do you want to process wininit.ini (file move operations) ?", "Make choice permanent", MB_YESNO|SHOW_SHUTUP); + asked = TRUE; + } + + /* Check if there are other sections in the ini file beside the rename section */ + for (p=buffer; *p; p= p + lstrlenA(p) +1) + { + if (strcasecmp(p,"rename")) + { + WARN("Unknown section [%s]\n",p); + WARN("Processing anyway\n"); + } + } + /* Maybe the section is damn long. Try to cope with that */ + while (1) + { + i = GetPrivateProfileStringA("rename",NULL,"",buffer,(j)*1024,WININITINI); + if (i < ((j)*1024)-1) + break; + buffer = HeapReAlloc( GetProcessHeap(), 0, buffer,(j++ +1)*1024 ); + if (!buffer) + { + ERR("Failed to allocate needed space for scanning %s\n",WININITINI); + return; + } + } + /* NUL means delete, otherwise move */ + for (p=buffer; *p; p= p + lstrlenA(p) +1) + { + i = GetPrivateProfileStringA("rename",p,"",inifile,MAX_PATHNAME_LEN,WININITINI); + if (i > MAX_PATHNAME_LEN - 1) + WARN("Filename too long\n"); + else + { + BOOL delete = (!strcasecmp(p,"NUL")); + + if (gui_asksingle) + { + char buffer[512]; + DWORD res; + + if (delete) + sprintf(buffer, "wininit.ini wants to delete file '%s'. Delete it ?", inifile); + sprintf(buffer, "wininit.ini wants to rename file '%s' to '%s'. Rename it ?", inifile, p); + res = BOOT_NotifyBox_Show(buffer, "", MB_YESNODEL|SHOW_SHUTUP); + } + if (delete) + { + TRACE("%sdeleting %s\n",do_it,inifile); + if (!(BF_DryRun)) + DeleteFileA(inifile); + } + else + { + TRACE("%srenaming %s to %s\n",do_it,inifile,p); + if (!(BF_DryRun)) + MoveFileExA(inifile,p,MOVEFILE_REPLACE_EXISTING); + } + } + } + GetWindowsDirectoryA(inifile,MAX_PATHNAME_LEN); + lstrcpynA(inifile+lstrlenA(inifile),"\\",MAX_PATHNAME_LEN-lstrlenA(inifile)); + lstrcpynA(bakfile,inifile,MAX_PATHNAME_LEN); + lstrcpynA(inifile+lstrlenA(inifile),WININITINI,MAX_PATHNAME_LEN-1-lstrlenA(inifile)); + lstrcpynA(bakfile+lstrlenA(bakfile),WININITBAK,MAX_PATHNAME_LEN-1-lstrlenA(bakfile)); + if (k) + sprintf(bakfile,"%s%d",bakfile,k); + TRACE(" %sMoving %s to %s\n",do_it,inifile,bakfile); + if (!(BF_DryRun)) + MoveFileExA(inifile,bakfile,MOVEFILE_REPLACE_EXISTING); + k++; + } + TRACE("BOOT: %s processing finished.\n", WININITINI); + return; +} + +static void BOOT_Registry_FileOps(void) +{ + HKEY hkeyRF, hkey; + DWORD type, count; + CHAR subkey_buf[256], name_buf[256], value_buf[256]; + CHAR path[MAX_PATHNAME_LEN], src[MAX_PATHNAME_LEN], dest[MAX_PATHNAME_LEN]; + BOOL gui_asksingle; + DWORD name_len, value_len, subkey_len; + DWORD dwIndex, postpath = 0, flags, res; + FILETIME ft; + int i; + LPSTR p; + + OPENREG_CURRVER(USE_HKLM); + + if (RegOpenKeyA(hkeyHKLM_CV, "RenameFiles", &hkeyRF) != ERROR_SUCCESS) + { + TRACE("RenameFiles key not found, nothing to do.\n"); + return; + } + + if (GET_CONFIG(CFG_RENAMEFILES_GUI_ASKWHOLE)) + { + DWORD res2; + res2 = BOOT_NotifyBox_Show("Execute registry section 'RenameFiles' ?", "", MB_YESNO|SHOW_SHUTUP); + } + + BOOT_StartMessages(VIRUS_NOWARN); + + gui_asksingle = GET_CONFIG(CFG_RENAMEFILES_GUI_ASKSINGLE); + + subkey_len = sizeof(subkey_buf); + /* Traverse all RenameFiles subkey entries we have available */ + for( dwIndex=0; + (res = RegEnumKeyExA( hkeyRF, dwIndex, subkey_buf, &subkey_len, + NULL, NULL, NULL, &ft )) != ERROR_NO_MORE_ITEMS; + ++dwIndex, subkey_len = sizeof(subkey_buf) ) + { + TRACE("BOOT: found RenameFiles subkey '%s', res %lx\n", subkey_buf, res); + + if (RegOpenKeyA(hkeyRF, subkey_buf, &hkey) != ERROR_SUCCESS) + { + MESSAGE("BOOT: can't open RenameFiles '%s' subkey !!\n", subkey_buf); + continue; + } + + count = sizeof(path); + if ((RegQueryValueExA(hkey, NULL, 0, &type, path, &count) != ERROR_SUCCESS) + || (type != REG_SZ)) + { + FIXME("RenameFiles subkey '%s': path setting not found. What to do ???\n", subkey_buf); + *path = '\0'; + } + else + { + MESSAGE("found path setting '%s'.\n", path); + postpath = strlen(path); + if (postpath) + { + path[postpath++] = '\\'; + path[postpath] = '\0'; + } + strcpy(src, path); + strcpy(dest, path); + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + if (*name_buf == '\0') + goto next_entry; + + if (!(BF_Quiet)) + MESSAGE("BOOT: %sprocessing RenameFiles subkey '%s' entry: '%s': '%s'\n", + do_it, subkey_buf, name_buf, value_buf); + + if (gui_asksingle) + { + DWORD res; + char buffer[512]; + sprintf(buffer, "RenameFiles subkey '%s' wants to rename file '%s' to '%s'. Rename it ?", subkey_buf, name_buf, value_buf); + res = BOOT_NotifyBox_Show(buffer, "", MB_YESNODEL|SHOW_SHUTUP); + } + + if ((p = strchr(value_buf, ','))) + { + *p = '\0'; + p++; + flags = atoi(p); /* file attribute flags: FILE_ATTRIBUTE_xxx */ + TRACE("found file attribute flags: 0x%lx !\n", flags); + } + else + flags = 0; + strcpy(&src[postpath], name_buf); + if (value_buf[0] != '\0') + strcpy(&dest[postpath], value_buf); + else + strcpy(&dest[postpath], name_buf); + + if (!(BF_DryRun)) + { + if (!MoveFileExA(src,dest,MOVEFILE_REPLACE_EXISTING)) + if (!(BF_Quiet)) + ERR("Can't rename file '%s' as '%s' (GLE %ld) ! Please investigate.\n", src, dest, GetLastError()); + if (flags) + SetFileAttributesA(dest, flags); + } + +next_entry: + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + RegCloseKey(hkey); + + BOOT_RegStuff_AddToKill(hkeyRF, TRUE, subkey_buf); + } + BOOT_RegStuff_Kill(); + + RegCloseKey(hkeyRF); + RegDeleteKeyA(hkeyHKLM_CV, "RenameFiles"); +} + +static void BOOT_Registry_RunStuff(BOOL hkcu, BOOL runonce, BOOL services, BOOL wait_exit) +{ + HKEY hkey, hkeyCV; + CHAR name_buf[256], value_buf[256], *run_what, *what_root, cwd[MAX_PATHNAME_LEN]; + DWORD name_len, value_len; + DWORD type; + int i; + DWORD cfg_gui_askwhole, cfg_gui_asksingle; + BOOL askedwhole = FALSE, shutup = FALSE; + DWORD res; + + OPENREG_CURRVER(hkcu); + + if (services) + { + if (runonce) + { + run_what = "RunServicesOnce"; + cfg_gui_askwhole = CFG_RSO_GUI_ASKWHOLE; + cfg_gui_asksingle = CFG_RSO_GUI_ASKSINGLE; + } + else + { + run_what = "RunServices"; + cfg_gui_askwhole = CFG_RSHKLM_GUI_ASKWHOLE; + cfg_gui_asksingle = CFG_RSHKLM_GUI_ASKSINGLE; + } + } + else + { + if (runonce) + { + run_what = "RunOnce"; + cfg_gui_askwhole = CFG_ROHKLM_GUI_ASKWHOLE; + cfg_gui_asksingle = CFG_ROHKLM_GUI_ASKSINGLE; + } + else + { + run_what = "Run"; + if (hkcu) + { + cfg_gui_askwhole = CFG_RUNHKCU_GUI_ASKWHOLE; + cfg_gui_asksingle = CFG_RUNHKCU_GUI_ASKSINGLE; + } + else + { + cfg_gui_askwhole = CFG_RUNHKLM_GUI_ASKWHOLE; + cfg_gui_asksingle = CFG_RUNHKLM_GUI_ASKSINGLE; + } + } + } + + hkeyCV = hkcu ? hkeyHKCU_CV : hkeyHKLM_CV; + what_root = hkcu ? "HKCU" : "HKLM"; + if ((!services) && (!runonce)) /* Run */ + GetWindowsDirectoryA(cwd, sizeof(cwd)); + else + strcpy(cwd, "C:\\"); + + if (RegOpenKeyA(hkeyCV, run_what, &hkey)) + { + TRACE("'%s' key not found, nothing to do.\n", run_what); + return; + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + if (type == REG_SZ) + { + value_buf[sizeof(value_buf) - 1] = '\0'; + + if (!askedwhole) + { + char buffer[512]; + DWORD res; + + askedwhole = TRUE; + + if (GET_CONFIG(cfg_gui_askwhole)) + { + sprintf(buffer, "Do you want to execute some or all of the programs listed in registry key '%s %s' ?", what_root, run_what); + res = BOOT_NotifyBox_Show(buffer, "test1", MB_YESNO|SHOW_SHUTUP|SHOW_REALLYSHUTUP); + if (res & NBRET_BTN2) /* "No" */ + { + goto exit; + } + } + } + + BOOT_StartMessages(VIRUS_WARN); + + /* FIXME: we're supposed to display a dialog box with that + * annoying little animated drum at least for RunOnce here... */ + + if ((!shutup) && GET_CONFIG(cfg_gui_asksingle)) + { + char buffer[512]; + + sprintf(buffer, "Do you want to execute this registry entry ?\n\n\nTitle: '%s'\n\nProgram/action: '%s'\n\nContained in '%s %s' registry section", name_buf, value_buf, what_root, run_what); + res = BOOT_NotifyBox_Show(buffer, "test", MB_YESNODEL|SHOW_SHUTUP); + } + if (res & NBRET_BTN2) /* "No" */ + { + if (res & NBRET_SHUTUP) + goto next_turn; + } + if (res & NBRET_BTN3) /* "Delete entry" */ + { + static BOOL ask_forceddel = TRUE; + DWORD askres = 0; + if (ask_forceddel) + { + ask_forceddel = FALSE; + askres = MessageBoxA(GetDesktopWindow(), "Do you really want to delete subsequent entries, too ?", "Warning", MB_YESNO); + if (askres & IDNO) + res &= ~NBRET_BTN3; + } + goto skip_exec; + } + + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning '%s %s' entry '%s': '%s'\n", + do_it, what_root, run_what, name_buf, value_buf); + BOOT_CreateProcess(value_buf, cwd, wait_exit, PROCESS_MAXIMIZED); + } +skip_exec: + if (runonce) + /* tests indicate that deletion probably is unconditionally */ + BOOT_RegStuff_AddToKill(hkey, FALSE, name_buf); + +next_turn: + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + +exit: + /* now that we're finished, kill accumulated entries */ + BOOT_RegStuff_Kill(); + + RegCloseKey(hkey); +} + +static void BOOT_Registry_RunOnceEx(void) +{ + HKEY hkeyROEx, hkey, hkeyDepend = 0; + DWORD type, count; + CHAR name_buf[256], value_buf[256], subkey_buf[256]; + DWORD ROEx_flags = 0; + CHAR ROEx_title[256]; /* FIXME ? */ + DWORD name_len, value_len, subkey_len; + DWORD dwIndex; + FILETIME ft; + int i; + + TRACE("BOOT: FIXME: a lot of non-basic RunOnceEx functionality NIY !\n"); + + OPENREG_CURRVER(USE_HKLM); + + if (RegOpenKeyA(hkeyHKLM_CV, "RunOnceEx", &hkeyROEx)) + { + TRACE("BOOT: no RunOnceEx registry entries to process.\n"); + return; + } + + BOOT_StartMessages(VIRUS_NOWARN); + + type = REG_DWORD; + count = sizeof(ROEx_flags); + if (RegQueryValueExA(hkeyROEx, "Flags", 0, &type, (LPBYTE)&ROEx_flags, &count) == ERROR_SUCCESS) + TRACE("BOOT: got RunOnceEx \"Flags\" 0x%lx\n", ROEx_flags); + + type = REG_SZ; + count = sizeof(ROEx_title); + if (RegQueryValueExA(hkeyROEx, "Flags", 0, &type, ROEx_title, &count) == ERROR_SUCCESS) + TRACE("BOOT: got RunOnceEx \"Title\" '%s'\n", ROEx_title); + + if (RegOpenKeyA(hkeyROEx, "Depend", &hkeyDepend)) + TRACE("BOOT: found RunOnceEx \"Depend\" section.\n"); + + subkey_len = sizeof(subkey_buf); + + /* Traverse all ROEx subkey entries that we have available */ + for( dwIndex=0; + RegEnumKeyExA( hkeyROEx, dwIndex, subkey_buf, &subkey_len, + NULL, NULL, NULL, &ft ) != ERROR_NO_MORE_ITEMS; + ++dwIndex, subkey_len = sizeof(subkey_buf) ) + { + /* skip "Depend" key */ + if (!(strcasecmp(name_buf, "Depend"))) + continue; + + TRACE("BOOT: found '%s'\n", subkey_buf); + + if (RegOpenKeyA(hkeyROEx, subkey_buf, &hkey) != ERROR_SUCCESS) + { + MESSAGE("BOOT: can't open RunOnceEx '%s' subkey !!\n", subkey_buf); + continue; + } + + i = 0; + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf, &value_len) == ERROR_SUCCESS) + { + /* we assume entries without '|' are normal program entries */ + if (!(strchr(value_buf, '|'))) + { + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning RunOnceEx entry '%s': '%s'\n", + do_it, name_buf, value_buf); + BOOT_CreateProcess(value_buf, "C:\\", PROCESS_WAITEXIT, PROCESS_MAXIMIZED); + } + else + MESSAGE("BOOT: FIXME: HKLM RunOnceEx value '%s' ('%s') execution NIY !\n", name_buf, value_buf); + + /* initialize lengths for new iteration */ + name_len = sizeof(name_buf); + value_len = sizeof(value_buf); + } + RegCloseKey(hkey); + + BOOT_RegStuff_AddToKill(hkeyROEx, TRUE, subkey_buf); + } + BOOT_RegStuff_Kill(); + + if (hkeyDepend) + RegCloseKey(hkeyDepend); + + RegCloseKey(hkeyROEx); +} + +static void BOOT_WinIni_Execute(BOOL do_load) +{ + char line_buf[1024]; /* FIXME ? */ + DWORD numchars; + char buf[MAX_PATH]; /* FIXME ? */ + char *p1, *p2; + + numchars = GetProfileStringA("windows", do_load ? "Load" : "Run", "", + line_buf, sizeof(line_buf)); + if (numchars) + { + BOOT_StartMessages(VIRUS_WARN); + p1 = p2 = line_buf; + + /* split the program entries in this line and run them */ + while (1) + { + while ((*p2 != ' ') && (*p2 != '\0') && (*p2 != '\t')) + p2++; + if ((int)p2 - (int)p1 > sizeof(buf) - 1) + FIXME("buffer problem !!\n"); + strncpy(buf, p1, (int)p2 - (int)p1); + buf[(int)p2 - (int)p1] = '\0'; + + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning win.ini %s= program entry '%s'\n", + do_it, do_load ? "Load" : "Run", buf); + + BOOT_CreateProcess(buf, NULL, PROCESS_NOWAITEXIT, do_load); + + if (*p2 == '\0') /* abort if end of line */ + break; + p2++; + p1 = p2; + } + } + return; +} + +static void BOOT_StartUpFolder(BOOL common_startup) +{ + HKEY hkey = 0, hkeyCV; + char *what_folder = (common_startup) ? "Common StartUp" : "StartUp"; + char startupdir[MAX_PATHNAME_LEN], buffer[MAX_PATHNAME_LEN]; /* FIXME: that ok ? */ + DWORD type, count; + + OPENREG_CURRVER( common_startup ? USE_HKLM : USE_HKCU); + + hkeyCV = common_startup ? hkeyHKLM_CV : hkeyHKCU_CV; + + if(RegOpenKeyA(hkeyCV, "Explorer\\Shell Folders", &hkey) != ERROR_SUCCESS) + goto cleanup; + + count = sizeof(startupdir); + if (RegQueryValueExA(hkey, what_folder, 0, &type, startupdir, &count) != ERROR_SUCCESS) + goto cleanup; + + strcpy(buffer, startupdir); + + /* check whether \\*.* can be added to string */ + if (strlen(buffer)+1 < sizeof(buffer)-4) + { + HANDLE hFF; + WIN32_FIND_DATAA fd; + char *file_part, *p; + + /* add a marker for the file part */ + file_part = buffer+strlen(buffer); + *file_part = '\\'; file_part++; + + *file_part = '\0'; strcat(file_part, "*.*"); + + hFF = FindFirstFileA(buffer, &fd); + if (hFF != INVALID_HANDLE_VALUE) + do + { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + p = strrchr(fd.cFileName, '.'); + + if (p) + { + p++; + + if (!(strcasecmp(p, "exe"))) + { + BOOT_StartMessages(VIRUS_WARN); + if (!(BF_Quiet)) + MESSAGE("BOOT: %srunning file '%s' in %s folder\n", do_it, fd.cFileName, what_folder); + *file_part = '\0'; strcat(file_part, fd.cFileName); + + BOOT_CreateProcess(buffer, startupdir, PROCESS_NOWAITEXIT, PROCESS_MAXIMIZED); + } + else + if (!(BF_Quiet)) + FIXME("Processing of %s folder file '%s' NIY !\n", what_folder, fd.cFileName); + } + } + } + while (FindNextFileA(hFF, &fd)); + } + else + FIXME("buffer size problem !!\n"); + +cleanup: + if (hkey) RegCloseKey(hkey); + + return; +} + +int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow ) +{ +/* FIXME */ +#if 0 + /*------------------------------------------------------------------------ + ** Do the magic check + **----------------------------------------------------------------------*/ + if ((!cmdline) || (strlen(cmdline) < 9) || (memcmp(cmdline, "--yesdoit", 9))) + { + MESSAGE("Sorry, no go.\nThis program is intended to be called by Wine on bootup in order to do a lot of program startup tasks.\nIf you still intend to run this program standalone, then run it using 'wineboot -- --yesdoit'.\n"); + return 0; + } +#endif + + if (!GET_CONFIG(CFG_ENABLE)) + { + MESSAGE("Boot handling disabled in wine registry, aborting.\n"); + return 0; + } + + BF_DryRun = GET_CONFIG(CFG_DRYRUN); + BF_Verbose = GET_CONFIG(CFG_TTY_VERBOSE); + BF_Quiet = GET_CONFIG(CFG_TTY_QUIET); + + do_it = (BF_DryRun) ? "Not " : ""; + + if (GET_CONFIG(CFG_TTY_VERBOSE)) + BOOT_StartMessages(VIRUS_NOWARN); + + + if (GET_CONFIG(CFG_WININIT_EXECUTE)) + BOOT_WininitIni(); + + if (GET_CONFIG(CFG_RSO_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUNONCE, TRUE, PROCESS_NOWAITEXIT); + if (GET_CONFIG(CFG_RSHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUN, TRUE, PROCESS_NOWAITEXIT); + +#if NO_RUNONCE_BINARY + /* builtin runonce.exe begin */ + if (GET_CONFIG(CFG_RENAMEFILES_EXECUTE)) + BOOT_Registry_FileOps(); + + if (GET_CONFIG(CFG_ROHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUNONCE, FALSE, PROCESS_WAITEXIT); + /* runonce.exe end */ +#else + /* execute "runonce.exe -m", native Windows binary */ +#endif + + if (GET_CONFIG(CFG_ROEX_EXECUTE)) + BOOT_Registry_RunOnceEx(); + + if (GET_CONFIG(CFG_WININILOAD_EXECUTE)) + BOOT_WinIni_Execute(WININI_LOAD); + if (GET_CONFIG(CFG_WININIRUN_EXECUTE)) + BOOT_WinIni_Execute(WININI_RUN); + + if (GET_CONFIG(CFG_RUNHKLM_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKLM, REG_RUN, FALSE, PROCESS_NOWAITEXIT); + if (GET_CONFIG(CFG_RUNHKCU_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKCU, REG_RUN, FALSE, PROCESS_NOWAITEXIT); + + if (GET_CONFIG(CFG_SFC_EXECUTE)) + BOOT_StartUpFolder(STARTUP_COMMON); + if (GET_CONFIG(CFG_SFU_EXECUTE)) + BOOT_StartUpFolder(STARTUP_USER); + + if (GET_CONFIG(CFG_ROHKCU_EXECUTE)) + BOOT_Registry_RunStuff(USE_HKCU, REG_RUNONCE, FALSE, PROCESS_NOWAITEXIT); + + BOOT_RegStuff_Cleanup(); + + BOOT_CloseRegistry(); + + if (BOOT_started) + BOOT_FinishMessage(); + + +/* res = BOOT_NotifyBox_Show("this is a stupid and very loo ooo ooo oooo oo ooo oo oo ooo ooo ooo oooo ooo ooo ooo ooo ooo ooooo ooo ooooo oooo oo ooo oooo ooo ooo ooo oo ooo ooo oo ooo oooo ooo ooooo oo oooo oooo ooo ooooo ooooo oooo oooooo ooooooong test", "Don't ask me again", MB_YESNOCANCEL|SHOW_SHUTUP|SHOW_REALLYSHUTUP);*/ + return 1; +} --- /dev/null 2002-12-13 09:59:08.000000000 +0200 +++ programs/wineboot/wineboot.h 2002-04-01 19:18:53.000000000 +0300 @@ -0,0 +1,72 @@ +#include <windows.h> + +#define BOOT_PROFILING TRUE +#define NO_RUNONCE_BINARY TRUE + +#define VIRUS_WARN TRUE +#define VIRUS_NOWARN FALSE + +#define PROCESS_WAITEXIT TRUE +#define PROCESS_NOWAITEXIT FALSE +#define PROCESS_MINIMIZED TRUE +#define PROCESS_MAXIMIZED FALSE + +#define WININI_LOAD TRUE +#define WININI_RUN FALSE + +#define REG_RUNONCE TRUE +#define REG_RUN FALSE + +#define STARTUP_COMMON TRUE +#define STARTUP_USER FALSE + +/* dialog defines */ +#define IDS_APPNAME 1101 + +#define IDMSG 501 +#define IDBUTTON1 601 +#define IDBUTTON2 602 +#define IDBUTTON3 603 +#define IDABOUT 604 +#define IDSETUP 605 +#define IDCHK1 701 +#define IDCHK2 702 +#define BOOTNOTIFY 1000 + +#define MB_YESNODEL 0x0006 +#define SHOW_SHUTUP 0x1000 +#define SHOW_REALLYSHUTUP 0x2000 + +#define NBRET_BTN1 1 +#define NBRET_BTN2 2 +#define NBRET_BTN3 3 +#define NBRET_SHUTUP 0x10 +#define NBRET_REALLYSHUTUP 0x20 +/******/ + +#define VIRUS_WARN TRUE +#define VIRUS_NOWARN FALSE + +#define PROCESS_WAITEXIT TRUE +#define PROCESS_NOWAITEXIT FALSE +#define PROCESS_MINIMIZED TRUE +#define PROCESS_MAXIMIZED FALSE + +#define WININI_LOAD TRUE +#define WININI_RUN FALSE + +#define REG_RUNONCE TRUE +#define REG_RUN FALSE + +#define STARTUP_COMMON TRUE +#define STARTUP_USER FALSE + +#define GET_CONFIG(x) \ + ((BOOT_Config[x].status & (CFGS_NOTAVAIL|CFGS_LOADED)) ? \ + BOOT_Config[x].value : BOOT_ReadConfig(x)) +#define SET_CONFIG(x, value) \ + BOOT_Config[x].value = value; \ + BOOT_Config[x].status |= CFGS_MODIFIED +#define WRITE_CONFIG(x) \ + if (BOOT_Config[x].status & CFGS_MODIFIED) \ + BOOT_WriteConfig(x, BOOT_Config[x].value)