diff --git a/reactos/lib/setupapi/Cs.rc b/reactos/lib/setupapi/Cs.rc new file mode 100644 index 00000000000..330eeddd797 --- /dev/null +++ b/reactos/lib/setupapi/Cs.rc @@ -0,0 +1,35 @@ +/* + * Czech resources for SETUPAPI + * + * Copyright 2001 Andreas Mohr + * Copyright 2004 David Kredba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_CZECH, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Kopruji soubory..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Storno", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Zdroj:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Cl:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/De.rc b/reactos/lib/setupapi/De.rc new file mode 100644 index 00000000000..0fd9555a97f --- /dev/null +++ b/reactos/lib/setupapi/De.rc @@ -0,0 +1,34 @@ +/* + * German resources for SETUPAPI + * + * Copyright 2004 Henning Gerhardt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Dateien kopieren..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Abbrechen", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Quelle:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Ziel:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/En.rc b/reactos/lib/setupapi/En.rc new file mode 100644 index 00000000000..aa504ca13d8 --- /dev/null +++ b/reactos/lib/setupapi/En.rc @@ -0,0 +1,34 @@ +/* + * English resources for SETUPAPI + * + * Copyright 2001 Andreas Mohr + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Copying Files..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Cancel", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Source:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destination:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Es.rc b/reactos/lib/setupapi/Es.rc new file mode 100644 index 00000000000..f09e276ddd6 --- /dev/null +++ b/reactos/lib/setupapi/Es.rc @@ -0,0 +1,34 @@ +/* + * Spanish resources for SETUPAPI + * + * Copyright 2003 Jos Manuel Ferrer Ortiz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_SPANISH, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Copiando archivos..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Cancelar", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Origen:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destino:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Fr.rc b/reactos/lib/setupapi/Fr.rc new file mode 100644 index 00000000000..40f01716a23 --- /dev/null +++ b/reactos/lib/setupapi/Fr.rc @@ -0,0 +1,35 @@ +/* + * French resources for SETUPAPI + * + * Copyright 2001 Andreas Mohr + * Copyright 2003 Vincent Bron + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Copie de fichiers..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Annuler", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Source:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destination:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/It.rc b/reactos/lib/setupapi/It.rc new file mode 100644 index 00000000000..dc7b679e315 --- /dev/null +++ b/reactos/lib/setupapi/It.rc @@ -0,0 +1,35 @@ +/* + * Italian resources for SETUPAPI + * + * Copyright 2001 Andreas Mohr + * Copyright 2003 Ivan Leo Puoti + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_ITALIAN, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Copia dei file in corso..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Anulla", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Origine:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destinazione:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Ja.rc b/reactos/lib/setupapi/Ja.rc new file mode 100644 index 00000000000..03513668ace --- /dev/null +++ b/reactos/lib/setupapi/Ja.rc @@ -0,0 +1,34 @@ +/* + * Japanese resources for SETUPAPI + * + * Copyright 2004 Hajime Segawa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "t@CRs[Ă܂..." +FONT 9, "MS UI Gothic" +BEGIN + PUSHBUTTON "LZ", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Rs[:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Rs[:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Makefile b/reactos/lib/setupapi/Makefile new file mode 100644 index 00000000000..5c2ab0a26c5 --- /dev/null +++ b/reactos/lib/setupapi/Makefile @@ -0,0 +1,415 @@ +EXTRADEFS = -D_SETUPAPI_ +TOPSRCDIR = ../.. +TOPOBJDIR = ../.. +SRCDIR = . + +MODULE = setupapi.dll +IMPORTS = user32 version advapi32 rpcrt4 kernel32 ntdll +DELAYIMPORTS = shell32 +EXTRALIBS = $(LIBUNICODE) + +C_SRCS = \ + devinst.c \ + dirid.c \ + diskspace.c \ + install.c \ + misc.c \ + parser.c \ + queue.c \ + setupcab.c \ + stubs.c + +C_SRCS16 = \ + devinst16.c \ + infparse.c \ + setupx_main.c \ + virtcopy.c + +SPEC_SRCS16 = setupx.spec + +RC_SRCS= setupapi.rc + + +# Global rules for building dlls -*-Makefile-*- +# +# Each individual makefile should define the following variables: +# MODULE : name of the main module being built +# EXTRALIBS : extra libraries to link in (optional) +# SPEC_SRCS16 : interface definition files for 16-bit dlls (optional) +# SUBSYSTEM : (optional) subsystem (for native dlls) +# +# plus all variables required by the global Make.rules.in +# + +DLLDEFS = +DLLFLAGS = -D_REENTRANT +DLLEXT = +DEFS = -D__WINESRC__ $(DLLDEFS) $(EXTRADEFS) +MAINSPEC = $(MODULE:%.dll=%).spec +SPEC_DEF = $(MAINSPEC).def +WIN16_FILES = $(SPEC_SRCS16:.spec=.spec.o) $(C_SRCS16:.c=.o) $(EXTRA_OBJS16) +ALL_OBJS = $(OBJS) $(MODULE).dbg.o +ALL_LIBS = $(LIBWINE) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS) +IMPORTLIBS = $(DELAYIMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) $(IMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) + +all: $(MODULE)$(DLLEXT) $(SUBDIRS) + + +# 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 +# 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 = mingw32-gcc +CFLAGS = -g -O2 +CPPFLAGS = +LIBS = +BISON = bison +YACC = $(BISON) -y +LEX = flex +LEXLIB = +EXEEXT = .exe +OBJEXT = o +LIBEXT = dll +DLLEXT = +IMPLIBEXT = a +LDSHARED = +DLLTOOL = mingw32-dlltool +DLLWRAP = mingw32-dllwrap +AR = mingw32-ar rc +RANLIB = mingw32-ranlib +STRIP = mingw32-strip +WINDRES = mingw32-windres +LN = ln +LN_S = ln -s +TOOLSDIR = /usr/src/wine-tools/ +AS = mingw32-as +LD = mingw32-ld +LDFLAGS = +RM = rm -f +MV = mv +LINT = +LINTFLAGS = +FONTFORGE = fontforge +INCLUDES = -I$(SRCDIR) -I. -I$(TOPSRCDIR)/include -I$(TOPOBJDIR)/include $(EXTRAINCL) +EXTRACFLAGS = -Wall -pipe -fno-strength-reduce -mpreferred-stack-boundary=2 -fno-strict-aliasing -gstabs+ -Wpointer-arith +ALLCFLAGS = $(INCLUDES) $(DEFS) $(DLLFLAGS) $(EXTRACFLAGS) $(CPPFLAGS) $(CFLAGS) +ALLLINTFLAGS = $(INCLUDES) $(DEFS) $(LINTFLAGS) +IDLFLAGS = $(INCLUDES) $(DEFS) $(EXTRAIDLFLAGS) +MKINSTALLDIRS= $(TOPSRCDIR)/tools/mkinstalldirs -m 755 +WINAPI_CHECK = $(TOPSRCDIR)/tools/winapi_check/winapi_check +WINEWRAPPER = $(TOPSRCDIR)/tools/winewrapper +C2MAN = $(TOPSRCDIR)/tools/c2man.pl +RUNTEST = $(TOPSRCDIR)/tools/runtest +WINEBUILD = $(TOOLSDIR)/tools/winebuild/winebuild +MAKEDEP = $(TOOLSDIR)/tools/makedep +WRC = $(TOOLSDIR)/tools/wrc/wrc +BIN2RES = $(TOOLSDIR)/tools/bin2res +WMC = $(TOOLSDIR)/tools/wmc/wmc +WIDL = $(TOOLSDIR)/tools/widl/widl +WINEGCC = $(TOOLSDIR)/tools/winegcc/winegcc +SFNT2FNT = $(TOOLSDIR)/tools/sfnt2fnt +FNT2FON = $(TOOLSDIR)/tools/fnt2fon +RC = $(WRC) +RC16 = $(WRC) +RCFLAGS = --nostdinc $(INCLUDES) $(DEFS) $(EXTRARCFLAGS) +RC16FLAGS = -O res16 $(RCFLAGS) +LDPATH = LD_LIBRARY_PATH="$(TOOLSDIR)/libs/unicode:$$LD_LIBRARY_PATH" +DLLDIR = $(TOPOBJDIR)/dlls +LIBDIR = $(TOPOBJDIR)/libs +LIBPORT = -L$(TOPOBJDIR)/libs/port -lwine_port +LIBUNICODE = -L$(TOPOBJDIR)/libs/unicode -lwine_unicode +LIBWINE = -L$(TOPOBJDIR)/libs/wine -lwine + + + +# Installation infos + +INSTALL = /usr/bin/ginstall -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 +api_manext = 3w +conf_manext = 5 +CLEAN_FILES = *.o *.a *.so *.ln *.$(LIBEXT) \\\#*\\\# *~ *% .\\\#* *.bak *.orig *.rej \ + *.flc *.spec.c *.spec.def *.dbg.c *.tab.c *.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 .idl .h .ok .sfd .ttf + +.c.o: + $(CC) -c $(ALLCFLAGS) -o $@ $< + +.s.o: + $(AS) -o $@ $< + +.mc.mc.rc: + $(LDPATH) $(WMC) -i -U -H /dev/null -o $@ $< + +.rc.res: + $(LDPATH) $(RC) $(RCFLAGS) -fo$@ $< + +.res.res.o: + $(WINDRES) -i $< -o $@ + +.spec.spec.c: + $(WINEBUILD) $(DEFS) -o $@ --main-module $(MODULE) --dll $< + +.spec.spec.def: + $(WINEBUILD) -w $(DEFS) -o $@ --def $< + +.idl.h: + $(WIDL) $(IDLFLAGS) -h -H $@ $< + +.c.ln: + $(LINT) -c $(ALLLINTFLAGS) $< || ( $(RM) $@ && exit 1 ) + +.c.ok: + $(RUNTEST) $(RUNTESTFLAGS) $< && touch $@ + +.sfd.ttf: + $(FONTFORGE) -script $(TOPSRCDIR)/fonts/genttf.ff $< + +# '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 + +# Rules for resources + +$(RC_BINARIES): $(BIN2RES) $(RC_BINSRC) + $(BIN2RES) -f -o $@ $(SRCDIR)/$(RC_BINSRC) + +$(RC_SRCS:.rc=.res) $(RC_SRCS16:.rc=.res): $(WRC) $(RC_BINARIES) + +# Rule for main module debug channels + +$(MODULE).dbg.c: $(C_SRCS) $(C_SRCS16) $(WINEBUILD) + $(WINEBUILD) $(DEFS) -o $@ --debug -C$(SRCDIR) $(C_SRCS) $(C_SRCS16) + +# Rules for makefile + +Makefile: Makefile.in $(TOPSRCDIR)/configure + @echo Makefile is older than $?, please rerun $(TOPSRCDIR)/configure + @exit 1 + +# 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__): dummy + cd `dirname $@` && $(MAKE) depend + +depend: $(IDL_SRCS:.idl=.h) $(SUBDIRS:%=%/__depend__) + $(MAKEDEP) $(INCLUDES) -C$(SRCDIR) $(C_SRCS) $(C_SRCS16) $(RC_SRCS) $(RC_SRCS16) $(MC_SRCS) $(IDL_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) $(IDL_SRCS:.idl=.h) $(PROGRAMS) $(RC_BINARIES) + +.PHONY: clean testclean $(SUBDIRS:%=%/__clean__) $(SUBDIRS:%=%/__testclean__) $(EXTRASUBDIRS:%=%/__clean__) + +# Rules for installing + +$(SUBDIRS:%=%/__install__): dummy + cd `dirname $@` && $(MAKE) install + +$(SUBDIRS:%=%/__install-lib__): dummy + cd `dirname $@` && $(MAKE) install-lib + +$(SUBDIRS:%=%/__install-dev__): dummy + cd `dirname $@` && $(MAKE) install-dev + +$(SUBDIRS:%=%/__uninstall__): dummy + cd `dirname $@` && $(MAKE) uninstall + +install:: $(INSTALLSUBDIRS:%=%/__install__) + +uninstall:: $(INSTALLSUBDIRS:%=%/__uninstall__) + +.PHONY: install install-lib install-dev uninstall \ + $(SUBDIRS:%=%/__install__) $(SUBDIRS:%=%/__uninstall__) \ + $(SUBDIRS:%=%/__install-lib__) $(SUBDIRS:%=%/__install-dev__) + +# 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 + +$(MC_SRCS:.mc=.mc.rc): $(WMC) + +$(IDL_SRCS:.idl=.h): $(WIDL) + +$(SUBDIRS): dummy + @cd $@ && $(MAKE) + +dummy: + +.PHONY: dummy $(SUBDIRS) + +# End of global rules + +# Rules for .so files + +$(MODULE).so: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) Makefile.in + $(WINEGCC) -B$(TOOLSDIR)/tools/winebuild -shared $(SRCDIR)/$(MAINSPEC) $(ALL_OBJS) $(RC_SRCS:.rc=.res) $(SUBSYSTEM:%=-Wb,--subsystem,%) -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(IMPORTS:%=-l%) $(ALL_LIBS) + +# Rules for .dll files + +$(MODULE): $(RCOBJS) $(OBJS) $(MODULE).dbg.o $(SPEC_DEF) $(IMPORTLIBS) Makefile.in + $(DLLWRAP) -k --def $(SPEC_DEF) -o $@ $(RCOBJS) $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(ALL_LIBS) + +$(SPEC_DEF): $(WINEBUILD) + +# Rules for checking that no imports are missing + +.PHONY: checklink16 $(WIN16_FILES:%=__checklink16__%) + +$(WIN16_FILES:%=__checklink16__%): checklink16 + +checklink16:: $(MAINSPEC).o $(OBJS) $(MODULE).dbg.o dummy + $(CC) -o checklink -Wl,-rpath,$(TOPOBJDIR)/libs $(TOPSRCDIR)/dlls/checklink.c $(MAINSPEC).o $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(ALL_LIBS) -lm && $(RM) checklink $(MAINSPEC).c $(MAINSPEC).o + +checklink:: $(WIN16_FILES:%=__checklink16__%) + +# Rules for testing + +check test:: $(SUBDIRS:%=%/__test__) + +crosstest:: $(SUBDIRS:%=%/__crosstest__) + +# Rule to explicitly generate the .spec.c for debugging + +$(MAINSPEC).c: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) $(WINEBUILD) + $(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --dll $(SRCDIR)/$(MAINSPEC) $(SUBSYSTEM:%=--subsystem %) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%) + +# Rules for auto documentation + +man: $(C_SRCS) + $(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext) -R$(TOPOBJDIR) -S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16) + +doc-html: $(C_SRCS) + $(C2MAN) -o $(TOPOBJDIR)/documentation/html -R$(TOPSRCDIR) $(INCLUDES) -Th $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16) + +doc-sgml: $(C_SRCS) + $(C2MAN) -o $(TOPOBJDIR)/documentation/api-guide -R$(TOPSRCDIR) $(INCLUDES) -Ts $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16) + +.PHONY: man doc-html doc-sgml + +# Rules for installation + +EXE_SPECS16 = $(SPEC_SRCS16:.exe.spec=.exe) +DRV_SPECS16 = $(EXE_SPECS16:.drv.spec=.drv) +ALL_SPECS16 = $(DRV_SPECS16:.spec=.dll) + +WIN16_INSTALL = $(ALL_SPECS16:%=_install_/%) + +.PHONY: install_lib $(ALL_SPECS16:%=_install_/%) $(ALL_SPECS16:%=_uninstall_/%) + +$(ALL_SPECS16:%=_install_/%): install_lib + cd $(dlldir) && $(RM) `basename $@`$(DLLEXT) && $(LN_S) $(MODULE)$(DLLEXT) `basename $@`$(DLLEXT) + +$(ALL_SPECS16:%=_uninstall_/%): dummy + $(RM) $(dlldir)/`basename $@`$(DLLEXT) + +install_lib: $(MODULE)$(DLLEXT) + $(MKINSTALLDIRS) $(dlldir) + $(INSTALL_PROGRAM) $(MODULE)$(DLLEXT) $(dlldir)/$(MODULE)$(DLLEXT) + +install:: install_lib + +uninstall:: $(ALL_SPECS16:%=_uninstall_/%) + $(RM) $(dlldir)/$(MODULE)$(DLLEXT) + +# Misc. rules + +$(SPEC_SRCS16:.spec=.spec.c): $(WINEBUILD) + +# End of global dll rules + +### Dependencies: diff --git a/reactos/lib/setupapi/Makefile.in b/reactos/lib/setupapi/Makefile.in new file mode 100644 index 00000000000..b3444fbe957 --- /dev/null +++ b/reactos/lib/setupapi/Makefile.in @@ -0,0 +1,34 @@ +EXTRADEFS = -D_SETUPAPI_ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = setupapi.dll +IMPORTS = user32 version advapi32 rpcrt4 kernel32 ntdll +DELAYIMPORTS = shell32 +EXTRALIBS = $(LIBUNICODE) + +C_SRCS = \ + devinst.c \ + dirid.c \ + diskspace.c \ + install.c \ + misc.c \ + parser.c \ + queue.c \ + setupcab.c \ + stubs.c + +C_SRCS16 = \ + devinst16.c \ + infparse.c \ + setupx_main.c \ + virtcopy.c + +SPEC_SRCS16 = setupx.spec + +RC_SRCS= setupapi.rc + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/setupapi/Nl.rc b/reactos/lib/setupapi/Nl.rc new file mode 100644 index 00000000000..76dc7ed1da4 --- /dev/null +++ b/reactos/lib/setupapi/Nl.rc @@ -0,0 +1,34 @@ +/* + * setupapi (Dutch resources) + * + * Copyright 2003 Hans Leidekker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Bestanden worden gekopiëerd..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Annuleren", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Bron:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Bestemming:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Pt.rc b/reactos/lib/setupapi/Pt.rc new file mode 100644 index 00000000000..69bede2e379 --- /dev/null +++ b/reactos/lib/setupapi/Pt.rc @@ -0,0 +1,34 @@ +/* + * Portuguese resources for SETUPAPI + * + * Copyright 2003 Marcelo Duarte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Copiando arquivos..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Cancelar", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Origem:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destino:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/Ru.rc b/reactos/lib/setupapi/Ru.rc new file mode 100644 index 00000000000..3efa2424097 --- /dev/null +++ b/reactos/lib/setupapi/Ru.rc @@ -0,0 +1,34 @@ +/* + * SETUPAPI (Russian resources) + * + * Copyright 2003 Igor Stepin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION " ..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT ":", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT ":", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/devinst.c b/reactos/lib/setupapi/devinst.c new file mode 100644 index 00000000000..da423c9d504 --- /dev/null +++ b/reactos/lib/setupapi/devinst.c @@ -0,0 +1,1207 @@ +/* + * SetupAPI device installer + * + * Copyright 2000 Andreas Mohr for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "winreg.h" +#include "winternl.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcdce.h" + + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/* Unicode constants */ +static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; +static const WCHAR Class[] = {'C','l','a','s','s',0}; +static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0}; +static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0}; +static const WCHAR NoInstallClass[] = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0}; +static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0}; +static const WCHAR NtExtension[] = {'.','N','T',0}; +static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0}; +static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; +static const WCHAR WinExtension[] = {'.','W','i','n',0}; + +/* Registry key and value names */ +static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'C','l','a','s','s',0}; + +static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'D','e','v','i','c','e','C','l','a','s','s','e','s',0}; + +/*********************************************************************** + * SetupDiBuildClassInfoList (SETUPAPI.@) + */ +BOOL WINAPI SetupDiBuildClassInfoList( + DWORD Flags, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize) +{ + TRACE("\n"); + return SetupDiBuildClassInfoListExW(Flags, ClassGuidList, + ClassGuidListSize, RequiredSize, + NULL, NULL); +} + +/*********************************************************************** + * SetupDiBuildClassInfoListExA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiBuildClassInfoListExA( + DWORD Flags, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize, + LPCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiBuildClassInfoListExW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiBuildClassInfoListExW( + DWORD Flags, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize, + LPCWSTR MachineName, + PVOID Reserved) +{ + WCHAR szKeyName[40]; + HKEY hClassesKey; + HKEY hClassKey; + DWORD dwLength; + DWORD dwIndex; + LONG lError; + DWORD dwGuidListIndex = 0; + + TRACE("\n"); + + if (RequiredSize != NULL) + *RequiredSize = 0; + + hClassesKey = SetupDiOpenClassRegKeyExW(NULL, + KEY_ALL_ACCESS, + DIOCR_INSTALLER, + MachineName, + Reserved); + if (hClassesKey == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + for (dwIndex = 0; ; dwIndex++) + { + dwLength = 40; + lError = RegEnumKeyExW(hClassesKey, + dwIndex, + szKeyName, + &dwLength, + NULL, + NULL, + NULL, + NULL); + TRACE("RegEnumKeyExW() returns %ld\n", lError); + if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) + { + TRACE("Key name: %p\n", szKeyName); + + if (RegOpenKeyExW(hClassesKey, + szKeyName, + 0, + KEY_ALL_ACCESS, + &hClassKey)) + { + RegCloseKey(hClassesKey); + return FALSE; + } + + if (!RegQueryValueExW(hClassKey, + NoUseClass, + NULL, + NULL, + NULL, + NULL)) + { + TRACE("'NoUseClass' value found!\n"); + RegCloseKey(hClassKey); + continue; + } + + if ((Flags & DIBCI_NOINSTALLCLASS) && + (!RegQueryValueExW(hClassKey, + NoInstallClass, + NULL, + NULL, + NULL, + NULL))) + { + TRACE("'NoInstallClass' value found!\n"); + RegCloseKey(hClassKey); + continue; + } + + if ((Flags & DIBCI_NODISPLAYCLASS) && + (!RegQueryValueExW(hClassKey, + NoDisplayClass, + NULL, + NULL, + NULL, + NULL))) + { + TRACE("'NoDisplayClass' value found!\n"); + RegCloseKey(hClassKey); + continue; + } + + RegCloseKey(hClassKey); + + TRACE("Guid: %p\n", szKeyName); + if (dwGuidListIndex < ClassGuidListSize) + { + if (szKeyName[0] == L'{' && szKeyName[37] == L'}') + { + szKeyName[37] = 0; + } + TRACE("Guid: %p\n", &szKeyName[1]); + + UuidFromStringW(&szKeyName[1], + &ClassGuidList[dwGuidListIndex]); + } + + dwGuidListIndex++; + } + + if (lError != ERROR_SUCCESS) + break; + } + + RegCloseKey(hClassesKey); + + if (RequiredSize != NULL) + *RequiredSize = dwGuidListIndex; + + if (ClassGuidListSize < dwGuidListIndex) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + return TRUE; +} + +/*********************************************************************** + * SetupDiClassGuidsFromNameA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassGuidsFromNameA( + LPCSTR ClassName, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize) +{ + return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList, + ClassGuidListSize, RequiredSize, + NULL, NULL); +} + +/*********************************************************************** + * SetupDiClassGuidsFromNameW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassGuidsFromNameW( + LPCWSTR ClassName, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize) +{ + return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList, + ClassGuidListSize, RequiredSize, + NULL, NULL); +} + +/*********************************************************************** + * SetupDiClassGuidsFromNameExA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassGuidsFromNameExA( + LPCSTR ClassName, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize, + LPCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiClassGuidsFromNameExW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassGuidsFromNameExW( + LPCWSTR ClassName, + LPGUID ClassGuidList, + DWORD ClassGuidListSize, + PDWORD RequiredSize, + LPCWSTR MachineName, + PVOID Reserved) +{ + WCHAR szKeyName[40]; + WCHAR szClassName[256]; + HKEY hClassesKey; + HKEY hClassKey; + DWORD dwLength; + DWORD dwIndex; + LONG lError; + DWORD dwGuidListIndex = 0; + + if (RequiredSize != NULL) + *RequiredSize = 0; + + hClassesKey = SetupDiOpenClassRegKeyExW(NULL, + KEY_ALL_ACCESS, + DIOCR_INSTALLER, + MachineName, + Reserved); + if (hClassesKey == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + for (dwIndex = 0; ; dwIndex++) + { + dwLength = 40; + lError = RegEnumKeyExW(hClassesKey, + dwIndex, + szKeyName, + &dwLength, + NULL, + NULL, + NULL, + NULL); + TRACE("RegEnumKeyExW() returns %ld\n", lError); + if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) + { + TRACE("Key name: %p\n", szKeyName); + + if (RegOpenKeyExW(hClassesKey, + szKeyName, + 0, + KEY_ALL_ACCESS, + &hClassKey)) + { + RegCloseKey(hClassesKey); + return FALSE; + } + + dwLength = 256 * sizeof(WCHAR); + if (!RegQueryValueExW(hClassKey, + Class, + NULL, + NULL, + (LPBYTE)szClassName, + &dwLength)) + { + TRACE("Class name: %p\n", szClassName); + + if (strcmpiW(szClassName, ClassName) == 0) + { + TRACE("Found matching class name\n"); + + TRACE("Guid: %p\n", szKeyName); + if (dwGuidListIndex < ClassGuidListSize) + { + if (szKeyName[0] == L'{' && szKeyName[37] == L'}') + { + szKeyName[37] = 0; + } + TRACE("Guid: %p\n", &szKeyName[1]); + + UuidFromStringW(&szKeyName[1], + &ClassGuidList[dwGuidListIndex]); + } + + dwGuidListIndex++; + } + } + + RegCloseKey(hClassKey); + } + + if (lError != ERROR_SUCCESS) + break; + } + + RegCloseKey(hClassesKey); + + if (RequiredSize != NULL) + *RequiredSize = dwGuidListIndex; + + if (ClassGuidListSize < dwGuidListIndex) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + return TRUE; +} + +/*********************************************************************** + * SetupDiClassNameFromGuidA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassNameFromGuidA( + const GUID* ClassGuid, + PSTR ClassName, + DWORD ClassNameSize, + PDWORD RequiredSize) +{ + return SetupDiClassNameFromGuidExA(ClassGuid, ClassName, + ClassNameSize, RequiredSize, + NULL, NULL); +} + +/*********************************************************************** + * SetupDiClassNameFromGuidW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassNameFromGuidW( + const GUID* ClassGuid, + PWSTR ClassName, + DWORD ClassNameSize, + PDWORD RequiredSize) +{ + return SetupDiClassNameFromGuidExW(ClassGuid, ClassName, + ClassNameSize, RequiredSize, + NULL, NULL); +} + +/*********************************************************************** + * SetupDiClassNameFromGuidExA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassNameFromGuidExA( + const GUID* ClassGuid, + PSTR ClassName, + DWORD ClassNameSize, + PDWORD RequiredSize, + PCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiClassNameFromGuidExW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiClassNameFromGuidExW( + const GUID* ClassGuid, + PWSTR ClassName, + DWORD ClassNameSize, + PDWORD RequiredSize, + PCWSTR MachineName, + PVOID Reserved) +{ + HKEY hKey; + DWORD dwLength; + + hKey = SetupDiOpenClassRegKeyExW(ClassGuid, + KEY_ALL_ACCESS, + DIOCR_INSTALLER, + MachineName, + Reserved); + if (hKey == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + if (RequiredSize != NULL) + { + dwLength = 0; + if (RegQueryValueExW(hKey, + Class, + NULL, + NULL, + NULL, + &dwLength)) + { + RegCloseKey(hKey); + return FALSE; + } + + *RequiredSize = dwLength / sizeof(WCHAR); + } + + dwLength = ClassNameSize * sizeof(WCHAR); + if (RegQueryValueExW(hKey, + Class, + NULL, + NULL, + (LPBYTE)ClassName, + &dwLength)) + { + RegCloseKey(hKey); + return FALSE; + } + + RegCloseKey(hKey); + + return TRUE; +} + +/*********************************************************************** + * SetupDiCreateDeviceInfoList (SETUPAPI.@) + */ +HDEVINFO WINAPI +SetupDiCreateDeviceInfoList(const GUID *ClassGuid, + HWND hwndParent) +{ + return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL); +} + +/*********************************************************************** + * SetupDiCreateDeviceInfoListExA (SETUPAPI.@) + */ +HDEVINFO WINAPI +SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid, + HWND hwndParent, + PCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return (HDEVINFO)INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupDiCreateDeviceInfoListExW (SETUPAPI.@) + */ +HDEVINFO WINAPI +SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, + HWND hwndParent, + PCWSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return (HDEVINFO)INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupDiDestroyDeviceInfoList (SETUPAPI.@) + */ +BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) +{ + FIXME("%p\n", devinfo); + return FALSE; +} + +/*********************************************************************** + * SetupDiEnumDeviceInfo (SETUPAPI.@) + */ +BOOL WINAPI SetupDiEnumDeviceInfo( + HDEVINFO devinfo, + DWORD index, + PSP_DEVINFO_DATA info) +{ + FIXME("%p %ld %p\n", devinfo, index, info); + + if(info==NULL) + return FALSE; + if(info->cbSize < sizeof(*info)) + return FALSE; + + return FALSE; +} + +/*********************************************************************** + * SetupDiEnumDeviceInterfaces (SETUPAPI.@) + */ +BOOL WINAPI SetupDiEnumDeviceInterfaces( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + CONST GUID * InterfaceClassGuid, + DWORD MemberIndex, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetActualSectionToInstallA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetActualSectionToInstallA( + HINF InfHandle, + PCSTR InfSectionName, + PSTR InfSectionWithExt, + DWORD InfSectionWithExtSize, + PDWORD RequiredSize, + PSTR *Extension) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetActualSectionToInstallW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetActualSectionToInstallW( + HINF InfHandle, + PCWSTR InfSectionName, + PWSTR InfSectionWithExt, + DWORD InfSectionWithExtSize, + PDWORD RequiredSize, + PWSTR *Extension) +{ + WCHAR szBuffer[MAX_PATH]; + OSVERSIONINFOW OsVersionInfo; + DWORD dwLength; + DWORD dwFullLength; + LONG lLineCount = -1; + + OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); + if (!GetVersionExW(&OsVersionInfo)) + { + return FALSE; + } + + lstrcpyW(szBuffer, InfSectionName); + dwLength = lstrlenW(szBuffer); + + if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + /* Test section name with '.NTx86' extension */ + lstrcpyW(&szBuffer[dwLength], NtPlatformExtension); + lLineCount = SetupGetLineCountW(InfHandle, szBuffer); + + if (lLineCount == -1) + { + /* Test section name with '.NT' extension */ + lstrcpyW(&szBuffer[dwLength], NtExtension); + lLineCount = SetupGetLineCountW(InfHandle, szBuffer); + } + } + else + { + /* Test section name with '.Win' extension */ + lstrcpyW(&szBuffer[dwLength], WinExtension); + lLineCount = SetupGetLineCountW(InfHandle, szBuffer); + } + + if (lLineCount == -1) + { + /* Test section name without extension */ + szBuffer[dwLength] = 0; + lLineCount = SetupGetLineCountW(InfHandle, szBuffer); + } + + if (lLineCount == -1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + dwFullLength = lstrlenW(szBuffer); + + if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0) + { + if (InfSectionWithExtSize < (dwFullLength + 1)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + lstrcpyW(InfSectionWithExt, szBuffer); + if (Extension != NULL) + { + *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength]; + } + } + + if (RequiredSize != NULL) + { + *RequiredSize = dwFullLength + 1; + } + + return TRUE; +} + +/*********************************************************************** + * SetupDiGetClassDescriptionA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDescriptionA( + const GUID* ClassGuid, + PSTR ClassDescription, + DWORD ClassDescriptionSize, + PDWORD RequiredSize) +{ + return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription, + ClassDescriptionSize, + RequiredSize, NULL, NULL); +} + +/*********************************************************************** + * SetupDiGetClassDescriptionW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDescriptionW( + const GUID* ClassGuid, + PWSTR ClassDescription, + DWORD ClassDescriptionSize, + PDWORD RequiredSize) +{ + return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription, + ClassDescriptionSize, + RequiredSize, NULL, NULL); +} + +/*********************************************************************** + * SetupDiGetClassDescriptionExA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDescriptionExA( + const GUID* ClassGuid, + PSTR ClassDescription, + DWORD ClassDescriptionSize, + PDWORD RequiredSize, + PCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetClassDescriptionExW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDescriptionExW( + const GUID* ClassGuid, + PWSTR ClassDescription, + DWORD ClassDescriptionSize, + PDWORD RequiredSize, + PCWSTR MachineName, + PVOID Reserved) +{ + HKEY hKey; + DWORD dwLength; + + hKey = SetupDiOpenClassRegKeyExW(ClassGuid, + KEY_ALL_ACCESS, + DIOCR_INSTALLER, + MachineName, + Reserved); + if (hKey == INVALID_HANDLE_VALUE) + { + WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError()); + return FALSE; + } + + if (RequiredSize != NULL) + { + dwLength = 0; + if (RegQueryValueExW(hKey, + NULL, + NULL, + NULL, + NULL, + &dwLength)) + { + RegCloseKey(hKey); + return FALSE; + } + + *RequiredSize = dwLength / sizeof(WCHAR); + } + + dwLength = ClassDescriptionSize * sizeof(WCHAR); + if (RegQueryValueExW(hKey, + NULL, + NULL, + NULL, + (LPBYTE)ClassDescription, + &dwLength)) + { + RegCloseKey(hKey); + return FALSE; + } + + RegCloseKey(hKey); + + return TRUE; +} + +/*********************************************************************** + * SetupDiGetClassDevsA (SETUPAPI.@) + */ +HDEVINFO WINAPI SetupDiGetClassDevsA( + CONST GUID *class, + LPCSTR enumstr, + HWND parent, + DWORD flags) +{ + FIXME("%s %s %p %08lx\n",debugstr_guid(class),enumstr,parent,flags); + + return (HDEVINFO) INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupDiGetClassDevsW (SETUPAPI.@) + */ +HDEVINFO WINAPI SetupDiGetClassDevsW( + CONST GUID *class, + LPCWSTR enumstr, + HWND parent, + DWORD flags) +{ + FIXME("%s %s %p %08lx\n",debugstr_guid(class),debugstr_w(enumstr),parent,flags); + + return (HDEVINFO) INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInterfaceDetailA( + HDEVINFO DeviceInfoSet, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData, + DWORD DeviceInterfaceDetailDataSize, + PDWORD RequiredSize, + PSP_DEVINFO_DATA DeviceInfoData) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInterfaceDetailW( + HDEVINFO DeviceInfoSet, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, + DWORD DeviceInterfaceDetailDataSize, + PDWORD RequiredSize, + PSP_DEVINFO_DATA DeviceInfoData) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceRegistryPropertyA( + HDEVINFO devinfo, + PSP_DEVINFO_DATA DeviceInfoData, + DWORD Property, + PDWORD PropertyRegDataType, + PBYTE PropertyBuffer, + DWORD PropertyBufferSize, + PDWORD RequiredSize) +{ + FIXME("%04lx %p %ld %p %p %ld %p\n", (DWORD)devinfo, DeviceInfoData, + Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, + RequiredSize); + return FALSE; +} + +/*********************************************************************** + * SetupDiInstallClassA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassA( + HWND hwndParent, + PCSTR InfFileName, + DWORD Flags, + HSPFILEQ FileQueue) +{ + UNICODE_STRING FileNameW; + BOOL Result; + + if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue); + + RtlFreeUnicodeString(&FileNameW); + + return Result; +} + +static HKEY CreateClassKey(HINF hInf) +{ + WCHAR FullBuffer[MAX_PATH]; + WCHAR Buffer[MAX_PATH]; + DWORD RequiredSize; + HKEY hClassKey; + + if (!SetupGetLineTextW(NULL, + hInf, + Version, + ClassGUID, + Buffer, + MAX_PATH, + &RequiredSize)) + { + return INVALID_HANDLE_VALUE; + } + + lstrcpyW(FullBuffer, ControlClass); + lstrcatW(FullBuffer, Buffer); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + FullBuffer, + 0, + KEY_ALL_ACCESS, + &hClassKey)) + { + if (!SetupGetLineTextW(NULL, + hInf, + Version, + Class, + Buffer, + MAX_PATH, + &RequiredSize)) + { + return INVALID_HANDLE_VALUE; + } + + if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, + FullBuffer, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &hClassKey, + NULL)) + { + return INVALID_HANDLE_VALUE; + } + + } + + if (RegSetValueExW(hClassKey, + Class, + 0, + REG_SZ, + (LPBYTE)Buffer, + RequiredSize * sizeof(WCHAR))) + { + RegCloseKey(hClassKey); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, + FullBuffer); + return INVALID_HANDLE_VALUE; + } + + return hClassKey; +} + +/*********************************************************************** + * SetupDiInstallClassW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassW( + HWND hwndParent, + PCWSTR InfFileName, + DWORD Flags, + HSPFILEQ FileQueue) +{ + WCHAR SectionName[MAX_PATH]; + DWORD SectionNameLength = 0; + HINF hInf; + BOOL bFileQueueCreated = FALSE; + HKEY hClassKey; + + + FIXME("\n"); + + if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* Open the .inf file */ + hInf = SetupOpenInfFileW(InfFileName, + NULL, + INF_STYLE_WIN4, + NULL); + if (hInf == INVALID_HANDLE_VALUE) + { + + return FALSE; + } + + /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */ + hClassKey = CreateClassKey(hInf); + if (hClassKey == INVALID_HANDLE_VALUE) + { + SetupCloseInfFile(hInf); + return FALSE; + } + + + /* Try to append a layout file */ +#if 0 + SetupOpenAppendInfFileW(NULL, hInf, NULL); +#endif + + /* Retrieve the actual section name */ + SetupDiGetActualSectionToInstallW(hInf, + ClassInstall32, + SectionName, + MAX_PATH, + &SectionNameLength, + NULL); + +#if 0 + if (!(Flags & DI_NOVCP)) + { + FileQueue = SetupOpenFileQueue(); + if (FileQueue == INVALID_HANDLE_VALUE) + { + SetupCloseInfFile(hInf); + return FALSE; + } + + bFileQueueCreated = TRUE; + + } +#endif + + SetupInstallFromInfSectionW(NULL, + hInf, + SectionName, + SPINST_REGISTRY, + hClassKey, + NULL, + 0, + NULL, + NULL, + INVALID_HANDLE_VALUE, + NULL); + + /* FIXME: More code! */ + + if (bFileQueueCreated) + SetupCloseFileQueue(FileQueue); + + SetupCloseInfFile(hInf); + + return TRUE; +} + + +/*********************************************************************** + * SetupDiOpenClassRegKey (SETUPAPI.@) + */ +HKEY WINAPI SetupDiOpenClassRegKey( + const GUID* ClassGuid, + REGSAM samDesired) +{ + return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired, + DIOCR_INSTALLER, NULL, NULL); +} + + +/*********************************************************************** + * SetupDiOpenClassRegKeyExA (SETUPAPI.@) + */ +HKEY WINAPI SetupDiOpenClassRegKeyExA( + const GUID* ClassGuid, + REGSAM samDesired, + DWORD Flags, + PCSTR MachineName, + PVOID Reserved) +{ + FIXME("\n"); + return INVALID_HANDLE_VALUE; +} + + +/*********************************************************************** + * SetupDiOpenClassRegKeyExW (SETUPAPI.@) + */ +HKEY WINAPI SetupDiOpenClassRegKeyExW( + const GUID* ClassGuid, + REGSAM samDesired, + DWORD Flags, + PCWSTR MachineName, + PVOID Reserved) +{ + LPWSTR lpGuidString; + HKEY hClassesKey; + HKEY hClassKey; + LPCWSTR lpKeyName; + + if (MachineName != NULL) + { + FIXME("Remote access not supported yet!\n"); + return INVALID_HANDLE_VALUE; + } + + if (Flags == DIOCR_INSTALLER) + { + lpKeyName = ControlClass; + } + else if (Flags == DIOCR_INTERFACE) + { + lpKeyName = DeviceClasses; + } + else + { + ERR("Invalid Flags parameter!\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpKeyName, + 0, + KEY_ALL_ACCESS, + &hClassesKey)) + { + return INVALID_HANDLE_VALUE; + } + + if (ClassGuid == NULL) + return hClassesKey; + + if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK) + { + RegCloseKey(hClassesKey); + return FALSE; + } + + if (RegOpenKeyExW(hClassesKey, + lpGuidString, + 0, + KEY_ALL_ACCESS, + &hClassKey)) + { + RpcStringFreeW(&lpGuidString); + RegCloseKey(hClassesKey); + return FALSE; + } + + RpcStringFreeW(&lpGuidString); + RegCloseKey(hClassesKey); + + return hClassKey; +} + +/*********************************************************************** + * SetupDiOpenDeviceInterfaceA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiOpenDeviceInterfaceW( + HDEVINFO DeviceInfoSet, + PCWSTR DevicePath, + DWORD OpenFlags, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) +{ + FIXME("%p %s %08lx %p\n", + DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData); + return FALSE; +} + +/*********************************************************************** + * SetupDiOpenDeviceInterfaceA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiOpenDeviceInterfaceA( + HDEVINFO DeviceInfoSet, + PCSTR DevicePath, + DWORD OpenFlags, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) +{ + FIXME("%p %s %08lx %p\n", DeviceInfoSet, + debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData); + return FALSE; +} + +/*********************************************************************** + * SetupDiSetClassInstallParamsA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiSetClassInstallParamsA( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + PSP_CLASSINSTALL_HEADER ClassInstallParams, + DWORD ClassInstallParamsSize) +{ + FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData, + ClassInstallParams->InstallFunction, ClassInstallParamsSize); + return FALSE; +} + +/*********************************************************************** + * SetupDiCallClassInstaller (SETUPAPI.@) + */ +BOOL WINAPI SetupDiCallClassInstaller( + DWORD InstallFunction, + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData) +{ + FIXME("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetDeviceInstallParamsA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInstallParamsA( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + PSP_DEVINSTALL_PARAMS_A DeviceInstallParams) +{ + FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); + return FALSE; +} + +/*********************************************************************** + * SetupDiOpenDevRegKey (SETUPAPI.@) + */ +HKEY WINAPI SetupDiOpenDevRegKey( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + DWORD Scope, + DWORD HwProfile, + DWORD KeyType, + REGSAM samDesired) +{ + FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData, + Scope, HwProfile, KeyType, samDesired); + return INVALID_HANDLE_VALUE; +} diff --git a/reactos/lib/setupapi/devinst16.c b/reactos/lib/setupapi/devinst16.c new file mode 100644 index 00000000000..f0c51544218 --- /dev/null +++ b/reactos/lib/setupapi/devinst16.c @@ -0,0 +1,134 @@ +/* + * SetupAPI device installer + * + * Copyright 2000 Andreas Mohr for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "setupx16.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/*********************************************************************** + * DiGetClassDevs (SETUPX.304) + * Return a list of installed system devices. + * Uses HKLM\\ENUM to list devices. + */ +RETERR16 WINAPI DiGetClassDevs16(LPLPDEVICE_INFO16 lplpdi, + LPCSTR lpszClassName, HWND16 hwndParent, INT16 iFlags) +{ + LPDEVICE_INFO16 lpdi; + + FIXME("(%p, '%s', %04x, %04x), semi-stub.\n", + lplpdi, lpszClassName, hwndParent, iFlags); + lpdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO16)); + lpdi->cbSize = sizeof(DEVICE_INFO16); + *lplpdi = (LPDEVICE_INFO16)MapLS(lpdi); + return OK; +} + +/*********************************************************************** + * DiBuildCompatDrvList (SETUPX.300) + */ +RETERR16 WINAPI DiBuildCompatDrvList16(LPDEVICE_INFO16 lpdi) +{ + FIXME("(%p): stub\n", lpdi); + lpdi->lpCompatDrvList = NULL; + return FALSE; +} + +/*********************************************************************** + * DiBuildClassDrvList (SETUPX.301) + */ +RETERR16 WINAPI DiBuildClassDrvList16(LPDEVICE_INFO16 lpdi) +{ + FIXME("(%p): stub\n", lpdi); + lpdi->lpCompatDrvList = NULL; + return FALSE; +} + +/*********************************************************************** + * DiCallClassInstaller (SETUPX.308) + */ +RETERR16 WINAPI DiCallClassInstaller16(DI_FUNCTION16 diFctn, LPDEVICE_INFO16 lpdi) +{ + FIXME("(%x, %p): stub\n", diFctn, lpdi); + return FALSE; +} + +/*********************************************************************** + * DiCreateDevRegKey (SETUPX.318) + */ +RETERR16 WINAPI DiCreateDevRegKey16(LPDEVICE_INFO16 lpdi, + VOID* p2, WORD w3, + LPCSTR s4, WORD w5) +{ + FIXME("(%p, %p, %x, %s, %x): stub\n", lpdi, p2, w3, debugstr_a(s4), w5); + return FALSE; +} + +/*********************************************************************** + * DiDeleteDevRegKey (SETUPX.344) + */ +RETERR16 WINAPI DiDeleteDevRegKey16(LPDEVICE_INFO16 lpdi, INT16 iFlags) +{ + FIXME("(%p, %x): stub\n", lpdi, iFlags); + return FALSE; +} + +/*********************************************************************** + * DiCreateDeviceInfo (SETUPX.303) + */ +RETERR16 WINAPI DiCreateDeviceInfo16(LPLPDEVICE_INFO16 lplpdi, + LPCSTR lpszDescription, DWORD dnDevnode, + HKEY16 hkey, LPCSTR lpszRegsubkey, + LPCSTR lpszClassName, HWND16 hwndParent) +{ + LPDEVICE_INFO16 lpdi; + FIXME("(%p %s %08lx %x %s %s %x): stub\n", lplpdi, + debugstr_a(lpszDescription), dnDevnode, hkey, + debugstr_a(lpszRegsubkey), debugstr_a(lpszClassName), hwndParent); + lpdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO16)); + lpdi->cbSize = sizeof(DEVICE_INFO16); + strcpy(lpdi->szClassName, lpszClassName); + lpdi->hwndParent = hwndParent; + *lplpdi = (LPDEVICE_INFO16)MapLS(lpdi); + return OK; +} + +/*********************************************************************** + * DiDestroyDeviceInfoList (SETUPX.305) + */ +RETERR16 WINAPI DiDestroyDeviceInfoList16(LPDEVICE_INFO16 lpdi) +{ + FIXME("(%p): stub\n", lpdi); + return FALSE; +} + +/*********************************************************************** + * DiOpenDevRegKey (SETUPX.319) + */ +RETERR16 WINAPI DiOpenDevRegKey16(LPDEVICE_INFO16 lpdi, + LPHKEY16 lphk,INT16 iFlags) +{ + FIXME("(%p %p %d): stub\n", lpdi, lphk, iFlags); + return FALSE; +} diff --git a/reactos/lib/setupapi/dirid.c b/reactos/lib/setupapi/dirid.c new file mode 100644 index 00000000000..639da022258 --- /dev/null +++ b/reactos/lib/setupapi/dirid.c @@ -0,0 +1,288 @@ +/* + * Directory id handling + * + * Copyright 2002 Alexandre Julliard for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "shlobj.h" +#include "wine/unicode.h" +#include "setupapi_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +#define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR +#define MIN_CSIDL_DIRID 0x4000 +#define MAX_CSIDL_DIRID 0x403f + +struct user_dirid +{ + int id; + WCHAR *str; +}; + +static int nb_user_dirids; /* number of user dirids in use */ +static int alloc_user_dirids; /* number of allocated user dirids */ +static struct user_dirid *user_dirids; +static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1]; +static const WCHAR *csidl_dirids[MAX_CSIDL_DIRID-MIN_CSIDL_DIRID+1]; + +/* retrieve the string for unknown dirids */ +static const WCHAR *get_unknown_dirid(void) +{ + static WCHAR *unknown_dirid; + static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0}; + + if (!unknown_dirid) + { + UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str); + if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; + GetSystemDirectoryW( unknown_dirid, len ); + strcatW( unknown_dirid, unknown_str ); + } + return unknown_dirid; +} + +static const WCHAR *get_csidl_dir(DWORD csidl); + +/* create the string for a system dirid */ +static const WCHAR *create_system_dirid( int dirid ) +{ + static const WCHAR Null[] = {0}; + static const WCHAR C_Root[] = {'C',':','\\',0}; + static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0}; + static const WCHAR Inf[] = {'\\','i','n','f',0}; + static const WCHAR Help[] = {'\\','h','e','l','p',0}; + static const WCHAR Fonts[] = {'\\','f','o','n','t','s',0}; + static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0}; + static const WCHAR System[] = {'\\','s','y','s','t','e','m',0}; + static const WCHAR Spool[] = {'\\','s','p','o','o','l',0}; + static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; + + WCHAR buffer[MAX_PATH+32], *str; + int len; + + switch(dirid) + { + case DIRID_NULL: + return Null; + case DIRID_WINDOWS: + GetWindowsDirectoryW( buffer, MAX_PATH ); + break; + case DIRID_SYSTEM: + GetSystemDirectoryW( buffer, MAX_PATH ); + break; + case DIRID_DRIVERS: + GetSystemDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Drivers ); + break; + case DIRID_INF: + GetWindowsDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Inf ); + break; + case DIRID_HELP: + GetWindowsDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Help ); + break; + case DIRID_FONTS: + GetWindowsDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Fonts ); + break; + case DIRID_VIEWERS: + GetSystemDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Viewers ); + break; + case DIRID_APPS: + return C_Root; /* FIXME */ + case DIRID_SHARED: + GetWindowsDirectoryW( buffer, MAX_PATH ); + break; + case DIRID_BOOT: + return C_Root; /* FIXME */ + case DIRID_SYSTEM16: + GetWindowsDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, System ); + break; + case DIRID_SPOOL: + case DIRID_SPOOLDRIVERS: /* FIXME */ + GetWindowsDirectoryW( buffer, MAX_PATH ); + strcatW( buffer, Spool ); + break; + case DIRID_USERPROFILE: + if (GetEnvironmentVariableW( UserProfile, buffer, MAX_PATH )) break; + return get_csidl_dir(CSIDL_PROFILE); + case DIRID_LOADER: + return C_Root; /* FIXME */ + case DIRID_COLOR: /* FIXME */ + case DIRID_PRINTPROCESSOR: /* FIXME */ + default: + FIXME( "unknown dirid %d\n", dirid ); + return get_unknown_dirid(); + } + len = (strlenW(buffer) + 1) * sizeof(WCHAR); + if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); + return str; +} + +static const WCHAR *get_csidl_dir( DWORD csidl ) +{ + WCHAR buffer[MAX_PATH], *str; + int len; + + if (!SHGetSpecialFolderPathW( NULL, buffer, csidl, TRUE )) + { + FIXME( "CSIDL %lx not found\n", csidl ); + return get_unknown_dirid(); + } + len = (strlenW(buffer) + 1) * sizeof(WCHAR); + if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); + return str; +} + +/* retrieve the string corresponding to a dirid, or NULL if none */ +const WCHAR *DIRID_get_string( HINF hinf, int dirid ) +{ + int i; + + if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL; + + if (dirid >= DIRID_USER) + { + for (i = 0; i < nb_user_dirids; i++) + if (user_dirids[i].id == dirid) return user_dirids[i].str; + ERR("user id %d not found\n", dirid ); + return NULL; + } + else if (dirid >= MIN_CSIDL_DIRID) + { + if (dirid > MAX_CSIDL_DIRID) return get_unknown_dirid(); + dirid -= MIN_CSIDL_DIRID; + if (!csidl_dirids[dirid]) csidl_dirids[dirid] = get_csidl_dir( dirid ); + return csidl_dirids[dirid]; + } + else + { + if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid(); + if (dirid == DIRID_SRCPATH) return PARSER_get_src_root( hinf ); + if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid ); + return system_dirids[dirid]; + } +} + +/* store a user dirid string */ +static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str ) +{ + int i; + + for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break; + + if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); + else + { + if (nb_user_dirids >= alloc_user_dirids) + { + int new_size = max( 32, alloc_user_dirids * 2 ); + + struct user_dirid *new; + + if (user_dirids) + new = HeapReAlloc( GetProcessHeap(), 0, user_dirids, + new_size * sizeof(*new) ); + else + new = HeapAlloc( GetProcessHeap(), 0, + new_size * sizeof(*new) ); + + if (!new) return FALSE; + user_dirids = new; + alloc_user_dirids = new_size; + } + nb_user_dirids++; + } + user_dirids[i].id = id; + user_dirids[i].str = str; + TRACE("id %d -> %s\n", id, debugstr_w(str) ); + return TRUE; +} + + +/*********************************************************************** + * SetupSetDirectoryIdA (SETUPAPI.@) + */ +BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir ) +{ + UNICODE_STRING dirW; + int i; + + if (!id) /* clear everything */ + { + for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); + nb_user_dirids = 0; + return TRUE; + } + if (id < DIRID_USER) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + /* duplicate the string */ + if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + return store_user_dirid( hinf, id, dirW.Buffer ); +} + + +/*********************************************************************** + * SetupSetDirectoryIdW (SETUPAPI.@) + */ +BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir ) +{ + int i, len; + WCHAR *str; + + if (!id) /* clear everything */ + { + for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); + nb_user_dirids = 0; + return TRUE; + } + if (id < DIRID_USER) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + /* duplicate the string */ + len = (strlenW(dir)+1) * sizeof(WCHAR); + if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE; + memcpy( str, dir, len ); + return store_user_dirid( hinf, id, str ); +} diff --git a/reactos/lib/setupapi/diskspace.c b/reactos/lib/setupapi/diskspace.c new file mode 100644 index 00000000000..72c69280391 --- /dev/null +++ b/reactos/lib/setupapi/diskspace.c @@ -0,0 +1,153 @@ +/* + * SetupAPI DiskSpace functions + * + * Copyright 2004 CodeWeavers (Aric Stewart) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "setupapi.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +typedef struct { + WCHAR lpzName[20]; + LONGLONG dwFreeSpace; + LONGLONG dwWantedSpace; +} DRIVE_ENTRY, *LPDRIVE_ENTRY; + +typedef struct { + DWORD dwDriveCount; + DRIVE_ENTRY Drives[26]; +} DISKSPACELIST, *LPDISKSPACELIST; + + +/*********************************************************************** + * SetupCreateDiskSpaceListW (SETUPAPI.@) + */ +HDSKSPC WINAPI SetupCreateDiskSpaceListW(PVOID Reserved1, DWORD Reserved2, UINT Flags) +{ + WCHAR drives[255]; + DWORD rc; + WCHAR *ptr; + LPDISKSPACELIST list=NULL; + + rc = GetLogicalDriveStringsW(255,drives); + + if (rc == 0) + return NULL; + + list = (LPDISKSPACELIST)HeapAlloc(GetProcessHeap(),0,sizeof(DISKSPACELIST)); + + list->dwDriveCount = 0; + + ptr = drives; + + while (*ptr) + { + DWORD type = GetDriveTypeW(ptr); + DWORD len; + if (type == DRIVE_FIXED) + { + DWORD clusters; + DWORD sectors; + DWORD bytes; + DWORD total; + lstrcpyW(list->Drives[list->dwDriveCount].lpzName,ptr); + GetDiskFreeSpaceW(ptr,§ors,&bytes,&clusters,&total); + list->Drives[list->dwDriveCount].dwFreeSpace = clusters * sectors * + bytes; + list->Drives[list->dwDriveCount].dwWantedSpace = 0; + list->dwDriveCount++; + } + len = lstrlenW(ptr); + len++; + ptr+=sizeof(WCHAR)*len; + } + return (HANDLE)list; +} + + +/*********************************************************************** + * SetupCreateDiskSpaceListA (SETUPAPI.@) + */ +HDSKSPC WINAPI SetupCreateDiskSpaceListA(PVOID Reserved1, DWORD Reserved2, UINT Flags) +{ + return SetupCreateDiskSpaceListW( Reserved1, Reserved2, Flags ); +} + + +/*********************************************************************** + * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) + */ +BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC DiskSpace, + HINF InfHandle, HINF LayoutInfHandle, + LPSTR SectionName, PVOID Reserved1, UINT Reserved2) +{ + FIXME ("Stub\n"); + return TRUE; +} + +/*********************************************************************** +* SetupQuerySpaceRequiredOnDriveA (SETUPAPI.@) +*/ +BOOL WINAPI SetupQuerySpaceRequiredOnDriveA(HDSKSPC DiskSpace, + LPSTR DriveSpec, LONGLONG* SpaceRequired, + PVOID Reserved1, UINT Reserved2) +{ + WCHAR driveW[20]; + unsigned int i; + LPDISKSPACELIST list = (LPDISKSPACELIST)DiskSpace; + BOOL rc = FALSE; + static const WCHAR bkslsh[]= {'\\',0}; + + MultiByteToWideChar(CP_ACP,0,DriveSpec,-1,driveW,20); + + lstrcatW(driveW,bkslsh); + + TRACE("Looking for drive %s\n",debugstr_w(driveW)); + + for (i = 0; i < list->dwDriveCount; i++) + { + TRACE("checking drive %s\n",debugstr_w(list->Drives[i].lpzName)); + if (lstrcmpW(driveW,list->Drives[i].lpzName)==0) + { + rc = TRUE; + *SpaceRequired = list->Drives[i].dwWantedSpace; + break; + } + } + + return rc; +} + +/*********************************************************************** +* SetupDestroyDiskSpaceList (SETUPAPI.@) +*/ +BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC DiskSpace) +{ + LPDISKSPACELIST list = (LPDISKSPACELIST)DiskSpace; + HeapFree(GetProcessHeap(),0,list); + return TRUE; +} diff --git a/reactos/lib/setupapi/infparse.c b/reactos/lib/setupapi/infparse.c new file mode 100644 index 00000000000..c508db613ae --- /dev/null +++ b/reactos/lib/setupapi/infparse.c @@ -0,0 +1,198 @@ +/* + * SetupX .inf file parsing functions + * + * Copyright 2000 Andreas Mohr for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: + * - return values ??? + * - this should be reimplemented at some point to have its own + * file parsing instead of using profile functions, + * as some SETUPX exports probably demand that + * (IpSaveRestorePosition, IpFindNextMatchLine, ...). + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "setupx16.h" +#include "setupapi_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +#define MAX_HANDLES 16384 +#define FIRST_HANDLE 32 + +static HINF handles[MAX_HANDLES]; + + +static RETERR16 alloc_hinf16( HINF hinf, HINF16 *hinf16 ) +{ + int i; + for (i = 0; i < MAX_HANDLES; i++) + { + if (!handles[i]) + { + handles[i] = hinf; + *hinf16 = i + FIRST_HANDLE; + return OK; + } + } + return ERR_IP_OUT_OF_HANDLES; +} + +static HINF get_hinf( HINF16 hinf16 ) +{ + int idx = hinf16 - FIRST_HANDLE; + if (idx < 0 || idx >= MAX_HANDLES) return 0; + return handles[idx]; +} + + +static HINF free_hinf16( HINF16 hinf16 ) +{ + HINF ret; + int idx = hinf16 - FIRST_HANDLE; + + if (idx < 0 || idx >= MAX_HANDLES) return 0; + ret = handles[idx]; + handles[idx] = 0; + return ret; +} + +/* convert last error code to a RETERR16 value */ +static RETERR16 get_last_error(void) +{ + switch(GetLastError()) + { + case ERROR_EXPECTED_SECTION_NAME: + case ERROR_BAD_SECTION_NAME_LINE: + case ERROR_SECTION_NAME_TOO_LONG: return ERR_IP_INVALID_SECT_NAME; + case ERROR_SECTION_NOT_FOUND: return ERR_IP_SECT_NOT_FOUND; + case ERROR_LINE_NOT_FOUND: return ERR_IP_LINE_NOT_FOUND; + default: return IP_ERROR; /* FIXME */ + } +} + + +/*********************************************************************** + * IpOpen (SETUPX.2) + * + */ +RETERR16 WINAPI IpOpen16( LPCSTR filename, HINF16 *hinf16 ) +{ + HINF hinf = SetupOpenInfFileA( filename, NULL, INF_STYLE_WIN4, NULL ); + if (hinf == (HINF)INVALID_HANDLE_VALUE) return get_last_error(); + return alloc_hinf16( hinf, hinf16 ); +} + + +/*********************************************************************** + * IpClose (SETUPX.4) + */ +RETERR16 WINAPI IpClose16( HINF16 hinf16 ) +{ + HINF hinf = free_hinf16( hinf16 ); + if (!hinf) return ERR_IP_INVALID_HINF; + SetupCloseInfFile( hinf ); + return OK; +} + + +/*********************************************************************** + * IpGetProfileString (SETUPX.210) + */ +RETERR16 WINAPI IpGetProfileString16( HINF16 hinf16, LPCSTR section, LPCSTR entry, + LPSTR buffer, WORD buflen ) +{ + DWORD required_size; + HINF hinf = get_hinf( hinf16 ); + + if (!hinf) return ERR_IP_INVALID_HINF; + if (!SetupGetLineTextA( NULL, hinf, section, entry, buffer, buflen, &required_size )) + return get_last_error(); + TRACE("%p: section %s entry %s ret %s\n", + hinf, debugstr_a(section), debugstr_a(entry), debugstr_a(buffer) ); + return OK; +} + + +/*********************************************************************** + * GenFormStrWithoutPlaceHolders (SETUPX.103) + * + * ought to be pretty much implemented, I guess... + */ +void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR dst, LPCSTR src, HINF16 hinf16 ) +{ + UNICODE_STRING srcW; + HINF hinf = get_hinf( hinf16 ); + + if (!hinf) return; + + if (!RtlCreateUnicodeStringFromAsciiz( &srcW, src )) return; + PARSER_string_substA( hinf, srcW.Buffer, dst, MAX_INF_STRING_LENGTH ); + RtlFreeUnicodeString( &srcW ); + TRACE( "%s -> %s\n", debugstr_a(src), debugstr_a(dst) ); +} + +/*********************************************************************** + * GenInstall (SETUPX.101) + * + * generic installer function for .INF file sections + * + * This is not perfect - patch whenever you can ! + * + * wFlags == GENINSTALL_DO_xxx + * e.g. NetMeeting: + * first call GENINSTALL_DO_REGSRCPATH | GENINSTALL_DO_FILES, + * second call GENINSTALL_DO_LOGCONFIG | CFGAUTO | INI2REG | REG | INI + */ +RETERR16 WINAPI GenInstall16( HINF16 hinf16, LPCSTR section, WORD genflags ) +{ + UINT flags = 0; + HINF hinf = get_hinf( hinf16 ); + RETERR16 ret = OK; + void *context; + + if (!hinf) return ERR_IP_INVALID_HINF; + + if (genflags & GENINSTALL_DO_FILES) flags |= SPINST_FILES; + if (genflags & GENINSTALL_DO_INI) flags |= SPINST_INIFILES; + if (genflags & GENINSTALL_DO_REG) flags |= SPINST_REGISTRY; + if (genflags & GENINSTALL_DO_INI2REG) flags |= SPINST_INI2REG; + if (genflags & GENINSTALL_DO_LOGCONFIG) flags |= SPINST_LOGCONFIG; + if (genflags & GENINSTALL_DO_REGSRCPATH) FIXME( "unsupported flag: GENINSTALL_DO_REGSRCPATH\n" ); + if (genflags & GENINSTALL_DO_CFGAUTO) FIXME( "unsupported flag: GENINSTALL_DO_CFGAUTO\n" ); + if (genflags & GENINSTALL_DO_PERUSER) FIXME( "unsupported flag: GENINSTALL_DO_PERUSER\n" ); + + context = SetupInitDefaultQueueCallback( 0 ); + if (!SetupInstallFromInfSectionA( 0, hinf, section, flags, 0, NULL, + SP_COPY_NEWER_OR_SAME, SetupDefaultQueueCallbackA, + context, 0, 0 )) + ret = get_last_error(); + + SetupTermDefaultQueueCallback( context ); + return ret; +} diff --git a/reactos/lib/setupapi/install.c b/reactos/lib/setupapi/install.c new file mode 100644 index 00000000000..344e91934ce --- /dev/null +++ b/reactos/lib/setupapi/install.c @@ -0,0 +1,955 @@ +/* + * Setupapi install routines + * + * Copyright 2002 Alexandre Julliard for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "setupapi_private.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/* info passed to callback functions dealing with files */ +struct files_callback_info +{ + HSPFILEQ queue; + PCWSTR src_root; + UINT copy_flags; + HINF layout; +}; + +/* info passed to callback functions dealing with the registry */ +struct registry_callback_info +{ + HKEY default_root; + BOOL delete; +}; + +/* info passed to callback functions dealing with registering dlls */ +struct register_dll_info +{ + PSP_FILE_CALLBACK_W callback; + PVOID callback_context; + BOOL unregister; +}; + +typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg ); + +/* Unicode constants */ +static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; +static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0}; +static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0}; +static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0}; +static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0}; +static const WCHAR AddReg[] = {'A','d','d','R','e','g',0}; +static const WCHAR DelReg[] = {'D','e','l','R','e','g',0}; +static const WCHAR BitReg[] = {'B','i','t','R','e','g',0}; +static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0}; +static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0}; +static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0}; +static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0}; +static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0}; +static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0}; + + +/*********************************************************************** + * get_field_string + * + * Retrieve the contents of a field, dynamically growing the buffer if necessary. + */ +static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer, + WCHAR *static_buffer, DWORD *size ) +{ + DWORD required; + + if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer; + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + /* now grow the buffer */ + if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL; + *size = required; + if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer; + } + if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); + return NULL; +} + + +/*********************************************************************** + * copy_files_callback + * + * Called once for each CopyFiles entry in a given section. + */ +static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct files_callback_info *info = arg; + + if (field[0] == '@') /* special case: copy single file */ + SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags ); + else + SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags ); + return TRUE; +} + + +/*********************************************************************** + * delete_files_callback + * + * Called once for each DelFiles entry in a given section. + */ +static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct files_callback_info *info = arg; + SetupQueueDeleteSectionW( info->queue, hinf, 0, field ); + return TRUE; +} + + +/*********************************************************************** + * rename_files_callback + * + * Called once for each RenFiles entry in a given section. + */ +static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct files_callback_info *info = arg; + SetupQueueRenameSectionW( info->queue, hinf, 0, field ); + return TRUE; +} + + +/*********************************************************************** + * get_root_key + * + * Retrieve the registry root key from its name. + */ +static HKEY get_root_key( const WCHAR *name, HKEY def_root ) +{ + static const WCHAR HKCR[] = {'H','K','C','R',0}; + static const WCHAR HKCU[] = {'H','K','C','U',0}; + static const WCHAR HKLM[] = {'H','K','L','M',0}; + static const WCHAR HKU[] = {'H','K','U',0}; + static const WCHAR HKR[] = {'H','K','R',0}; + + if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT; + if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER; + if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE; + if (!strcmpiW( name, HKU )) return HKEY_USERS; + if (!strcmpiW( name, HKR )) return def_root; + return 0; +} + + +/*********************************************************************** + * append_multi_sz_value + * + * Append a multisz string to a multisz registry value. + */ +static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings, + DWORD str_size ) +{ + DWORD size, type, total; + WCHAR *buffer, *p; + + if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; + if (type != REG_MULTI_SZ) return; + + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return; + if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; + + /* compare each string against all the existing ones */ + total = size; + while (*strings) + { + int len = strlenW(strings) + 1; + + for (p = buffer; *p; p += strlenW(p) + 1) + if (!strcmpiW( p, strings )) break; + + if (!*p) /* not found, need to append it */ + { + memcpy( p, strings, len * sizeof(WCHAR) ); + p[len] = 0; + total += len; + } + strings += len; + } + if (total != size) + { + TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) ); + RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total ); + } + done: + HeapFree( GetProcessHeap(), 0, buffer ); +} + + +/*********************************************************************** + * delete_multi_sz_value + * + * Remove a string from a multisz registry value. + */ +static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string ) +{ + DWORD size, type; + WCHAR *buffer, *src, *dst; + + if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; + if (type != REG_MULTI_SZ) return; + /* allocate double the size, one for value before and one for after */ + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return; + if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; + src = buffer; + dst = buffer + size; + while (*src) + { + int len = strlenW(src) + 1; + if (strcmpiW( src, string )) + { + memcpy( dst, src, len * sizeof(WCHAR) ); + dst += len; + } + src += len; + } + *dst++ = 0; + if (dst != buffer + 2*size) /* did we remove something? */ + { + TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) ); + RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, + (BYTE *)(buffer + size), dst - (buffer + size) ); + } + done: + HeapFree( GetProcessHeap(), 0, buffer ); +} + + +/*********************************************************************** + * do_reg_operation + * + * Perform an add/delete registry operation depending on the flags. + */ +static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags ) +{ + DWORD type, size; + + if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */ + { + if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON)) + { + if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING) + { + WCHAR *str; + + if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE; + if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; + SetupGetStringFieldW( context, 5, str, size, NULL ); + delete_multi_sz_value( hkey, value, str ); + HeapFree( GetProcessHeap(), 0, str ); + } + else RegDeleteValueW( hkey, value ); + } + else RegDeleteKeyW( hkey, NULL ); + return TRUE; + } + + if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE; + + if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY)) + { + BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL ); + if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE; + if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE; + } + + switch(flags & FLG_ADDREG_TYPE_MASK) + { + case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break; + case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break; + case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break; + case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break; + case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break; + case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break; + default: type = flags >> 16; break; + } + + if (!(flags & FLG_ADDREG_BINVALUETYPE) || + (type == REG_DWORD && SetupGetFieldCount(context) == 5)) + { + static const WCHAR empty; + WCHAR *str = NULL; + + if (type == REG_MULTI_SZ) + { + if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0; + if (size) + { + if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; + SetupGetMultiSzFieldW( context, 5, str, size, NULL ); + } + if (flags & FLG_ADDREG_APPEND) + { + if (!str) return TRUE; + append_multi_sz_value( hkey, value, str, size ); + HeapFree( GetProcessHeap(), 0, str ); + return TRUE; + } + /* else fall through to normal string handling */ + } + else + { + if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0; + if (size) + { + if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; + SetupGetStringFieldW( context, 5, str, size, NULL ); + } + } + + if (type == REG_DWORD) + { + DWORD dw = str ? strtoulW( str, NULL, 16 ) : 0; + TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw ); + RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) ); + } + else + { + TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) ); + if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) ); + else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) ); + } + HeapFree( GetProcessHeap(), 0, str ); + return TRUE; + } + else /* get the binary data */ + { + BYTE *data = NULL; + + if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0; + if (size) + { + if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; + TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size ); + SetupGetBinaryField( context, 5, data, size, NULL ); + } + RegSetValueExW( hkey, value, 0, type, data, size ); + HeapFree( GetProcessHeap(), 0, data ); + return TRUE; + } +} + + +/*********************************************************************** + * registry_callback + * + * Called once for each AddReg and DelReg entry in a given section. + */ +static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct registry_callback_info *info = arg; + INFCONTEXT context; + HKEY root_key, hkey; + + BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); + + for (; ok; ok = SetupFindNextLine( &context, &context )) + { + WCHAR buffer[MAX_INF_STRING_LENGTH]; + INT flags; + + /* get root */ + if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + continue; + if (!(root_key = get_root_key( buffer, info->default_root ))) + continue; + + /* get key */ + if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + *buffer = 0; + + /* get flags */ + if (!SetupGetIntField( &context, 4, &flags )) flags = 0; + + if (!info->delete) + { + if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */ + } + else + { + if (!flags) flags = FLG_ADDREG_DELREG_BIT; + else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */ + } + + if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY)) + { + if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */ + } + else if (RegCreateKeyW( root_key, buffer, &hkey )) + { + ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) ); + continue; + } + TRACE( "key %p %s\n", root_key, debugstr_w(buffer) ); + + /* get value name */ + if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + *buffer = 0; + + /* and now do it */ + if (!do_reg_operation( hkey, buffer, &context, flags )) + { + RegCloseKey( hkey ); + return FALSE; + } + RegCloseKey( hkey ); + } + return TRUE; +} + + +/*********************************************************************** + * do_register_dll + * + * Register or unregister a dll. + */ +static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path, + INT flags, INT timeout, const WCHAR *args ) +{ + HMODULE module; + HRESULT res; + SP_REGISTER_CONTROL_STATUSW status; + + status.cbSize = sizeof(status); + status.FileName = path; + status.FailureCode = SPREG_SUCCESS; + status.Win32Error = ERROR_SUCCESS; + + if (info->callback) + { + switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION, + (UINT_PTR)&status, !info->unregister )) + { + case FILEOP_ABORT: + SetLastError( ERROR_OPERATION_ABORTED ); + return FALSE; + case FILEOP_SKIP: + return TRUE; + case FILEOP_DOIT: + break; + } + } + + if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH ))) + { + WARN( "could not load %s\n", debugstr_w(path) ); + status.FailureCode = SPREG_LOADLIBRARY; + status.Win32Error = GetLastError(); + goto done; + } + + if (flags & FLG_REGSVR_DLLREGISTER) + { + const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer"; + HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point ); + + if (!func) + { + status.FailureCode = SPREG_GETPROCADDR; + status.Win32Error = GetLastError(); + goto done; + } + + TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) ); + res = func(); + + if (FAILED(res)) + { + WARN( "calling %s in %s returned error %lx\n", entry_point, debugstr_w(path), res ); + status.FailureCode = SPREG_REGSVR; + status.Win32Error = res; + goto done; + } + } + + if (flags & FLG_REGSVR_DLLINSTALL) + { + HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" ); + + if (!func) + { + status.FailureCode = SPREG_GETPROCADDR; + status.Win32Error = GetLastError(); + goto done; + } + + TRACE( "calling DllInstall(%d,%s) in %s\n", + !info->unregister, debugstr_w(args), debugstr_w(path) ); + res = func( !info->unregister, args ); + + if (FAILED(res)) + { + WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path), res ); + status.FailureCode = SPREG_REGSVR; + status.Win32Error = res; + goto done; + } + } + +done: + if (module) FreeLibrary( module ); + if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION, + (UINT_PTR)&status, !info->unregister ); + return TRUE; +} + + +/*********************************************************************** + * register_dlls_callback + * + * Called once for each RegisterDlls entry in a given section. + */ +static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct register_dll_info *info = arg; + INFCONTEXT context; + BOOL ret = TRUE; + BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); + + for (; ok; ok = SetupFindNextLine( &context, &context )) + { + WCHAR *path, *args, *p; + WCHAR buffer[MAX_INF_STRING_LENGTH]; + INT flags, timeout; + + /* get directory */ + if (!(path = PARSER_get_dest_dir( &context ))) continue; + + /* get dll name */ + if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + goto done; + if (!(p = HeapReAlloc( GetProcessHeap(), 0, path, + (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done; + path = p; + p += strlenW(p); + if (p == path || p[-1] != '\\') *p++ = '\\'; + strcpyW( p, buffer ); + + /* get flags */ + if (!SetupGetIntField( &context, 4, &flags )) flags = 0; + + /* get timeout */ + if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60; + + /* get command line */ + args = NULL; + if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + args = buffer; + + ret = do_register_dll( info, path, flags, timeout, args ); + + done: + HeapFree( GetProcessHeap(), 0, path ); + if (!ret) break; + } + return ret; +} + +/*********************************************************************** + * update_ini_callback + * + * Called once for each UpdateInis entry in a given section. + */ +static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg ) +{ + INFCONTEXT context; + + BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); + + for (; ok; ok = SetupFindNextLine( &context, &context )) + { + WCHAR buffer[MAX_INF_STRING_LENGTH]; + WCHAR filename[MAX_INF_STRING_LENGTH]; + WCHAR section[MAX_INF_STRING_LENGTH]; + WCHAR entry[MAX_INF_STRING_LENGTH]; + WCHAR string[MAX_INF_STRING_LENGTH]; + LPWSTR divider; + + if (!SetupGetStringFieldW( &context, 1, filename, + sizeof(filename)/sizeof(WCHAR), NULL )) + continue; + + if (!SetupGetStringFieldW( &context, 2, section, + sizeof(section)/sizeof(WCHAR), NULL )) + continue; + + if (!SetupGetStringFieldW( &context, 4, buffer, + sizeof(buffer)/sizeof(WCHAR), NULL )) + continue; + + divider = strchrW(buffer,'='); + if (divider) + { + *divider = 0; + strcpyW(entry,buffer); + divider++; + strcpyW(string,divider); + } + else + { + strcpyW(entry,buffer); + string[0]=0; + } + + TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry), + debugstr_w(string),debugstr_w(section),debugstr_w(filename)); + WritePrivateProfileStringW(section,entry,string,filename); + + } + return TRUE; +} + +static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should update ini fields %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do ini2reg %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do logconf %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do bitreg %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL profile_items_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do profile items %s\n", debugstr_w(field) ); + return TRUE; +} + +static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg ) +{ + FIXME( "should do copy inf %s\n", debugstr_w(field) ); + return TRUE; +} + + +/*********************************************************************** + * iterate_section_fields + * + * Iterate over all fields of a certain key of a certain section + */ +static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key, + iterate_fields_func callback, void *arg ) +{ + WCHAR static_buffer[200]; + WCHAR *buffer = static_buffer; + DWORD size = sizeof(static_buffer)/sizeof(WCHAR); + INFCONTEXT context; + BOOL ret = FALSE; + + BOOL ok = SetupFindFirstLineW( hinf, section, key, &context ); + while (ok) + { + UINT i, count = SetupGetFieldCount( &context ); + for (i = 1; i <= count; i++) + { + if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size ))) + goto done; + if (!callback( hinf, buffer, arg )) + { + WARN("callback failed for %s %s err %ld\n", + debugstr_w(section), debugstr_w(buffer), GetLastError() ); + goto done; + } + } + ok = SetupFindNextMatchLineW( &context, key, &context ); + } + ret = TRUE; + done: + if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); + return ret; +} + + +/*********************************************************************** + * SetupInstallFilesFromInfSectionA (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue, + PCSTR section, PCSTR src_root, UINT flags ) +{ + UNICODE_STRING sectionW; + BOOL ret = FALSE; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + if (!src_root) + ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, + NULL, flags ); + else + { + UNICODE_STRING srcW; + if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root )) + { + ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, + srcW.Buffer, flags ); + RtlFreeUnicodeString( &srcW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + RtlFreeUnicodeString( §ionW ); + return ret; +} + + +/*********************************************************************** + * SetupInstallFilesFromInfSectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue, + PCWSTR section, PCWSTR src_root, UINT flags ) +{ + struct files_callback_info info; + + info.queue = queue; + info.src_root = src_root; + info.copy_flags = flags; + info.layout = hlayout; + return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ); +} + + +/*********************************************************************** + * SetupInstallFromInfSectionA (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags, + HKEY key_root, PCSTR src_root, UINT copy_flags, + PSP_FILE_CALLBACK_A callback, PVOID context, + HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) +{ + UNICODE_STRING sectionW, src_rootW; + struct callback_WtoA_context ctx; + BOOL ret = FALSE; + + src_rootW.Buffer = NULL; + if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + ctx.orig_context = context; + ctx.orig_handler = callback; + ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root, + src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA, + &ctx, devinfo, devinfo_data ); + RtlFreeUnicodeString( §ionW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + + RtlFreeUnicodeString( &src_rootW ); + return ret; +} + + +/*********************************************************************** + * SetupInstallFromInfSectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags, + HKEY key_root, PCWSTR src_root, UINT copy_flags, + PSP_FILE_CALLBACK_W callback, PVOID context, + HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) +{ + if (flags & SPINST_FILES) + { + struct files_callback_info info; + HSPFILEQ queue; + BOOL ret; + + if (!(queue = SetupOpenFileQueue())) return FALSE; + info.queue = queue; + info.src_root = src_root; + info.copy_flags = copy_flags; + info.layout = hinf; + ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) && + iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) && + iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) && + SetupCommitFileQueueW( owner, queue, callback, context )); + SetupCloseFileQueue( queue ); + if (!ret) return FALSE; + } + if (flags & SPINST_INIFILES) + { + if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) || + !iterate_section_fields( hinf, section, UpdateIniFields, + update_ini_fields_callback, NULL )) + return FALSE; + } + if (flags & SPINST_INI2REG) + { + if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL )) + return FALSE; + } + if (flags & SPINST_LOGCONFIG) + { + if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL )) + return FALSE; + } + if (flags & SPINST_REGSVR) + { + struct register_dll_info info; + + info.unregister = FALSE; + if (flags & SPINST_REGISTERCALLBACKAWARE) + { + info.callback = callback; + info.callback_context = context; + } + else info.callback = NULL; + + if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info )) + return FALSE; + } + if (flags & SPINST_UNREGSVR) + { + struct register_dll_info info; + + info.unregister = TRUE; + if (flags & SPINST_REGISTERCALLBACKAWARE) + { + info.callback = callback; + info.callback_context = context; + } + else info.callback = NULL; + + if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info )) + return FALSE; + } + if (flags & SPINST_REGISTRY) + { + struct registry_callback_info info; + + info.default_root = key_root; + info.delete = TRUE; + if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info )) + return FALSE; + info.delete = FALSE; + if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info )) + return FALSE; + } + if (flags & SPINST_BITREG) + { + if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL )) + return FALSE; + } + if (flags & SPINST_PROFILEITEMS) + { + if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL )) + return FALSE; + } + if (flags & SPINST_COPYINF) + { + if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL )) + return FALSE; + } + + return TRUE; +} + + +/*********************************************************************** + * InstallHinfSectionW (SETUPAPI.@) + * + * NOTE: 'cmdline' is
from + * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection
+ */ +void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show ) +{ + WCHAR *p, *path, section[MAX_PATH]; + void *callback_context; + UINT mode; + HINF hinf; + + TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline)); + + lstrcpynW( section, cmdline, sizeof(section)/sizeof(WCHAR) ); + + if (!(p = strchrW( section, ' ' ))) return; + *p++ = 0; + while (*p == ' ') p++; + mode = atoiW( p ); + + if (!(p = strchrW( p, ' ' ))) return; + path = p + 1; + while (*path == ' ') path++; + + hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL ); + if (hinf == INVALID_HANDLE_VALUE) return; + + callback_context = SetupInitDefaultQueueCallback( hwnd ); + SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, SP_COPY_NEWER, + SetupDefaultQueueCallbackW, callback_context, + NULL, NULL ); + SetupTermDefaultQueueCallback( callback_context ); + SetupCloseInfFile( hinf ); + + /* FIXME: should check the mode and maybe reboot */ + /* there isn't much point in doing that since we */ + /* don't yet handle deferred file copies anyway. */ +} + + +/*********************************************************************** + * InstallHinfSectionA (SETUPAPI.@) + */ +void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show ) +{ + UNICODE_STRING cmdlineW; + + if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline )) + { + InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show ); + RtlFreeUnicodeString( &cmdlineW ); + } +} diff --git a/reactos/lib/setupapi/misc.c b/reactos/lib/setupapi/misc.c new file mode 100644 index 00000000000..dfbe49bb047 --- /dev/null +++ b/reactos/lib/setupapi/misc.c @@ -0,0 +1,174 @@ +/* + * Setupapi miscellaneous functions + * + * Copyright 2005 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "setupapi.h" + +#include "wine/unicode.h" + + +/************************************************************************** + * MyFree [SETUPAPI.@] + * + * Frees an allocated memory block from the process heap. + * + * PARAMS + * lpMem [I] pointer to memory block which will be freed + * + * RETURNS + * None + */ + +VOID WINAPI MyFree(LPVOID lpMem) +{ + HeapFree(GetProcessHeap(), 0, lpMem); +} + + +/************************************************************************** + * MyMalloc [SETUPAPI.@] + * + * Allocates memory block from the process heap. + * + * PARAMS + * dwSize [I] size of the allocated memory block + * + * RETURNS + * Success: pointer to allocated memory block + * Failure: NULL + */ + +LPVOID WINAPI MyMalloc(DWORD dwSize) +{ + return HeapAlloc(GetProcessHeap(), 0, dwSize); +} + + +/************************************************************************** + * MyRealloc [SETUPAPI.@] + * + * Changes the size of an allocated memory block or allocates a memory + * block from the process heap. + * + * PARAMS + * lpSrc [I] pointer to memory block which will be resized + * dwSize [I] new size of the memory block + * + * RETURNS + * Success: pointer to the resized memory block + * Failure: NULL + * + * NOTES + * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory + * block like MyMalloc. + */ + +LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize) +{ + if (lpSrc == NULL) + return HeapAlloc(GetProcessHeap(), 0, dwSize); + + return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize); +} + + +/************************************************************************** + * DuplicateString [SETUPAPI.@] + * + * Duplicates a unicode string. + * + * PARAMS + * lpSrc [I] pointer to the unicode string that will be duplicated + * + * RETURNS + * Success: pointer to the duplicated unicode string + * Failure: NULL + * + * NOTES + * Call MyFree() to release the duplicated string. + */ + +LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc) +{ + LPWSTR lpDst; + + lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR)); + if (lpDst == NULL) + return NULL; + + strcpyW(lpDst, lpSrc); + + return lpDst; +} + + +/************************************************************************** + * QueryRegistryValue [SETUPAPI.@] + * + * Retrieves value data from the registry and allocates memory for the + * value data. + * + * PARAMS + * hKey [I] Handle of the key to query + * lpValueName [I] Name of value under hkey to query + * lpData [O] Destination for the values contents, + * lpType [O] Destination for the value type + * lpcbData [O] Destination for the size of data + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Otherwise + * + * NOTES + * Use MyFree to release the lpData buffer. + */ + +LONG WINAPI QueryRegistryValue(HKEY hKey, + LPCWSTR lpValueName, + LPBYTE *lpData, + LPDWORD lpType, + LPDWORD lpcbData) +{ + LONG lError; + + /* Get required buffer size */ + *lpcbData = 0; + lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData); + if (lError != ERROR_SUCCESS) + return lError; + + /* Allocate buffer */ + *lpData = MyMalloc(*lpcbData); + if (*lpData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + /* Query registry value */ + lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData); + if (lError != ERROR_SUCCESS) + MyFree(*lpData); + + return lError; +} diff --git a/reactos/lib/setupapi/parser.c b/reactos/lib/setupapi/parser.c new file mode 100644 index 00000000000..53c9e3968b8 --- /dev/null +++ b/reactos/lib/setupapi/parser.c @@ -0,0 +1,1839 @@ +/* + * INF file parsing + * + * Copyright 2002 Alexandre Julliard for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" +#include "winerror.h" +#include "setupapi.h" +#include "setupapi_private.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +#define CONTROL_Z '\x1a' +#define MAX_SECTION_NAME_LEN 255 +#define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ +/* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ +#define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) + +/* inf file structure definitions */ + +struct field +{ + const WCHAR *text; /* field text */ +}; + +struct line +{ + int first_field; /* index of first field in field array */ + int nb_fields; /* number of fields in line */ + int key_field; /* index of field for key or -1 if no key */ +}; + +struct section +{ + const WCHAR *name; /* section name */ + unsigned int nb_lines; /* number of used lines */ + unsigned int alloc_lines; /* total number of allocated lines in array below */ + struct line lines[16]; /* lines information (grown dynamically, 16 is initial size) */ +}; + +struct inf_file +{ + struct inf_file *next; /* next appended file */ + WCHAR *strings; /* buffer for string data (section names and field values) */ + WCHAR *string_pos; /* position of next available string in buffer */ + unsigned int nb_sections; /* number of used sections */ + unsigned int alloc_sections; /* total number of allocated section pointers */ + struct section **sections; /* section pointers array */ + unsigned int nb_fields; + unsigned int alloc_fields; + struct field *fields; + int strings_section; /* index of [Strings] section or -1 if none */ + WCHAR *src_root; /* source root directory */ +}; + +/* parser definitions */ + +enum parser_state +{ + LINE_START, /* at beginning of a line */ + SECTION_NAME, /* parsing a section name */ + KEY_NAME, /* parsing a key name */ + VALUE_NAME, /* parsing a value name */ + EOL_BACKSLASH, /* backslash at end of line */ + QUOTES, /* inside quotes */ + LEADING_SPACES, /* leading spaces */ + TRAILING_SPACES, /* trailing spaces */ + COMMENT, /* inside a comment */ + NB_PARSER_STATES +}; + +struct parser +{ + const WCHAR *start; /* start position of item being parsed */ + const WCHAR *end; /* end of buffer */ + struct inf_file *file; /* file being built */ + enum parser_state state; /* current parser state */ + enum parser_state stack[4]; /* state stack */ + int stack_pos; /* current pos in stack */ + + int cur_section; /* index of section being parsed*/ + struct line *line; /* current line */ + unsigned int line_pos; /* current line position in file */ + unsigned int error; /* error code */ + unsigned int token_len; /* current token len */ + WCHAR token[MAX_FIELD_LEN+1]; /* current token */ +}; + +typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos ); + +/* parser state machine functions */ +static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ); + +static const parser_state_func parser_funcs[NB_PARSER_STATES] = +{ + line_start_state, /* LINE_START */ + section_name_state, /* SECTION_NAME */ + key_name_state, /* KEY_NAME */ + value_name_state, /* VALUE_NAME */ + eol_backslash_state, /* EOL_BACKSLASH */ + quotes_state, /* QUOTES */ + leading_spaces_state, /* LEADING_SPACES */ + trailing_spaces_state, /* TRAILING_SPACES */ + comment_state /* COMMENT */ +}; + + +/* Unicode string constants */ +static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; +static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0}; +static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0}; +static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0}; +static const WCHAR Windows95[] = {'$','W','i','n','d','o','w','s',' ','9','5','$',0}; +static const WCHAR LayoutFile[] = {'L','a','y','o','u','t','F','i','l','e',0}; + +/* extend an array, allocating more memory if necessary */ +static void *grow_array( void *array, unsigned int *count, size_t elem ) +{ + void *new_array; + unsigned int new_count = *count + *count / 2; + if (new_count < 32) new_count = 32; + + if (array) + new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, array, new_count * elem ); + else + new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * elem ); + + if (new_array) + *count = new_count; + else + HeapFree( GetProcessHeap(), 0, array ); + return new_array; +} + + +/* find a section by name */ +static int find_section( struct inf_file *file, const WCHAR *name ) +{ + unsigned int i; + + for (i = 0; i < file->nb_sections; i++) + if (!strcmpiW( name, file->sections[i]->name )) return i; + return -1; +} + + +/* find a line by name */ +static struct line *find_line( struct inf_file *file, int section_index, const WCHAR *name ) +{ + struct section *section; + struct line *line; + int i; + + if (section_index < 0 || section_index >= file->nb_sections) return NULL; + section = file->sections[section_index]; + for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) + { + if (line->key_field == -1) continue; + if (!strcmpiW( name, file->fields[line->key_field].text )) return line; + } + return NULL; +} + + +/* add a section to the file and return the section index */ +static int add_section( struct inf_file *file, const WCHAR *name ) +{ + struct section *section; + + if (file->nb_sections >= file->alloc_sections) + { + if (!(file->sections = grow_array( file->sections, &file->alloc_sections, + sizeof(file->sections[0]) ))) return -1; + } + if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ))) return -1; + section->name = name; + section->nb_lines = 0; + section->alloc_lines = sizeof(section->lines)/sizeof(section->lines[0]); + file->sections[file->nb_sections] = section; + return file->nb_sections++; +} + + +/* add a line to a given section */ +static struct line *add_line( struct inf_file *file, int section_index ) +{ + struct section *section; + struct line *line; + + assert( section_index >= 0 && section_index < file->nb_sections ); + + section = file->sections[section_index]; + if (section->nb_lines == section->alloc_lines) /* need to grow the section */ + { + int size = sizeof(*section) - sizeof(section->lines) + 2*section->alloc_lines*sizeof(*line); + if (!(section = HeapReAlloc( GetProcessHeap(), 0, section, size ))) return NULL; + section->alloc_lines *= 2; + file->sections[section_index] = section; + } + line = §ion->lines[section->nb_lines++]; + line->first_field = file->nb_fields; + line->nb_fields = 0; + line->key_field = -1; + return line; +} + + +/* retrieve a given line from section/line index */ +inline static struct line *get_line( struct inf_file *file, unsigned int section_index, + unsigned int line_index ) +{ + struct section *section; + + if (section_index >= file->nb_sections) return NULL; + section = file->sections[section_index]; + if (line_index >= section->nb_lines) return NULL; + return §ion->lines[line_index]; +} + + +/* retrieve a given field from section/line/field index */ +static struct field *get_field( struct inf_file *file, int section_index, int line_index, + int field_index ) +{ + struct line *line = get_line( file, section_index, line_index ); + + if (!line) return NULL; + if (!field_index) /* get the key */ + { + if (line->key_field == -1) return NULL; + return &file->fields[line->key_field]; + } + field_index--; + if (field_index >= line->nb_fields) return NULL; + return &file->fields[line->first_field + field_index]; +} + + +/* allocate a new field, growing the array if necessary */ +static struct field *add_field( struct inf_file *file, const WCHAR *text ) +{ + struct field *field; + + if (file->nb_fields >= file->alloc_fields) + { + if (!(file->fields = grow_array( file->fields, &file->alloc_fields, + sizeof(file->fields[0]) ))) return NULL; + } + field = &file->fields[file->nb_fields++]; + field->text = text; + return field; +} + + +/* retrieve the string substitution for a directory id */ +static const WCHAR *get_dirid_subst( int dirid, unsigned int *len ) +{ + extern const WCHAR *DIRID_get_string( HINF hinf, int dirid ); + const WCHAR *ret = DIRID_get_string( 0, dirid ); + if (ret) *len = strlenW(ret); + return ret; +} + + +/* retrieve the string substitution for a given string, or NULL if not found */ +/* if found, len is set to the substitution length */ +static const WCHAR *get_string_subst( struct inf_file *file, const WCHAR *str, unsigned int *len ) +{ + static const WCHAR percent = '%'; + + struct section *strings_section; + struct line *line; + struct field *field; + unsigned int i; + int dirid; + WCHAR *dirid_str, *end; + const WCHAR *ret = NULL; + + if (!*len) /* empty string (%%) is replaced by single percent */ + { + *len = 1; + return &percent; + } + if (file->strings_section == -1) goto not_found; + strings_section = file->sections[file->strings_section]; + for (i = 0, line = strings_section->lines; i < strings_section->nb_lines; i++, line++) + { + if (line->key_field == -1) continue; + if (strncmpiW( str, file->fields[line->key_field].text, *len )) continue; + if (!file->fields[line->key_field].text[*len]) break; + } + if (i == strings_section->nb_lines || !line->nb_fields) goto not_found; + field = &file->fields[line->first_field]; + *len = strlenW( field->text ); + return field->text; + + not_found: /* check for integer id */ + if ((dirid_str = HeapAlloc( GetProcessHeap(), 0, (*len+1) * sizeof(WCHAR) ))) + { + memcpy( dirid_str, str, *len * sizeof(WCHAR) ); + dirid_str[*len] = 0; + dirid = strtolW( dirid_str, &end, 10 ); + if (!*end) ret = get_dirid_subst( dirid, len ); + HeapFree( GetProcessHeap(), 0, dirid_str ); + return ret; + } + return NULL; +} + + +/* do string substitutions on the specified text */ +/* the buffer is assumed to be large enough */ +/* returns necessary length not including terminating null */ +unsigned int PARSER_string_substW( struct inf_file *file, const WCHAR *text, WCHAR *buffer, + unsigned int size ) +{ + const WCHAR *start, *subst, *p; + unsigned int len, total = 0; + int inside = 0; + + if (!buffer) size = MAX_STRING_LEN + 1; + for (p = start = text; *p; p++) + { + if (*p != '%') continue; + inside = !inside; + if (inside) /* start of a %xx% string */ + { + len = p - start; + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); + total += len; + size -= len; + start = p; + } + else /* end of the %xx% string, find substitution */ + { + len = p - start - 1; + subst = get_string_subst( file, start + 1, &len ); + if (!subst) + { + subst = start; + len = p - start + 1; + } + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) ); + total += len; + size -= len; + start = p + 1; + } + } + + if (start != p) /* unfinished string, copy it */ + { + len = p - start; + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); + total += len; + } + if (buffer && size) buffer[total] = 0; + return total; +} + + +/* do string substitutions on the specified text */ +/* the buffer is assumed to be large enough */ +/* returns necessary length not including terminating null */ +unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *text, char *buffer, + unsigned int size ) +{ + WCHAR buffW[MAX_STRING_LEN+1]; + DWORD ret; + + unsigned int len = PARSER_string_substW( file, text, buffW, sizeof(buffW)/sizeof(WCHAR) ); + if (!buffer) RtlUnicodeToMultiByteSize( &ret, buffW, len * sizeof(WCHAR) ); + else + { + RtlUnicodeToMultiByteN( buffer, size-1, &ret, buffW, len * sizeof(WCHAR) ); + buffer[ret] = 0; + } + return ret; +} + + +/* push some string data into the strings buffer */ +static WCHAR *push_string( struct inf_file *file, const WCHAR *string ) +{ + WCHAR *ret = file->string_pos; + strcpyW( ret, string ); + file->string_pos += strlenW( ret ) + 1; + return ret; +} + + +/* push the current state on the parser stack */ +inline static void push_state( struct parser *parser, enum parser_state state ) +{ + assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) ); + parser->stack[parser->stack_pos++] = state; +} + + +/* pop the current state */ +inline static void pop_state( struct parser *parser ) +{ + assert( parser->stack_pos ); + parser->state = parser->stack[--parser->stack_pos]; +} + + +/* set the parser state and return the previous one */ +inline static enum parser_state set_state( struct parser *parser, enum parser_state state ) +{ + enum parser_state ret = parser->state; + parser->state = state; + return ret; +} + + +/* check if the pointer points to an end of file */ +inline static int is_eof( struct parser *parser, const WCHAR *ptr ) +{ + return (ptr >= parser->end || *ptr == CONTROL_Z); +} + + +/* check if the pointer points to an end of line */ +inline static int is_eol( struct parser *parser, const WCHAR *ptr ) +{ + return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\n'); +} + + +/* push data from current token start up to pos into the current token */ +static int push_token( struct parser *parser, const WCHAR *pos ) +{ + int len = pos - parser->start; + const WCHAR *src = parser->start; + WCHAR *dst = parser->token + parser->token_len; + + if (len > MAX_FIELD_LEN - parser->token_len) len = MAX_FIELD_LEN - parser->token_len; + + parser->token_len += len; + for ( ; len > 0; len--, dst++, src++) *dst = *src ? *src : ' '; + *dst = 0; + parser->start = pos; + return 0; +} + + +/* add a section with the current token as name */ +static int add_section_from_token( struct parser *parser ) +{ + int section_index; + + if (parser->token_len > MAX_SECTION_NAME_LEN) + { + parser->error = ERROR_SECTION_NAME_TOO_LONG; + return -1; + } + if ((section_index = find_section( parser->file, parser->token )) == -1) + { + /* need to create a new one */ + const WCHAR *name = push_string( parser->file, parser->token ); + if ((section_index = add_section( parser->file, name )) == -1) + { + parser->error = ERROR_NOT_ENOUGH_MEMORY; + return -1; + } + } + parser->token_len = 0; + parser->cur_section = section_index; + return section_index; +} + + +/* add a field containing the current token to the current line */ +static struct field *add_field_from_token( struct parser *parser, int is_key ) +{ + struct field *field; + WCHAR *text; + + if (!parser->line) /* need to start a new line */ + { + if (parser->cur_section == -1) /* got a line before the first section */ + { + parser->error = ERROR_WRONG_INF_STYLE; + return NULL; + } + if (!(parser->line = add_line( parser->file, parser->cur_section ))) goto error; + } + else assert(!is_key); + + text = push_string( parser->file, parser->token ); + if ((field = add_field( parser->file, text ))) + { + if (!is_key) parser->line->nb_fields++; + else + { + /* replace first field by key field */ + parser->line->key_field = parser->line->first_field; + parser->line->first_field++; + } + parser->token_len = 0; + return field; + } + error: + parser->error = ERROR_NOT_ENOUGH_MEMORY; + return NULL; +} + + +/* close the current line and prepare for parsing a new one */ +static void close_current_line( struct parser *parser ) +{ + struct line *cur_line = parser->line; + + if (cur_line) + { + /* if line has a single field and no key, the field is the key too */ + if (cur_line->nb_fields == 1 && cur_line->key_field == -1) + cur_line->key_field = cur_line->first_field; + } + parser->line = NULL; +} + + +/* handler for parser LINE_START state */ +static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { + case '\n': + parser->line_pos++; + close_current_line( parser ); + break; + case ';': + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case '[': + parser->start = p + 1; + set_state( parser, SECTION_NAME ); + return p + 1; + default: + if (!isspaceW(*p)) + { + parser->start = p; + set_state( parser, KEY_NAME ); + return p; + } + break; + } + } + close_current_line( parser ); + return NULL; +} + + +/* handler for parser SECTION_NAME state */ +static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == ']') + { + push_token( parser, p ); + if (add_section_from_token( parser ) == -1) return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); /* ignore everything else on the line */ + return p + 1; + } + } + parser->error = ERROR_BAD_SECTION_NAME_LINE; /* unfinished section name */ + return NULL; +} + + +/* handler for parser KEY_NAME state */ +static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == ',') break; + switch(*p) + { + + case '=': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 1 )) return NULL; + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, LEADING_SPACES ); + return p + 1; + case ';': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case '"': + push_token( parser, token_end ); + parser->start = p + 1; + push_state( parser, KEY_NAME ); + set_state( parser, QUOTES ); + return p + 1; + case '\\': + push_token( parser, token_end ); + parser->start = p; + push_state( parser, KEY_NAME ); + set_state( parser, EOL_BACKSLASH ); + return p; + default: + if (!isspaceW(*p)) token_end = p + 1; + else + { + push_token( parser, p ); + push_state( parser, KEY_NAME ); + set_state( parser, TRAILING_SPACES ); + return p; + } + break; + } + } + push_token( parser, token_end ); + set_state( parser, VALUE_NAME ); + return p; +} + + +/* handler for parser VALUE_NAME state */ +static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + switch(*p) + { + case ';': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case ',': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, LEADING_SPACES ); + return p + 1; + case '"': + push_token( parser, token_end ); + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, QUOTES ); + return p + 1; + case '\\': + push_token( parser, token_end ); + parser->start = p; + push_state( parser, VALUE_NAME ); + set_state( parser, EOL_BACKSLASH ); + return p; + default: + if (!isspaceW(*p)) token_end = p + 1; + else + { + push_token( parser, p ); + push_state( parser, VALUE_NAME ); + set_state( parser, TRAILING_SPACES ); + return p; + } + break; + } + } + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + set_state( parser, LINE_START ); + return p; +} + + +/* handler for parser EOL_BACKSLASH state */ +static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { + case '\n': + parser->line_pos++; + parser->start = p + 1; + set_state( parser, LEADING_SPACES ); + return p + 1; + case '\\': + continue; + case ';': + push_state( parser, EOL_BACKSLASH ); + set_state( parser, COMMENT ); + return p + 1; + default: + if (isspaceW(*p)) continue; + push_token( parser, p ); + pop_state( parser ); + return p; + } + } + parser->start = p; + pop_state( parser ); + return p; +} + + +/* handler for parser QUOTES state */ +static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '"') + { + if (p+1 < parser->end && p[1] == '"') /* double quotes */ + { + push_token( parser, p + 1 ); + parser->start = token_end = p + 2; + p++; + } + else /* end of quotes */ + { + push_token( parser, p ); + parser->start = p + 1; + pop_state( parser ); + return p + 1; + } + } + } + push_token( parser, p ); + pop_state( parser ); + return p; +} + + +/* handler for parser LEADING_SPACES state */ +static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + parser->start = p; + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!isspaceW(*p)) break; + } + parser->start = p; + pop_state( parser ); + return p; +} + + +/* handler for parser TRAILING_SPACES state */ +static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!isspaceW(*p)) break; + } + pop_state( parser ); + return p; +} + + +/* handler for parser COMMENT state */ +static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p = pos; + + while (!is_eol( parser, p )) p++; + pop_state( parser ); + return p; +} + + +/* parse a complete buffer */ +static DWORD parse_buffer( struct inf_file *file, const WCHAR *buffer, const WCHAR *end, + UINT *error_line ) +{ + static const WCHAR Strings[] = {'S','t','r','i','n','g','s',0}; + + struct parser parser; + const WCHAR *pos = buffer; + + parser.start = buffer; + parser.end = end; + parser.file = file; + parser.line = NULL; + parser.state = LINE_START; + parser.stack_pos = 0; + parser.cur_section = -1; + parser.line_pos = 1; + parser.error = 0; + parser.token_len = 0; + + /* parser main loop */ + while (pos) pos = (parser_funcs[parser.state])( &parser, pos ); + + /* trim excess buffer space */ + if (file->alloc_sections > file->nb_sections) + { + file->sections = HeapReAlloc( GetProcessHeap(), 0, file->sections, + file->nb_sections * sizeof(file->sections[0]) ); + file->alloc_sections = file->nb_sections; + } + if (file->alloc_fields > file->nb_fields) + { + file->fields = HeapReAlloc( GetProcessHeap(), 0, file->fields, + file->nb_fields * sizeof(file->fields[0]) ); + file->alloc_fields = file->nb_fields; + } + file->strings = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, file->strings, + (file->string_pos - file->strings) * sizeof(WCHAR) ); + + if (parser.error) + { + if (error_line) *error_line = parser.line_pos; + return parser.error; + } + + /* find the [strings] section */ + file->strings_section = find_section( file, Strings ); + return 0; +} + + +/* append a child INF file to its parent list, in a thread-safe manner */ +static void append_inf_file( struct inf_file *parent, struct inf_file *child ) +{ + struct inf_file **ppnext = &parent->next; + child->next = NULL; + + for (;;) + { + struct inf_file *next = InterlockedCompareExchangePointer( (void **)ppnext, child, NULL ); + if (!next) return; + ppnext = &next->next; + } +} + + +/*********************************************************************** + * parse_file + * + * parse an INF file. + */ +static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *error_line ) +{ + void *buffer; + DWORD err = 0; + struct inf_file *file; + + DWORD size = GetFileSize( handle, NULL ); + HANDLE mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, size, NULL ); + if (!mapping) return NULL; + buffer = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size ); + NtClose( mapping ); + if (!buffer) return NULL; + + if (class) FIXME( "class %s not supported yet\n", debugstr_w(class) ); + + if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) ))) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + /* we won't need more strings space than the size of the file, + * so we can preallocate it here + */ + if (!(file->strings = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + file->string_pos = file->strings; + file->strings_section = -1; + + if (!RtlIsTextUnicode( buffer, size, NULL )) + { + WCHAR *new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + if (new_buff) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, buffer, size, new_buff, + size * sizeof(WCHAR) ); + err = parse_buffer( file, new_buff, new_buff + len, error_line ); + HeapFree( GetProcessHeap(), 0, new_buff ); + } + } + else err = parse_buffer( file, buffer, (WCHAR *)((char *)buffer + size), error_line ); + + if (!err) /* now check signature */ + { + int version_index = find_section( file, Version ); + if (version_index != -1) + { + struct line *line = find_line( file, version_index, Signature ); + if (line && line->nb_fields > 0) + { + struct field *field = file->fields + line->first_field; + if (!strcmpiW( field->text, Chicago )) goto done; + if (!strcmpiW( field->text, WindowsNT )) goto done; + if (!strcmpiW( field->text, Windows95 )) goto done; + } + } + err = ERROR_WRONG_INF_STYLE; + } + + done: + UnmapViewOfFile( buffer ); + if (err) + { + HeapFree( GetProcessHeap(), 0, file ); + SetLastError( err ); + file = NULL; + } + return file; +} + + +/*********************************************************************** + * PARSER_get_src_root + * + * Retrieve the source directory of an inf file. + */ +const WCHAR *PARSER_get_src_root( HINF hinf ) +{ + struct inf_file *file = hinf; + return file->src_root; +} + + +/*********************************************************************** + * PARSER_get_dest_dir + * + * retrieve a destination dir of the form "dirid,relative_path" in the given entry. + * returned buffer must be freed by caller. + */ +WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) +{ + const WCHAR *dir; + WCHAR *ptr, *ret; + INT dirid; + DWORD len1, len2; + + if (!SetupGetIntField( context, 1, &dirid )) return NULL; + if (!(dir = DIRID_get_string( context->Inf, dirid ))) return NULL; + len1 = strlenW(dir) + 1; + if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0; + if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL; + strcpyW( ret, dir ); + ptr = ret + strlenW(ret); + if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\'; + if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0; + return ret; +} + + +/*********************************************************************** + * SetupOpenInfFileA (SETUPAPI.@) + */ +HINF WINAPI SetupOpenInfFileA( PCSTR name, PCSTR class, DWORD style, UINT *error ) +{ + UNICODE_STRING nameW, classW; + HINF ret = (HINF)INVALID_HANDLE_VALUE; + + classW.Buffer = NULL; + if (class && !RtlCreateUnicodeStringFromAsciiz( &classW, class )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return ret; + } + if (RtlCreateUnicodeStringFromAsciiz( &nameW, name )) + { + ret = SetupOpenInfFileW( nameW.Buffer, classW.Buffer, style, error ); + RtlFreeUnicodeString( &nameW ); + } + RtlFreeUnicodeString( &classW ); + return ret; +} + + +/*********************************************************************** + * SetupOpenInfFileW (SETUPAPI.@) + */ +HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *error ) +{ + struct inf_file *file = NULL; + HANDLE handle; + WCHAR *path, *p; + UINT len; + + if (strchrW( name, '\\' ) || strchrW( name, '/' )) + { + if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return (HINF)INVALID_HANDLE_VALUE; + if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return (HINF)INVALID_HANDLE_VALUE; + } + GetFullPathNameW( name, len, path, NULL ); + handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + } + else /* try Windows directory */ + { + static const WCHAR Inf[] = {'\\','i','n','f','\\',0}; + static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0}; + + len = GetWindowsDirectoryW( NULL, 0 ) + strlenW(name) + 12; + if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return (HINF)INVALID_HANDLE_VALUE; + } + GetWindowsDirectoryW( path, len ); + p = path + strlenW(path); + strcpyW( p, Inf ); + strcatW( p, name ); + handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + { + strcpyW( p, System32 ); + strcatW( p, name ); + handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + } + } + + if (handle != INVALID_HANDLE_VALUE) + { + file = parse_file( handle, class, error ); + CloseHandle( handle ); + } + if (!file) + { + HeapFree( GetProcessHeap(), 0, path ); + return (HINF)INVALID_HANDLE_VALUE; + } + TRACE( "%s -> %p\n", debugstr_w(path), file ); + file->src_root = path; + if ((p = strrchrW( path, '\\' ))) p[1] = 0; /* remove file name */ + SetLastError( 0 ); + return (HINF)file; +} + + +/*********************************************************************** + * SetupOpenAppendInfFileA (SETUPAPI.@) + */ +BOOL WINAPI SetupOpenAppendInfFileA( PCSTR name, HINF parent_hinf, UINT *error ) +{ + HINF child_hinf; + + if (!name) return SetupOpenAppendInfFileW( NULL, parent_hinf, error ); + child_hinf = SetupOpenInfFileA( name, NULL, INF_STYLE_WIN4, error ); + if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE; + append_inf_file( parent_hinf, child_hinf ); + TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_a(name), child_hinf ); + return TRUE; +} + + +/*********************************************************************** + * SetupOpenAppendInfFileW (SETUPAPI.@) + */ +BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error ) +{ + HINF child_hinf; + + if (!name) + { + INFCONTEXT context; + WCHAR filename[MAX_PATH]; + int idx = 1; + + if (!SetupFindFirstLineW( parent_hinf, Version, LayoutFile, &context )) return FALSE; + while (SetupGetStringFieldW( &context, idx++, filename, + sizeof(filename)/sizeof(WCHAR), NULL )) + { + child_hinf = SetupOpenInfFileW( filename, NULL, INF_STYLE_WIN4, error ); + if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE; + append_inf_file( parent_hinf, child_hinf ); + TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(filename), child_hinf ); + } + return TRUE; + } + child_hinf = SetupOpenInfFileW( name, NULL, INF_STYLE_WIN4, error ); + if (child_hinf == (HINF)INVALID_HANDLE_VALUE) return FALSE; + append_inf_file( parent_hinf, child_hinf ); + TRACE( "%p: appended %s (%p)\n", parent_hinf, debugstr_w(name), child_hinf ); + return TRUE; +} + + +/*********************************************************************** + * SetupOpenMasterInf (SETUPAPI.@) + */ +HINF WINAPI SetupOpenMasterInf( VOID ) +{ + static const WCHAR Layout[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0}; + WCHAR Buffer[MAX_PATH]; + + GetWindowsDirectoryW( Buffer, MAX_PATH ); + strcatW( Buffer, Layout ); + return SetupOpenInfFileW( Buffer, NULL, INF_STYLE_WIN4, NULL); +} + + + +/*********************************************************************** + * SetupCloseInfFile (SETUPAPI.@) + */ +void WINAPI SetupCloseInfFile( HINF hinf ) +{ + struct inf_file *file = hinf; + unsigned int i; + + for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] ); + HeapFree( GetProcessHeap(), 0, file->src_root ); + HeapFree( GetProcessHeap(), 0, file->sections ); + HeapFree( GetProcessHeap(), 0, file->fields ); + HeapFree( GetProcessHeap(), 0, file->strings ); + HeapFree( GetProcessHeap(), 0, file ); +} + + +/*********************************************************************** + * SetupGetLineCountA (SETUPAPI.@) + */ +LONG WINAPI SetupGetLineCountA( HINF hinf, PCSTR name ) +{ + UNICODE_STRING sectionW; + LONG ret = -1; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, name )) + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + else + { + ret = SetupGetLineCountW( hinf, sectionW.Buffer ); + RtlFreeUnicodeString( §ionW ); + } + return ret; +} + + +/*********************************************************************** + * SetupGetLineCountW (SETUPAPI.@) + */ +LONG WINAPI SetupGetLineCountW( HINF hinf, PCWSTR section ) +{ + struct inf_file *file = hinf; + int section_index; + LONG ret = -1; + + for (file = hinf; file; file = file->next) + { + if ((section_index = find_section( file, section )) == -1) continue; + if (ret == -1) ret = 0; + ret += file->sections[section_index]->nb_lines; + } + TRACE( "(%p,%s) returning %ld\n", hinf, debugstr_w(section), ret ); + SetLastError( (ret == -1) ? ERROR_SECTION_NOT_FOUND : 0 ); + return ret; +} + + +/*********************************************************************** + * SetupGetLineByIndexA (SETUPAPI.@) + */ +BOOL WINAPI SetupGetLineByIndexA( HINF hinf, PCSTR section, DWORD index, INFCONTEXT *context ) +{ + UNICODE_STRING sectionW; + BOOL ret = FALSE; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + else + { + ret = SetupGetLineByIndexW( hinf, sectionW.Buffer, index, context ); + RtlFreeUnicodeString( §ionW ); + } + return ret; +} + + +/*********************************************************************** + * SetupGetLineByIndexW (SETUPAPI.@) + */ +BOOL WINAPI SetupGetLineByIndexW( HINF hinf, PCWSTR section, DWORD index, INFCONTEXT *context ) +{ + struct inf_file *file = hinf; + int section_index; + + SetLastError( ERROR_SECTION_NOT_FOUND ); + for (file = hinf; file; file = file->next) + { + if ((section_index = find_section( file, section )) == -1) continue; + SetLastError( ERROR_LINE_NOT_FOUND ); + if (index < file->sections[section_index]->nb_lines) + { + context->Inf = hinf; + context->CurrentInf = file; + context->Section = section_index; + context->Line = index; + SetLastError( 0 ); + TRACE( "(%p,%s): returning %d/%ld\n", + hinf, debugstr_w(section), section_index, index ); + return TRUE; + } + index -= file->sections[section_index]->nb_lines; + } + TRACE( "(%p,%s) not found\n", hinf, debugstr_w(section) ); + return FALSE; +} + + +/*********************************************************************** + * SetupFindFirstLineA (SETUPAPI.@) + */ +BOOL WINAPI SetupFindFirstLineA( HINF hinf, PCSTR section, PCSTR key, INFCONTEXT *context ) +{ + UNICODE_STRING sectionW, keyW; + BOOL ret = FALSE; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + + if (!key) ret = SetupFindFirstLineW( hinf, sectionW.Buffer, NULL, context ); + else + { + if (RtlCreateUnicodeStringFromAsciiz( &keyW, key )) + { + ret = SetupFindFirstLineW( hinf, sectionW.Buffer, keyW.Buffer, context ); + RtlFreeUnicodeString( &keyW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + RtlFreeUnicodeString( §ionW ); + return ret; +} + + +/*********************************************************************** + * SetupFindFirstLineW (SETUPAPI.@) + */ +BOOL WINAPI SetupFindFirstLineW( HINF hinf, PCWSTR section, PCWSTR key, INFCONTEXT *context ) +{ + struct inf_file *file; + int section_index; + + SetLastError( ERROR_SECTION_NOT_FOUND ); + for (file = hinf; file; file = file->next) + { + if ((section_index = find_section( file, section )) == -1) continue; + if (key) + { + INFCONTEXT ctx; + ctx.Inf = hinf; + ctx.CurrentInf = file; + ctx.Section = section_index; + ctx.Line = -1; + return SetupFindNextMatchLineW( &ctx, key, context ); + } + SetLastError( ERROR_LINE_NOT_FOUND ); /* found at least one section */ + if (file->sections[section_index]->nb_lines) + { + context->Inf = hinf; + context->CurrentInf = file; + context->Section = section_index; + context->Line = 0; + SetLastError( 0 ); + TRACE( "(%p,%s,%s): returning %d/0\n", + hinf, debugstr_w(section), debugstr_w(key), section_index ); + return TRUE; + } + } + TRACE( "(%p,%s,%s): not found\n", hinf, debugstr_w(section), debugstr_w(key) ); + return FALSE; +} + + +/*********************************************************************** + * SetupFindNextLine (SETUPAPI.@) + */ +BOOL WINAPI SetupFindNextLine( PINFCONTEXT context_in, PINFCONTEXT context_out ) +{ + struct inf_file *file = context_in->CurrentInf; + struct section *section; + + if (context_in->Section >= file->nb_sections) goto error; + + section = file->sections[context_in->Section]; + if (context_in->Line+1 < section->nb_lines) + { + if (context_out != context_in) *context_out = *context_in; + context_out->Line++; + SetLastError( 0 ); + return TRUE; + } + + /* now search the appended files */ + + for (file = file->next; file; file = file->next) + { + int section_index = find_section( file, section->name ); + if (section_index == -1) continue; + if (file->sections[section_index]->nb_lines) + { + context_out->Inf = context_in->Inf; + context_out->CurrentInf = file; + context_out->Section = section_index; + context_out->Line = 0; + SetLastError( 0 ); + return TRUE; + } + } + error: + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; +} + + +/*********************************************************************** + * SetupFindNextMatchLineA (SETUPAPI.@) + */ +BOOL WINAPI SetupFindNextMatchLineA( PINFCONTEXT context_in, PCSTR key, + PINFCONTEXT context_out ) +{ + UNICODE_STRING keyW; + BOOL ret = FALSE; + + if (!key) return SetupFindNextLine( context_in, context_out ); + + if (!RtlCreateUnicodeStringFromAsciiz( &keyW, key )) + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + else + { + ret = SetupFindNextMatchLineW( context_in, keyW.Buffer, context_out ); + RtlFreeUnicodeString( &keyW ); + } + return ret; +} + + +/*********************************************************************** + * SetupFindNextMatchLineW (SETUPAPI.@) + */ +BOOL WINAPI SetupFindNextMatchLineW( PINFCONTEXT context_in, PCWSTR key, + PINFCONTEXT context_out ) +{ + struct inf_file *file = context_in->CurrentInf; + struct section *section; + struct line *line; + unsigned int i; + + if (!key) return SetupFindNextLine( context_in, context_out ); + + if (context_in->Section >= file->nb_sections) goto error; + + section = file->sections[context_in->Section]; + + for (i = context_in->Line+1, line = §ion->lines[i]; i < section->nb_lines; i++, line++) + { + if (line->key_field == -1) continue; + if (!strcmpiW( key, file->fields[line->key_field].text )) + { + if (context_out != context_in) *context_out = *context_in; + context_out->Line = i; + SetLastError( 0 ); + TRACE( "(%p,%s,%s): returning %d\n", + file, debugstr_w(section->name), debugstr_w(key), i ); + return TRUE; + } + } + + /* now search the appended files */ + + for (file = file->next; file; file = file->next) + { + int section_index = find_section( file, section->name ); + if (section_index == -1) continue; + section = file->sections[section_index]; + for (i = 0, line = section->lines; i < section->nb_lines; i++, line++) + { + if (line->key_field == -1) continue; + if (!strcmpiW( key, file->fields[line->key_field].text )) + { + context_out->Inf = context_in->Inf; + context_out->CurrentInf = file; + context_out->Section = section_index; + context_out->Line = i; + SetLastError( 0 ); + TRACE( "(%p,%s,%s): returning %d/%d\n", + file, debugstr_w(section->name), debugstr_w(key), section_index, i ); + return TRUE; + } + } + } + TRACE( "(%p,%s,%s): not found\n", + context_in->CurrentInf, debugstr_w(section->name), debugstr_w(key) ); + error: + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; +} + + +/*********************************************************************** + * SetupGetLineTextW (SETUPAPI.@) + */ +BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_name, + PCWSTR key_name, PWSTR buffer, DWORD size, PDWORD required ) +{ + struct inf_file *file; + struct line *line; + struct field *field; + int i; + DWORD total = 0; + + if (!context) + { + INFCONTEXT new_context; + if (!SetupFindFirstLineW( hinf, section_name, key_name, &new_context )) return FALSE; + file = new_context.CurrentInf; + line = get_line( file, new_context.Section, new_context.Line ); + } + else + { + file = context->CurrentInf; + if (!(line = get_line( file, context->Section, context->Line ))) + { + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; + } + } + + for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) + total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1; + + if (required) *required = total; + if (buffer) + { + if (total > size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) + { + unsigned int len = PARSER_string_substW( file, field->text, buffer, size ); + if (i+1 < line->nb_fields) buffer[len] = ','; + buffer += len + 1; + } + } + return TRUE; +} + + +/*********************************************************************** + * SetupGetLineTextA (SETUPAPI.@) + */ +BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_name, + PCSTR key_name, PSTR buffer, DWORD size, PDWORD required ) +{ + struct inf_file *file; + struct line *line; + struct field *field; + int i; + DWORD total = 0; + + if (!context) + { + INFCONTEXT new_context; + if (!SetupFindFirstLineA( hinf, section_name, key_name, &new_context )) return FALSE; + file = new_context.CurrentInf; + line = get_line( file, new_context.Section, new_context.Line ); + } + else + { + file = context->CurrentInf; + if (!(line = get_line( file, context->Section, context->Line ))) + { + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; + } + } + + for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) + total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1; + + if (required) *required = total; + if (buffer) + { + if (total > size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++) + { + unsigned int len = PARSER_string_substA( file, field->text, buffer, size ); + if (i+1 < line->nb_fields) buffer[len] = ','; + buffer += len + 1; + } + } + return TRUE; +} + + +/*********************************************************************** + * SetupGetFieldCount (SETUPAPI.@) + */ +DWORD WINAPI SetupGetFieldCount( PINFCONTEXT context ) +{ + struct inf_file *file = context->CurrentInf; + struct line *line = get_line( file, context->Section, context->Line ); + + if (!line) return 0; + return line->nb_fields; +} + + +/*********************************************************************** + * SetupGetStringFieldA (SETUPAPI.@) + */ +BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, + DWORD size, PDWORD required ) +{ + struct inf_file *file = context->CurrentInf; + struct field *field = get_field( file, context->Section, context->Line, index ); + unsigned int len; + + SetLastError(0); + if (!field) return FALSE; + len = PARSER_string_substA( file, field->text, NULL, 0 ); + if (required) *required = len + 1; + if (buffer) + { + if (size <= len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + PARSER_string_substA( file, field->text, buffer, size ); + + TRACE( "context %p/%p/%d/%d index %ld returning %s\n", + context->Inf, context->CurrentInf, context->Section, context->Line, + index, debugstr_a(buffer) ); + } + return TRUE; +} + + +/*********************************************************************** + * SetupGetStringFieldW (SETUPAPI.@) + */ +BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, + DWORD size, PDWORD required ) +{ + struct inf_file *file = context->CurrentInf; + struct field *field = get_field( file, context->Section, context->Line, index ); + unsigned int len; + + SetLastError(0); + if (!field) return FALSE; + len = PARSER_string_substW( file, field->text, NULL, 0 ); + if (required) *required = len + 1; + if (buffer) + { + if (size <= len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + PARSER_string_substW( file, field->text, buffer, size ); + + TRACE( "context %p/%p/%d/%d index %ld returning %s\n", + context->Inf, context->CurrentInf, context->Section, context->Line, + index, debugstr_w(buffer) ); + } + return TRUE; +} + + +/*********************************************************************** + * SetupGetIntField (SETUPAPI.@) + */ +BOOL WINAPI SetupGetIntField( PINFCONTEXT context, DWORD index, PINT result ) +{ + char localbuff[20]; + char *end, *buffer = localbuff; + DWORD required; + INT res; + BOOL ret = FALSE; + + if (!SetupGetStringFieldA( context, index, localbuff, sizeof(localbuff), &required )) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE; + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required ))) return FALSE; + if (!SetupGetStringFieldA( context, index, buffer, required, NULL )) goto done; + } + res = strtol( buffer, &end, 0 ); + if (end != buffer && !*end) + { + *result = res; + ret = TRUE; + } + else SetLastError( ERROR_INVALID_DATA ); + + done: + if (buffer != localbuff) HeapFree( GetProcessHeap(), 0, buffer ); + return ret; +} + + +/*********************************************************************** + * SetupGetBinaryField (SETUPAPI.@) + */ +BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer, + DWORD size, LPDWORD required ) +{ + struct inf_file *file = context->CurrentInf; + struct line *line = get_line( file, context->Section, context->Line ); + struct field *field; + int i; + + if (!line) + { + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; + } + if (!index || index >= line->nb_fields) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + index--; /* fields start at 0 */ + if (required) *required = line->nb_fields - index; + if (!buffer) return TRUE; + if (size < line->nb_fields - index) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + field = &file->fields[line->first_field + index]; + for (i = index; i < line->nb_fields; i++, field++) + { + const WCHAR *p; + DWORD value = 0; + for (p = field->text; *p && isxdigitW(*p); p++) + { + if ((value <<= 4) > 255) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + if (*p <= '9') value |= (*p - '0'); + else value |= (tolowerW(*p) - 'a' + 10); + } + buffer[i - index] = value; + } + if (TRACE_ON(setupapi)) + { + TRACE( "%p/%p/%d/%d index %ld returning", + context->Inf, context->CurrentInf, context->Section, context->Line, index ); + for (i = index; i < line->nb_fields; i++) TRACE( " %02x", buffer[i - index] ); + TRACE( "\n" ); + } + return TRUE; +} + + +/*********************************************************************** + * SetupGetMultiSzFieldA (SETUPAPI.@) + */ +BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer, + DWORD size, LPDWORD required ) +{ + struct inf_file *file = context->CurrentInf; + struct line *line = get_line( file, context->Section, context->Line ); + struct field *field; + unsigned int len; + int i; + DWORD total = 1; + + if (!line) + { + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; + } + if (!index || index >= line->nb_fields) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + index--; /* fields start at 0 */ + field = &file->fields[line->first_field + index]; + for (i = index; i < line->nb_fields; i++, field++) + { + if (!(len = PARSER_string_substA( file, field->text, NULL, 0 ))) break; + total += len + 1; + } + + if (required) *required = total; + if (!buffer) return TRUE; + if (total > size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + field = &file->fields[line->first_field + index]; + for (i = index; i < line->nb_fields; i++, field++) + { + if (!(len = PARSER_string_substA( file, field->text, buffer, size ))) break; + buffer += len + 1; + } + *buffer = 0; /* add final null */ + return TRUE; +} + + +/*********************************************************************** + * SetupGetMultiSzFieldW (SETUPAPI.@) + */ +BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer, + DWORD size, LPDWORD required ) +{ + struct inf_file *file = context->CurrentInf; + struct line *line = get_line( file, context->Section, context->Line ); + struct field *field; + unsigned int len; + int i; + DWORD total = 1; + + if (!line) + { + SetLastError( ERROR_LINE_NOT_FOUND ); + return FALSE; + } + if (!index || index >= line->nb_fields) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + index--; /* fields start at 0 */ + field = &file->fields[line->first_field + index]; + for (i = index; i < line->nb_fields; i++, field++) + { + if (!(len = PARSER_string_substW( file, field->text, NULL, 0 ))) break; + total += len + 1; + } + + if (required) *required = total; + if (!buffer) return TRUE; + if (total > size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + field = &file->fields[line->first_field + index]; + for (i = index; i < line->nb_fields; i++, field++) + { + if (!(len = PARSER_string_substW( file, field->text, buffer, size ))) break; + buffer += len + 1; + } + *buffer = 0; /* add final null */ + return TRUE; +} diff --git a/reactos/lib/setupapi/queue.c b/reactos/lib/setupapi/queue.c new file mode 100644 index 00000000000..87693f01581 --- /dev/null +++ b/reactos/lib/setupapi/queue.c @@ -0,0 +1,1426 @@ +/* + * Setupapi file queue routines + * + * Copyright 2002 Alexandre Julliard for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "wine/unicode.h" +#include "setupapi_private.h" +#include "winver.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/* context structure for the default queue callback */ +struct default_callback_context +{ + HWND owner; + HWND progress; + UINT message; +}; + +struct file_op +{ + struct file_op *next; + UINT style; + WCHAR *src_root; + WCHAR *src_path; + WCHAR *src_file; + WCHAR *src_descr; + WCHAR *src_tag; + WCHAR *dst_path; + WCHAR *dst_file; +}; + +struct file_op_queue +{ + struct file_op *head; + struct file_op *tail; + unsigned int count; +}; + +struct file_queue +{ + struct file_op_queue copy_queue; + struct file_op_queue delete_queue; + struct file_op_queue rename_queue; + DWORD flags; +}; + + +inline static WCHAR *strdupW( const WCHAR *str ) +{ + WCHAR *ret = NULL; + if (str) + { + int len = (strlenW(str) + 1) * sizeof(WCHAR); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len ); + } + return ret; +} + + +inline static WCHAR *strdupAtoW( const char *str ) +{ + WCHAR *ret = NULL; + if (str) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); + } + return ret; +} + +inline static char *strdupWtoA( const WCHAR *str ) +{ + char *ret = NULL; + if (str) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) + WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + } + return ret; +} + +/* append a file operation to a queue */ +inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op ) +{ + op->next = NULL; + if (queue->tail) queue->tail->next = op; + else queue->head = op; + queue->tail = op; + queue->count++; +} + +/* free all the file operations on a given queue */ +static void free_file_op_queue( struct file_op_queue *queue ) +{ + struct file_op *t, *op = queue->head; + + while( op ) + { + HeapFree( GetProcessHeap(), 0, op->src_root ); + HeapFree( GetProcessHeap(), 0, op->src_path ); + HeapFree( GetProcessHeap(), 0, op->src_file ); + HeapFree( GetProcessHeap(), 0, op->src_descr ); + HeapFree( GetProcessHeap(), 0, op->src_tag ); + HeapFree( GetProcessHeap(), 0, op->dst_path ); + if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file ); + t = op; + op = op->next; + HeapFree( GetProcessHeap(), 0, t ); + } +} + +/* concat 3 strings to make a path, handling separators correctly */ +static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 ) +{ + *buffer = 0; + if (src1 && *src1) + { + strcpyW( buffer, src1 ); + buffer += strlenW(buffer ); + if (buffer[-1] != '\\') *buffer++ = '\\'; + if (src2) while (*src2 == '\\') src2++; + } + + if (src2) + { + strcpyW( buffer, src2 ); + buffer += strlenW(buffer ); + if (buffer[-1] != '\\') *buffer++ = '\\'; + if (src3) while (*src3 == '\\') src3++; + } + if (src3) + { + strcpyW( buffer, src3 ); + buffer += strlenW(buffer ); + } +} + + +/*********************************************************************** + * build_filepathsW + * + * Build a FILEPATHS_W structure for a given file operation. + */ +static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths ) +{ + unsigned int src_len = 1, dst_len = 1; + WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target; + + if (op->src_root) src_len += strlenW(op->src_root) + 1; + if (op->src_path) src_len += strlenW(op->src_path) + 1; + if (op->src_file) src_len += strlenW(op->src_file) + 1; + if (op->dst_path) dst_len += strlenW(op->dst_path) + 1; + if (op->dst_file) dst_len += strlenW(op->dst_file) + 1; + src_len *= sizeof(WCHAR); + dst_len *= sizeof(WCHAR); + + if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len ) + { + HeapFree( GetProcessHeap(), 0, source ); + paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len ); + } + if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len ) + { + HeapFree( GetProcessHeap(), 0, target ); + paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len ); + } + if (!source || !target) return FALSE; + concat_W( source, op->src_root, op->src_path, op->src_file ); + concat_W( target, NULL, op->dst_path, op->dst_file ); + paths->Win32Error = 0; + paths->Flags = 0; + return TRUE; +} + + +/*********************************************************************** + * QUEUE_callback_WtoA + * + * Map a file callback parameters from W to A and call the A callback. + */ +UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, + UINT_PTR param1, UINT_PTR param2 ) +{ + struct callback_WtoA_context *callback_ctx = context; + char buffer[MAX_PATH]; + UINT ret; + UINT_PTR old_param2 = param2; + + switch(notification) + { + case SPFILENOTIFY_COPYERROR: + param2 = (UINT_PTR)&buffer; + /* fall through */ + case SPFILENOTIFY_STARTDELETE: + case SPFILENOTIFY_ENDDELETE: + case SPFILENOTIFY_DELETEERROR: + case SPFILENOTIFY_STARTRENAME: + case SPFILENOTIFY_ENDRENAME: + case SPFILENOTIFY_RENAMEERROR: + case SPFILENOTIFY_STARTCOPY: + case SPFILENOTIFY_ENDCOPY: + { + FILEPATHS_W *pathsW = (FILEPATHS_W *)param1; + FILEPATHS_A pathsA; + + pathsA.Source = strdupWtoA( pathsW->Source ); + pathsA.Target = strdupWtoA( pathsW->Target ); + pathsA.Win32Error = pathsW->Win32Error; + pathsA.Flags = pathsW->Flags; + ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, + (UINT_PTR)&pathsA, param2 ); + HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source ); + HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target ); + } + if (notification == SPFILENOTIFY_COPYERROR) + MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH ); + break; + + case SPFILENOTIFY_STARTREGISTRATION: + case SPFILENOTIFY_ENDREGISTRATION: + { + SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1; + SP_REGISTER_CONTROL_STATUSA statusA; + + statusA.cbSize = sizeof(statusA); + statusA.FileName = strdupWtoA( statusW->FileName ); + statusA.Win32Error = statusW->Win32Error; + statusA.FailureCode = statusW->FailureCode; + ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, + (UINT_PTR)&statusA, param2 ); + HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName ); + } + break; + + case SPFILENOTIFY_NEEDMEDIA: + case SPFILENOTIFY_QUEUESCAN: + FIXME("mapping for %d not implemented\n",notification); + case SPFILENOTIFY_STARTQUEUE: + case SPFILENOTIFY_ENDQUEUE: + case SPFILENOTIFY_STARTSUBQUEUE: + case SPFILENOTIFY_ENDSUBQUEUE: + default: + ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 ); + break; + } + return ret; +} + + +/*********************************************************************** + * get_src_file_info + * + * Retrieve the source file information for a given file. + */ +static void get_src_file_info( HINF hinf, struct file_op *op ) +{ + static const WCHAR SourceDisksNames[] = + {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0}; + static const WCHAR SourceDisksFiles[] = + {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0}; + + INFCONTEXT file_ctx, disk_ctx; + INT id, diskid; + DWORD len, len2; + + /* find the SourceDisksFiles entry */ + if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx )) + { + const WCHAR *dir; + + if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return; + /* no specific info, use .inf file source directory */ + if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH ))) + op->src_root = strdupW( dir ); + return; + } + if (!SetupGetIntField( &file_ctx, 1, &diskid )) return; + + /* now find the diskid in the SourceDisksNames section */ + if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return; + for (;;) + { + if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break; + if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return; + } + + /* and fill in the missing info */ + + if (!op->src_descr) + { + if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && + (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ))) + SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL ); + } + if (!op->src_tag) + { + if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && + (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ))) + SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL ); + } + if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE)) + { + if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE)) + { + /* retrieve relative path for this disk */ + if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0; + } + /* retrieve relative path for this file */ + if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0; + + if ((len || len2) && + (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) ))) + { + WCHAR *ptr = op->src_path; + if (len) + { + SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL ); + ptr = op->src_path + strlenW(op->src_path); + if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\'; + } + if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0; + } + } + if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) ); +} + + +/*********************************************************************** + * get_destination_dir + * + * Retrieve the destination dir for a given section. + */ +static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) +{ + static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0}; + static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0}; + INFCONTEXT context; + + if (!SetupFindFirstLineW( hinf, Dest, section, &context ) && + !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL; + return PARSER_get_dest_dir( &context ); +} + + +static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD ); + +/*********************************************************************** + * extract_cabinet_file + * + * Extract a file from a .cab file. + */ +static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root, + const WCHAR *src, const WCHAR *dst ) +{ + static const WCHAR extW[] = {'.','c','a','b',0}; + static HMODULE advpack; + + char *cab_path, *cab_file; + int len = strlenW( cabinet ); + + /* make sure the cabinet file has a .cab extension */ + if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE; + if (!pExtractFiles) + { + if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" ))) + { + ERR( "could not load advpack.dll\n" ); + return FALSE; + } + if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" ))) + { + ERR( "could not find ExtractFiles in advpack.dll\n" ); + return FALSE; + } + } + + if (!(cab_path = strdupWtoA( root ))) return FALSE; + len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL ); + if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 ))) + { + HeapFree( GetProcessHeap(), 0, cab_path ); + return FALSE; + } + strcpy( cab_file, cab_path ); + if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" ); + WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL ); + FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) ); + pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 ); + HeapFree( GetProcessHeap(), 0, cab_file ); + HeapFree( GetProcessHeap(), 0, cab_path ); + return CopyFileW( src, dst, FALSE /*FIXME*/ ); +} + + +/*********************************************************************** + * SetupOpenFileQueue (SETUPAPI.@) + */ +HSPFILEQ WINAPI SetupOpenFileQueue(void) +{ + struct file_queue *queue; + + if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue)))) + return (HSPFILEQ)INVALID_HANDLE_VALUE; + return queue; +} + + +/*********************************************************************** + * SetupCloseFileQueue (SETUPAPI.@) + */ +BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle ) +{ + struct file_queue *queue = handle; + + free_file_op_queue( &queue->copy_queue ); + free_file_op_queue( &queue->rename_queue ); + free_file_op_queue( &queue->delete_queue ); + HeapFree( GetProcessHeap(), 0, queue ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueCopyIndirectA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params ) +{ + struct file_queue *queue = params->QueueHandle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = params->CopyStyle; + op->src_root = strdupAtoW( params->SourceRootPath ); + op->src_path = strdupAtoW( params->SourcePath ); + op->src_file = strdupAtoW( params->SourceFilename ); + op->src_descr = strdupAtoW( params->SourceDescription ); + op->src_tag = strdupAtoW( params->SourceTagfile ); + op->dst_path = strdupAtoW( params->TargetDirectory ); + op->dst_file = strdupAtoW( params->TargetFilename ); + + /* some defaults */ + if (!op->src_file) op->src_file = op->dst_file; + if (params->LayoutInf) + { + get_src_file_info( params->LayoutInf, op ); + if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); + } + + TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", + debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), + debugstr_w(op->dst_path), debugstr_w(op->dst_file), + debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); + + queue_file_op( &queue->copy_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueCopyIndirectW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) +{ + struct file_queue *queue = params->QueueHandle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = params->CopyStyle; + op->src_root = strdupW( params->SourceRootPath ); + op->src_path = strdupW( params->SourcePath ); + op->src_file = strdupW( params->SourceFilename ); + op->src_descr = strdupW( params->SourceDescription ); + op->src_tag = strdupW( params->SourceTagfile ); + op->dst_path = strdupW( params->TargetDirectory ); + op->dst_file = strdupW( params->TargetFilename ); + + /* some defaults */ + if (!op->src_file) op->src_file = op->dst_file; + if (params->LayoutInf) + { + get_src_file_info( params->LayoutInf, op ); + if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); + } + + TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", + debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), + debugstr_w(op->dst_path), debugstr_w(op->dst_file), + debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); + + queue_file_op( &queue->copy_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueCopyA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file, + PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file, + DWORD style ) +{ + SP_FILE_COPY_PARAMS_A params; + + params.cbSize = sizeof(params); + params.QueueHandle = queue; + params.SourceRootPath = src_root; + params.SourcePath = src_path; + params.SourceFilename = src_file; + params.SourceDescription = src_descr; + params.SourceTagfile = src_tag; + params.TargetDirectory = dst_dir; + params.TargetFilename = dst_file; + params.CopyStyle = style; + params.LayoutInf = 0; + params.SecurityDescriptor = NULL; + return SetupQueueCopyIndirectA( ¶ms ); +} + + +/*********************************************************************** + * SetupQueueCopyW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file, + PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file, + DWORD style ) +{ + SP_FILE_COPY_PARAMS_W params; + + params.cbSize = sizeof(params); + params.QueueHandle = queue; + params.SourceRootPath = src_root; + params.SourcePath = src_path; + params.SourceFilename = src_file; + params.SourceDescription = src_descr; + params.SourceTagfile = src_tag; + params.TargetDirectory = dst_dir; + params.TargetFilename = dst_file; + params.CopyStyle = style; + params.LayoutInf = 0; + params.SecurityDescriptor = NULL; + return SetupQueueCopyIndirectW( ¶ms ); +} + + +/*********************************************************************** + * SetupQueueDefaultCopyA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file, + PCSTR dst_file, DWORD style ) +{ + SP_FILE_COPY_PARAMS_A params; + + params.cbSize = sizeof(params); + params.QueueHandle = queue; + params.SourceRootPath = src_root; + params.SourcePath = NULL; + params.SourceFilename = src_file; + params.SourceDescription = NULL; + params.SourceTagfile = NULL; + params.TargetDirectory = NULL; + params.TargetFilename = dst_file; + params.CopyStyle = style; + params.LayoutInf = hinf; + params.SecurityDescriptor = NULL; + return SetupQueueCopyIndirectA( ¶ms ); +} + + +/*********************************************************************** + * SetupQueueDefaultCopyW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file, + PCWSTR dst_file, DWORD style ) +{ + SP_FILE_COPY_PARAMS_W params; + + params.cbSize = sizeof(params); + params.QueueHandle = queue; + params.SourceRootPath = src_root; + params.SourcePath = NULL; + params.SourceFilename = src_file; + params.SourceDescription = NULL; + params.SourceTagfile = NULL; + params.TargetDirectory = NULL; + params.TargetFilename = dst_file; + params.CopyStyle = style; + params.LayoutInf = hinf; + params.SecurityDescriptor = NULL; + return SetupQueueCopyIndirectW( ¶ms ); +} + + +/*********************************************************************** + * SetupQueueDeleteA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 ) +{ + struct file_queue *queue = handle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = 0; + op->src_root = NULL; + op->src_path = NULL; + op->src_file = NULL; + op->src_descr = NULL; + op->src_tag = NULL; + op->dst_path = strdupAtoW( part1 ); + op->dst_file = strdupAtoW( part2 ); + queue_file_op( &queue->delete_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueDeleteW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 ) +{ + struct file_queue *queue = handle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = 0; + op->src_root = NULL; + op->src_path = NULL; + op->src_file = NULL; + op->src_descr = NULL; + op->src_tag = NULL; + op->dst_path = strdupW( part1 ); + op->dst_file = strdupW( part2 ); + queue_file_op( &queue->delete_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueRenameA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename, + PCSTR TargetPath, PCSTR TargetFilename ) +{ + struct file_queue *queue = handle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = 0; + op->src_root = NULL; + op->src_path = strdupAtoW( SourcePath ); + op->src_file = strdupAtoW( SourceFilename ); + op->src_descr = NULL; + op->src_tag = NULL; + op->dst_path = strdupAtoW( TargetPath ); + op->dst_file = strdupAtoW( TargetFilename ); + queue_file_op( &queue->rename_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueRenameW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename, + PCWSTR TargetPath, PCWSTR TargetFilename ) +{ + struct file_queue *queue = handle; + struct file_op *op; + + if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; + op->style = 0; + op->src_root = NULL; + op->src_path = strdupW( SourcePath ); + op->src_file = strdupW( SourceFilename ); + op->src_descr = NULL; + op->src_tag = NULL; + op->dst_path = strdupW( TargetPath ); + op->dst_file = strdupW( TargetFilename ); + queue_file_op( &queue->rename_queue, op ); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueCopySectionA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist, + PCSTR section, DWORD style ) +{ + UNICODE_STRING sectionW; + BOOL ret = FALSE; + + if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + if (!src_root) + ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style ); + else + { + UNICODE_STRING srcW; + if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root )) + { + ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style ); + RtlFreeUnicodeString( &srcW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + RtlFreeUnicodeString( §ionW ); + return ret; +} + + +/*********************************************************************** + * SetupQueueCopySectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist, + PCWSTR section, DWORD style ) +{ + SP_FILE_COPY_PARAMS_W params; + INFCONTEXT context; + WCHAR dest[MAX_PATH], src[MAX_PATH]; + INT flags; + + TRACE( "hinf=%p/%p section=%s root=%s\n", + hinf, hlist, debugstr_w(section), debugstr_w(src_root) ); + + params.cbSize = sizeof(params); + params.QueueHandle = queue; + params.SourceRootPath = src_root; + params.SourcePath = NULL; + params.SourceDescription = NULL; + params.SourceTagfile = NULL; + params.TargetFilename = dest; + params.CopyStyle = style; + params.LayoutInf = hinf; + params.SecurityDescriptor = NULL; + + if (!hlist) hlist = hinf; + if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE; + if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE; + do + { + if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL )) + return FALSE; + if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0; + if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */ + + params.SourceFilename = *src ? src : NULL; + if (!SetupQueueCopyIndirectW( ¶ms )) return FALSE; + } while (SetupFindNextLine( &context, &context )); + return TRUE; +} + + +/*********************************************************************** + * SetupQueueDeleteSectionA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) +{ + UNICODE_STRING sectionW; + BOOL ret = FALSE; + + if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer ); + RtlFreeUnicodeString( §ionW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return ret; +} + + +/*********************************************************************** + * SetupQueueDeleteSectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section ) +{ + INFCONTEXT context; + WCHAR *dest_dir; + WCHAR buffer[MAX_PATH]; + BOOL ret = FALSE; + INT flags; + + TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) ); + + if (!hlist) hlist = hinf; + if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE; + if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE; + do + { + if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) + goto done; + if (!SetupGetIntField( &context, 4, &flags )) flags = 0; + if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done; + } while (SetupFindNextLine( &context, &context )); + + ret = TRUE; + done: + HeapFree( GetProcessHeap(), 0, dest_dir ); + return ret; +} + + +/*********************************************************************** + * SetupQueueRenameSectionA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) +{ + UNICODE_STRING sectionW; + BOOL ret = FALSE; + + if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) + { + ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer ); + RtlFreeUnicodeString( §ionW ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return ret; +} + + +/*********************************************************************** + * SetupQueueRenameSectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section ) +{ + INFCONTEXT context; + WCHAR *dest_dir; + WCHAR src[MAX_PATH], dst[MAX_PATH]; + BOOL ret = FALSE; + + TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) ); + + if (!hlist) hlist = hinf; + if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE; + if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE; + do + { + if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL )) + goto done; + if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) + goto done; + if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done; + } while (SetupFindNextLine( &context, &context )); + + ret = TRUE; + done: + HeapFree( GetProcessHeap(), 0, dest_dir ); + return ret; +} + + +/*********************************************************************** + * SetupCommitFileQueueA (SETUPAPI.@) + */ +BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler, + PVOID context ) +{ + struct callback_WtoA_context ctx; + + ctx.orig_context = context; + ctx.orig_handler = handler; + return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx ); +} + + +/*********************************************************************** + * create_full_pathW + * + * Recursively create all directories in the path. + */ +static BOOL create_full_pathW(const WCHAR *path) +{ + BOOL ret = TRUE; + int len; + WCHAR *new_path; + + new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR)); + strcpyW(new_path, path); + + while((len = strlenW(new_path)) && new_path[len - 1] == '\\') + new_path[len - 1] = 0; + + while(!CreateDirectoryW(new_path, NULL)) + { + WCHAR *slash; + DWORD last_error = GetLastError(); + + if(last_error == ERROR_ALREADY_EXISTS) + break; + + if(last_error != ERROR_PATH_NOT_FOUND) + { + ret = FALSE; + break; + } + + if(!(slash = strrchrW(new_path, '\\'))) + { + ret = FALSE; + break; + } + + len = slash - new_path; + new_path[len] = 0; + if(!create_full_pathW(new_path)) + { + ret = FALSE; + break; + } + new_path[len] = '\\'; + } + + HeapFree(GetProcessHeap(), 0, new_path); + return ret; +} + +BOOL static do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style) +{ + BOOL rc = FALSE; + BOOL docopy = TRUE; + + TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style); + + /* before copy processing */ + if (style & SP_COPY_REPLACEONLY) + { + if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES) + docopy = FALSE; + } + if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER)) + { + DWORD VersionSizeSource=0; + DWORD VersionSizeTarget=0; + DWORD zero=0; + + /* + * This is sort of an interesting workaround. You see, calling + * GetVersionInfoSize on a builtin dll loads that dll into memory + * and we do not properly unload builtin dlls.. so we effectively + * lock into memory all the targets we are replacing. This leads + * to problems when we try to register the replaced dlls. + * + * So I will test for the existence of the files first so that + * we just basically unconditionally replace the builtin versions. + */ + if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) && + (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES)) + { + VersionSizeSource = GetFileVersionInfoSizeW(source,&zero); + VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero); + } + + TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget, + VersionSizeSource); + + if (VersionSizeSource && VersionSizeTarget) + { + LPVOID VersionSource; + LPVOID VersionTarget; + VS_FIXEDFILEINFO *TargetInfo; + VS_FIXEDFILEINFO *SourceInfo; + UINT length; + WCHAR SubBlock[2]={'\\',0}; + DWORD ret; + + VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource); + VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget); + + ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource); + if (ret) + ret = GetFileVersionInfoW(target, 0, VersionSizeTarget, + VersionTarget); + + if (ret) + { + ret = VerQueryValueW(VersionSource, SubBlock, + (LPVOID*)&SourceInfo, &length); + if (ret) + ret = VerQueryValueW(VersionTarget, SubBlock, + (LPVOID*)&TargetInfo, &length); + + if (ret) + { + TRACE("Versions: Source %li.%li target %li.%li\n", + SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS, + TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS); + + if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS) + { + FIXME("Notify that target version is greater..\n"); + docopy = FALSE; + } + else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS) + && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS)) + { + FIXME("Notify that target version is greater..\n"); + docopy = FALSE; + } + else if ((style & SP_COPY_NEWER_ONLY) && + (TargetInfo->dwFileVersionMS == + SourceInfo->dwFileVersionMS) + &&(TargetInfo->dwFileVersionLS == + SourceInfo->dwFileVersionLS)) + { + FIXME("Notify that target version is greater..\n"); + docopy = FALSE; + } + } + } + HeapFree(GetProcessHeap(),0,VersionSource); + HeapFree(GetProcessHeap(),0,VersionTarget); + } + } + if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE)) + { + if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) + { + FIXME("Notify user target file exists\n"); + docopy = FALSE; + } + } + if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE | + SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP)) + { + ERR("Unsupported style(s) 0x%lx\n",style); + } + + if (docopy) + { + rc = CopyFileW(source,target,FALSE); + TRACE("Did copy... rc was %i\n",rc); + } + + /* after copy processing */ + if (style & SP_COPY_DELETESOURCE) + { + if (rc) + DeleteFileW(source); + } + + return rc; +} + +/*********************************************************************** + * SetupCommitFileQueueW (SETUPAPI.@) + */ +BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler, + PVOID context ) +{ + struct file_queue *queue = handle; + struct file_op *op; + BOOL result = FALSE; + FILEPATHS_W paths; + UINT op_result; + + paths.Source = paths.Target = NULL; + + if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count) + return TRUE; /* nothing to do */ + + if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT)owner, 0 )) return FALSE; + + /* perform deletes */ + + if (queue->delete_queue.count) + { + if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE, + queue->delete_queue.count ))) goto done; + for (op = queue->delete_queue.head; op; op = op->next) + { + build_filepathsW( op, &paths ); + op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE); + if (op_result == FILEOP_ABORT) goto done; + while (op_result == FILEOP_DOIT) + { + TRACE( "deleting file %s\n", debugstr_w(paths.Target) ); + if (DeleteFileW( paths.Target )) break; /* success */ + paths.Win32Error = GetLastError(); + op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 ); + if (op_result == FILEOP_ABORT) goto done; + } + handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 ); + } + handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 ); + } + + /* perform renames */ + + if (queue->rename_queue.count) + { + if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME, + queue->rename_queue.count ))) goto done; + for (op = queue->rename_queue.head; op; op = op->next) + { + build_filepathsW( op, &paths ); + op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME); + if (op_result == FILEOP_ABORT) goto done; + while (op_result == FILEOP_DOIT) + { + TRACE( "renaming file %s -> %s\n", + debugstr_w(paths.Source), debugstr_w(paths.Target) ); + if (MoveFileW( paths.Source, paths.Target )) break; /* success */ + paths.Win32Error = GetLastError(); + op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 ); + if (op_result == FILEOP_ABORT) goto done; + } + handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 ); + } + handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 ); + } + + /* perform copies */ + + if (queue->copy_queue.count) + { + if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY, + queue->copy_queue.count ))) goto done; + for (op = queue->copy_queue.head; op; op = op->next) + { + WCHAR newpath[MAX_PATH]; + + build_filepathsW( op, &paths ); + op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY ); + if (op_result == FILEOP_ABORT) goto done; + if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT; + while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH) + { + TRACE( "copying file %s -> %s\n", + debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ), + debugstr_w(paths.Target) ); + if (op->dst_path) + { + if (!create_full_pathW( op->dst_path )) + { + paths.Win32Error = GetLastError(); + op_result = handler( context, SPFILENOTIFY_COPYERROR, + (UINT_PTR)&paths, (UINT_PTR)newpath ); + if (op_result == FILEOP_ABORT) goto done; + } + } + if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source, + paths.Target, op->style )) break; /* success */ + /* try to extract it from the cabinet file */ + if (op->src_tag) + { + if (extract_cabinet_file( op->src_tag, op->src_root, + paths.Source, paths.Target )) break; + } + paths.Win32Error = GetLastError(); + op_result = handler( context, SPFILENOTIFY_COPYERROR, + (UINT_PTR)&paths, (UINT_PTR)newpath ); + if (op_result == FILEOP_ABORT) goto done; + } + handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 ); + } + handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 ); + } + + + result = TRUE; + + done: + handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 ); + HeapFree( GetProcessHeap(), 0, (void *)paths.Source ); + HeapFree( GetProcessHeap(), 0, (void *)paths.Target ); + return result; +} + + +/*********************************************************************** + * SetupScanFileQueueA (SETUPAPI.@) + */ +BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window, + PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result ) +{ + FIXME("stub\n"); + return FALSE; +} + + +/*********************************************************************** + * SetupScanFileQueueW (SETUPAPI.@) + */ +BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window, + PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result ) +{ + FIXME("stub\n"); + return FALSE; +} + + +/*********************************************************************** + * SetupGetFileQueueCount (SETUPAPI.@) + */ +BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result ) +{ + struct file_queue *queue = handle; + + switch(op) + { + case FILEOP_COPY: + *result = queue->copy_queue.count; + return TRUE; + case FILEOP_RENAME: + *result = queue->rename_queue.count; + return TRUE; + case FILEOP_DELETE: + *result = queue->delete_queue.count; + return TRUE; + } + return FALSE; +} + + +/*********************************************************************** + * SetupGetFileQueueFlags (SETUPAPI.@) + */ +BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags ) +{ + struct file_queue *queue = handle; + *flags = queue->flags; + return TRUE; +} + + +/*********************************************************************** + * SetupSetFileQueueFlags (SETUPAPI.@) + */ +BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags ) +{ + struct file_queue *queue = handle; + queue->flags = (queue->flags & ~mask) | flags; + return TRUE; +} + + +/*********************************************************************** + * SetupInitDefaultQueueCallback (SETUPAPI.@) + */ +PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner ) +{ + return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL ); +} + + +/*********************************************************************** + * SetupInitDefaultQueueCallbackEx (SETUPAPI.@) + */ +PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg, + DWORD reserved1, PVOID reserved2 ) +{ + struct default_callback_context *context; + + if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) ))) + { + context->owner = owner; + context->progress = progress; + context->message = msg; + } + return context; +} + + +/*********************************************************************** + * SetupTermDefaultQueueCallback (SETUPAPI.@) + */ +void WINAPI SetupTermDefaultQueueCallback( PVOID context ) +{ + HeapFree( GetProcessHeap(), 0, context ); +} + + +/*********************************************************************** + * SetupDefaultQueueCallbackA (SETUPAPI.@) + */ +UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification, + UINT_PTR param1, UINT_PTR param2 ) +{ + FILEPATHS_A *paths = (FILEPATHS_A *)param1; + + switch(notification) + { + case SPFILENOTIFY_STARTQUEUE: + TRACE( "start queue\n" ); + return TRUE; + case SPFILENOTIFY_ENDQUEUE: + TRACE( "end queue\n" ); + return 0; + case SPFILENOTIFY_STARTSUBQUEUE: + TRACE( "start subqueue %d count %d\n", param1, param2 ); + return TRUE; + case SPFILENOTIFY_ENDSUBQUEUE: + TRACE( "end subqueue %d\n", param1 ); + return 0; + case SPFILENOTIFY_STARTDELETE: + TRACE( "start delete %s\n", debugstr_a(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDDELETE: + TRACE( "end delete %s\n", debugstr_a(paths->Target) ); + return 0; + case SPFILENOTIFY_DELETEERROR: + ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_STARTRENAME: + TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDRENAME: + TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return 0; + case SPFILENOTIFY_RENAMEERROR: + ERR( "rename error %d %s -> %s\n", paths->Win32Error, + debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_STARTCOPY: + TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDCOPY: + TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return 0; + case SPFILENOTIFY_COPYERROR: + ERR( "copy error %d %s -> %s\n", paths->Win32Error, + debugstr_a(paths->Source), debugstr_a(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_NEEDMEDIA: + TRACE( "need media\n" ); + return FILEOP_SKIP; + default: + FIXME( "notification %d params %x,%x\n", notification, param1, param2 ); + break; + } + return 0; +} + + +/*********************************************************************** + * SetupDefaultQueueCallbackW (SETUPAPI.@) + */ +UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification, + UINT_PTR param1, UINT_PTR param2 ) +{ + FILEPATHS_W *paths = (FILEPATHS_W *)param1; + + switch(notification) + { + case SPFILENOTIFY_STARTQUEUE: + TRACE( "start queue\n" ); + return TRUE; + case SPFILENOTIFY_ENDQUEUE: + TRACE( "end queue\n" ); + return 0; + case SPFILENOTIFY_STARTSUBQUEUE: + TRACE( "start subqueue %d count %d\n", param1, param2 ); + return TRUE; + case SPFILENOTIFY_ENDSUBQUEUE: + TRACE( "end subqueue %d\n", param1 ); + return 0; + case SPFILENOTIFY_STARTDELETE: + TRACE( "start delete %s\n", debugstr_w(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDDELETE: + TRACE( "end delete %s\n", debugstr_w(paths->Target) ); + return 0; + case SPFILENOTIFY_DELETEERROR: + ERR( "delete error %d %s\n", paths->Win32Error, debugstr_w(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_STARTRENAME: + TRACE( "start rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDRENAME: + TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return 0; + case SPFILENOTIFY_RENAMEERROR: + ERR( "rename error %d %s -> %s\n", paths->Win32Error, + debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_STARTCOPY: + TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return FILEOP_DOIT; + case SPFILENOTIFY_ENDCOPY: + TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return 0; + case SPFILENOTIFY_COPYERROR: + ERR( "copy error %d %s -> %s\n", paths->Win32Error, + debugstr_w(paths->Source), debugstr_w(paths->Target) ); + return FILEOP_SKIP; + case SPFILENOTIFY_NEEDMEDIA: + TRACE( "need media\n" ); + return FILEOP_SKIP; + default: + FIXME( "notification %d params %x,%x\n", notification, param1, param2 ); + break; + } + return 0; +} diff --git a/reactos/lib/setupapi/setupapi.rc b/reactos/lib/setupapi/setupapi.rc new file mode 100644 index 00000000000..ed5d6428e26 --- /dev/null +++ b/reactos/lib/setupapi/setupapi.rc @@ -0,0 +1,36 @@ +/* + * Top level resource file for SETUPX + * + * Copyright 2001 Andreas Mohr + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi_private.h" + +#include "Cs.rc" +#include "De.rc" +#include "En.rc" +#include "Es.rc" +#include "Fr.rc" +#include "It.rc" +#include "Ja.rc" +#include "Nl.rc" +#include "Pt.rc" +#include "Ru.rc" diff --git a/reactos/lib/setupapi/setupapi.spec b/reactos/lib/setupapi/setupapi.spec new file mode 100644 index 00000000000..22a164c6716 --- /dev/null +++ b/reactos/lib/setupapi/setupapi.spec @@ -0,0 +1,552 @@ +@ stub AcquireSCMLock +@ stub AddMiniIconToList +@ stub AddTagToGroupOrderListEntry +@ stub AppendStringToMultiSz +@ stub AssertFail +@ stub CMP_Init_Detection +@ stub CMP_RegisterNotification +@ stub CMP_Report_LogOn +@ stub CMP_UnregisterNotification +@ stub CMP_WaitNoPendingInstallEvents +@ stub CMP_WaitServices +@ stub CM_Add_Empty_Log_Conf +@ stub CM_Add_Empty_Log_Conf_Ex +@ stub CM_Add_IDA +@ stub CM_Add_IDW +@ stub CM_Add_ID_ExA +@ stub CM_Add_ID_ExW +@ stub CM_Add_Range +@ stub CM_Add_Res_Des +@ stub CM_Add_Res_Des_Ex +@ stub CM_Connect_MachineA +@ stdcall CM_Connect_MachineW(wstr ptr) +@ stub CM_Create_DevNodeA +@ stub CM_Create_DevNodeW +@ stub CM_Create_DevNode_ExA +@ stub CM_Create_DevNode_ExW +@ stub CM_Create_Range_List +@ stub CM_Delete_Class_Key +@ stub CM_Delete_Class_Key_Ex +@ stub CM_Delete_DevNode_Key +@ stub CM_Delete_DevNode_Key_Ex +@ stub CM_Delete_Range +@ stub CM_Detect_Resource_Conflict +@ stub CM_Detect_Resource_Conflict_Ex +@ stub CM_Disable_DevNode +@ stub CM_Disable_DevNode_Ex +@ stdcall CM_Disconnect_Machine(long) +@ stub CM_Dup_Range_List +@ stub CM_Enable_DevNode +@ stub CM_Enable_DevNode_Ex +@ stub CM_Enumerate_Classes +@ stub CM_Enumerate_Classes_Ex +@ stub CM_Enumerate_EnumeratorsA +@ stub CM_Enumerate_EnumeratorsW +@ stub CM_Enumerate_Enumerators_ExA +@ stub CM_Enumerate_Enumerators_ExW +@ stub CM_Find_Range +@ stub CM_First_Range +@ stub CM_Free_Log_Conf +@ stub CM_Free_Log_Conf_Ex +@ stub CM_Free_Log_Conf_Handle +@ stub CM_Free_Range_List +@ stub CM_Free_Res_Des +@ stub CM_Free_Res_Des_Ex +@ stub CM_Free_Res_Des_Handle +@ stub CM_Get_Child +@ stub CM_Get_Child_Ex +@ stub CM_Get_Class_Key_NameA +@ stub CM_Get_Class_Key_NameW +@ stub CM_Get_Class_Key_Name_ExA +@ stub CM_Get_Class_Key_Name_ExW +@ stub CM_Get_Class_NameA +@ stub CM_Get_Class_NameW +@ stub CM_Get_Class_Name_ExA +@ stub CM_Get_Class_Name_ExW +@ stub CM_Get_Depth +@ stub CM_Get_Depth_Ex +@ stub CM_Get_DevNode_Registry_PropertyA +@ stub CM_Get_DevNode_Registry_PropertyW +@ stub CM_Get_DevNode_Registry_Property_ExA +@ stub CM_Get_DevNode_Registry_Property_ExW +@ stub CM_Get_DevNode_Status +@ stub CM_Get_DevNode_Status_Ex +@ stub CM_Get_Device_IDA +@ stub CM_Get_Device_IDW +@ stub CM_Get_Device_ID_ExA +@ stub CM_Get_Device_ID_ExW +@ stdcall CM_Get_Device_ID_ListA(ptr ptr long long) +@ stub CM_Get_Device_ID_ListW +@ stub CM_Get_Device_ID_List_ExA +@ stub CM_Get_Device_ID_List_ExW +@ stub CM_Get_Device_ID_List_SizeA +@ stub CM_Get_Device_ID_List_SizeW +@ stub CM_Get_Device_ID_List_Size_ExA +@ stub CM_Get_Device_ID_List_Size_ExW +@ stub CM_Get_Device_ID_Size +@ stub CM_Get_Device_ID_Size_Ex +@ stub CM_Get_Device_Interface_AliasA +@ stub CM_Get_Device_Interface_AliasW +@ stub CM_Get_Device_Interface_Alias_ExA +@ stub CM_Get_Device_Interface_Alias_ExW +@ stub CM_Get_Device_Interface_ListA +@ stub CM_Get_Device_Interface_ListW +@ stub CM_Get_Device_Interface_List_ExA +@ stub CM_Get_Device_Interface_List_ExW +@ stub CM_Get_Device_Interface_List_SizeA +@ stub CM_Get_Device_Interface_List_SizeW +@ stub CM_Get_Device_Interface_List_Size_ExA +@ stub CM_Get_Device_Interface_List_Size_ExW +@ stub CM_Request_Device_EjectA +@ stub CM_Request_Device_EjectW +@ stub CM_Get_First_Log_Conf +@ stub CM_Get_First_Log_Conf_Ex +@ stub CM_Get_Global_State +@ stub CM_Get_Global_State_Ex +@ stub CM_Get_HW_Prof_FlagsA +@ stub CM_Get_HW_Prof_FlagsW +@ stub CM_Get_HW_Prof_Flags_ExA +@ stub CM_Get_HW_Prof_Flags_ExW +@ stub CM_Get_Hardware_Profile_InfoA +@ stub CM_Get_Hardware_Profile_InfoW +@ stub CM_Get_Hardware_Profile_Info_ExA +@ stub CM_Get_Hardware_Profile_Info_ExW +@ stub CM_Get_Log_Conf_Priority +@ stub CM_Get_Log_Conf_Priority_Ex +@ stub CM_Get_Next_Log_Conf +@ stub CM_Get_Next_Log_Conf_Ex +@ stub CM_Get_Next_Res_Des +@ stub CM_Get_Next_Res_Des_Ex +@ stub CM_Get_Parent +@ stub CM_Get_Parent_Ex +@ stub CM_Get_Res_Des_Data +@ stub CM_Get_Res_Des_Data_Ex +@ stub CM_Get_Res_Des_Data_Size +@ stub CM_Get_Res_Des_Data_Size_Ex +@ stub CM_Get_Sibling +@ stub CM_Get_Sibling_Ex +@ stub CM_Get_Version +@ stub CM_Get_Version_Ex +@ stub CM_Intersect_Range_List +@ stub CM_Invert_Range_List +@ stub CM_Is_Dock_Station_Present +@ stub CM_Locate_DevNodeA +@ stub CM_Locate_DevNodeW +@ stub CM_Locate_DevNode_ExA +@ stub CM_Locate_DevNode_ExW +@ stub CM_Merge_Range_List +@ stub CM_Modify_Res_Des +@ stub CM_Modify_Res_Des_Ex +@ stub CM_Move_DevNode +@ stub CM_Move_DevNode_Ex +@ stub CM_Next_Range +@ stub CM_Open_Class_KeyA +@ stub CM_Open_Class_KeyW +@ stub CM_Open_Class_Key_ExA +@ stub CM_Open_Class_Key_ExW +@ stub CM_Open_DevNode_Key +@ stub CM_Open_DevNode_Key_Ex +@ stub CM_Query_Arbitrator_Free_Data +@ stub CM_Query_Arbitrator_Free_Data_Ex +@ stub CM_Query_Arbitrator_Free_Size +@ stub CM_Query_Arbitrator_Free_Size_Ex +@ stub CM_Query_Remove_SubTree +@ stub CM_Query_Remove_SubTree_Ex +@ stub CM_Reenumerate_DevNode +@ stub CM_Reenumerate_DevNode_Ex +@ stub CM_Register_Device_Driver +@ stub CM_Register_Device_Driver_Ex +@ stub CM_Register_Device_InterfaceA +@ stub CM_Register_Device_InterfaceW +@ stub CM_Register_Device_Interface_ExA +@ stub CM_Register_Device_Interface_ExW +@ stub CM_Remove_SubTree +@ stub CM_Remove_SubTree_Ex +@ stub CM_Remove_Unmarked_Children +@ stub CM_Remove_Unmarked_Children_Ex +@ stub CM_Request_Eject_PC +@ stub CM_Reset_Children_Marks +@ stub CM_Reset_Children_Marks_Ex +@ stub CM_Run_Detection +@ stub CM_Run_Detection_Ex +@ stub CM_Set_DevNode_Problem +@ stub CM_Set_DevNode_Problem_Ex +@ stub CM_Set_DevNode_Registry_PropertyA +@ stub CM_Set_DevNode_Registry_PropertyW +@ stub CM_Set_DevNode_Registry_Property_ExA +@ stub CM_Set_DevNode_Registry_Property_ExW +@ stub CM_Set_HW_Prof +@ stub CM_Set_HW_Prof_Ex +@ stub CM_Set_HW_Prof_FlagsA +@ stub CM_Set_HW_Prof_FlagsW +@ stub CM_Set_HW_Prof_Flags_ExA +@ stub CM_Set_HW_Prof_Flags_ExW +@ stub CM_Setup_DevNode +@ stub CM_Setup_DevNode_Ex +@ stub CM_Test_Range_Available +@ stub CM_Uninstall_DevNode +@ stub CM_Uninstall_DevNode_Ex +@ stub CM_Unregister_Device_InterfaceA +@ stub CM_Unregister_Device_InterfaceW +@ stub CM_Unregister_Device_Interface_ExA +@ stub CM_Unregister_Device_Interface_ExW +@ stub CaptureAndConvertAnsiArg +@ stub CaptureStringArg +@ stub CenterWindowRelativeToParent +@ stub ConcatenatePaths +@ stub DelayedMove +@ stub DelimStringToMultiSz +@ stub DestroyTextFileReadBuffer +@ stub DoesUserHavePrivilege +@ stdcall DuplicateString(wstr) +@ stub EnablePrivilege +@ stub ExtensionPropSheetPageProc +@ stub FileExists +@ stub FreeStringArray +@ stub GetCurrentDriverSigningPolicy +@ stub GetNewInfName +@ stub GetSetFileTimestamp +@ stub GetVersionInfoFromImage +@ stub InfIsFromOemLocation +@ stub InstallCatalog +@ stdcall InstallHinfSection(long long str long) InstallHinfSectionA +@ stdcall InstallHinfSectionA(long long str long) +@ stdcall InstallHinfSectionW(long long wstr long) +@ stub InstallStop +@ stub InstallStopEx +@ stub IsUserAdmin +@ stub LookUpStringInTable +@ stub MemoryInitialize +@ stub MultiByteToUnicode +@ stub MultiSzFromSearchControl +@ stdcall MyFree(ptr) +@ stub MyGetFileTitle +@ stdcall MyMalloc(long) +@ stdcall MyRealloc(ptr long) +@ stub OpenAndMapFileForRead +@ stub OutOfMemory +@ stub QueryMultiSzValueToArray +@ stdcall QueryRegistryValue(long wstr ptr ptr ptr) +@ stub ReadAsciiOrUnicodeTextFile +@ stub RegistryDelnode +@ stub RetreiveFileSecurity +@ stub RetrieveServiceConfig +@ stub SearchForInfFile +@ stub SetArrayToMultiSzValue +@ stdcall SetupAddInstallSectionToDiskSpaceListA(long long long str ptr long) +@ stub SetupAddInstallSectionToDiskSpaceListW +@ stub SetupAddSectionToDiskSpaceListA +@ stub SetupAddSectionToDiskSpaceListW +@ stub SetupAddToDiskSpaceListA +@ stub SetupAddToDiskSpaceListW +@ stub SetupAddToSourceListA +@ stub SetupAddToSourceListW +@ stub SetupAdjustDiskSpaceListA +@ stub SetupAdjustDiskSpaceListW +@ stub SetupCancelTemporarySourceList +@ stdcall SetupCloseFileQueue(ptr) +@ stdcall SetupCloseInfFile(long) +@ stub SetupCloseLog +@ stdcall SetupCommitFileQueue(long long ptr ptr) SetupCommitFileQueueW +@ stdcall SetupCommitFileQueueA(long long ptr ptr) +@ stdcall SetupCommitFileQueueW(long long ptr ptr) +@ stub SetupCopyErrorA +@ stub SetupCopyErrorW +@ stdcall SetupCopyOEMInfA(str str long long ptr long ptr ptr) +@ stub SetupCopyOEMInfW +@ stdcall SetupCreateDiskSpaceListA(ptr long long) +@ stdcall SetupCreateDiskSpaceListW(ptr long long) +@ stub SetupDecompressOrCopyFileA +@ stub SetupDecompressOrCopyFileW +@ stub SetupDefaultQueueCallback +@ stdcall SetupDefaultQueueCallbackA(ptr long long long) +@ stdcall SetupDefaultQueueCallbackW(ptr long long long) +@ stub SetupDeleteErrorA +@ stub SetupDeleteErrorW +@ stdcall SetupDestroyDiskSpaceList(long) +@ stub SetupDiAskForOEMDisk +@ stdcall SetupDiBuildClassInfoList(long ptr long ptr) +@ stdcall SetupDiBuildClassInfoListExA(long ptr long ptr str ptr) +@ stdcall SetupDiBuildClassInfoListExW(long ptr long ptr wstr ptr) +@ stub SetupDiBuildDriverInfoList +@ stdcall SetupDiCallClassInstaller(long ptr ptr) +@ stub SetupDiCancelDriverInfoSearch +@ stub SetupDiChangeState +@ stdcall SetupDiClassGuidsFromNameA(str ptr long ptr) +@ stdcall SetupDiClassGuidsFromNameExA(str ptr long ptr str ptr) +@ stdcall SetupDiClassGuidsFromNameExW(wstr ptr long ptr wstr ptr) +@ stdcall SetupDiClassGuidsFromNameW(wstr ptr long ptr) +@ stdcall SetupDiClassNameFromGuidA(ptr str long ptr) +@ stdcall SetupDiClassNameFromGuidExA(ptr str long ptr wstr ptr) +@ stdcall SetupDiClassNameFromGuidExW(ptr wstr long ptr wstr ptr) +@ stdcall SetupDiClassNameFromGuidW(ptr wstr long ptr) +@ stub SetupDiCreateDevRegKeyA +@ stub SetupDiCreateDevRegKeyW +@ stub SetupDiCreateDeviceInfoA +@ stdcall SetupDiCreateDeviceInfoList(ptr ptr) +@ stdcall SetupDiCreateDeviceInfoListExA(ptr long str ptr) +@ stdcall SetupDiCreateDeviceInfoListExW(ptr long str ptr) +@ stub SetupDiCreateDeviceInfoW +@ stub SetupDiDeleteDevRegKey +@ stub SetupDiDeleteDeviceInfo +@ stub SetupDiDeleteDeviceInterfaceData +@ stub SetupDiDeleteDeviceRegKey +@ stub SetupDiDestroyClassImageList +@ stdcall SetupDiDestroyDeviceInfoList(long) +@ stub SetupDiDestroyDriverInfoList +@ stub SetupDiDrawMiniIcon +@ stdcall SetupDiEnumDeviceInfo(long long ptr) +@ stdcall SetupDiEnumDeviceInterfaces(long ptr ptr long ptr) +@ stub SetupDiEnumDriverInfoA +@ stub SetupDiEnumDriverInfoW +@ stdcall SetupDiGetActualSectionToInstallA(long str str long ptr ptr) +@ stdcall SetupDiGetActualSectionToInstallW(long wstr wstr long ptr ptr) +@ stub SetupDiGetClassBitmapIndex +@ stdcall SetupDiGetClassDescriptionA(ptr str long ptr) +@ stdcall SetupDiGetClassDescriptionExA(ptr str long ptr str ptr) +@ stdcall SetupDiGetClassDescriptionExW(ptr wstr long ptr wstr ptr) +@ stdcall SetupDiGetClassDescriptionW(ptr wstr long ptr) +@ stub SetupDiGetClassDevPropertySheetsA +@ stub SetupDiGetClassDevPropertySheetsW +@ stdcall SetupDiGetClassDevsA(ptr ptr long long) +@ stdcall SetupDiGetClassDevsExA(ptr str ptr long ptr str ptr) +@ stdcall SetupDiGetClassDevsExW(ptr wstr ptr long ptr wstr ptr) +@ stdcall SetupDiGetClassDevsW(ptr ptr long long) +@ stub SetupDiGetClassImageIndex +@ stub SetupDiGetClassImageList +@ stub SetupDiGetClassImageListExA +@ stub SetupDiGetClassImageListExW +@ stub SetupDiGetClassInstallParamsA +@ stub SetupDiGetClassInstallParamsW +@ stub SetupDiGetDeviceInfoListClass +@ stdcall SetupDiGetDeviceInfoListDetailA(ptr ptr) +@ stdcall SetupDiGetDeviceInfoListDetailW(ptr ptr) +@ stdcall SetupDiGetDeviceInstallParamsA(ptr ptr ptr) +@ stub SetupDiGetDeviceInstallParamsW +@ stub SetupDiGetDeviceInstanceIdA +@ stub SetupDiGetDeviceInstanceIdW +@ stdcall SetupDiGetDeviceRegistryPropertyA(long ptr long ptr ptr long ptr) +@ stub SetupDiGetDeviceRegistryPropertyW +@ stub SetupDiGetDriverInfoDetailA +@ stub SetupDiGetDriverInfoDetailW +@ stub SetupDiGetDriverInstallParamsA +@ stub SetupDiGetDriverInstallParamsW +@ stub SetupDiGetDeviceInterfaceAlias +@ stdcall SetupDiGetDeviceInterfaceDetailA(long ptr ptr long ptr ptr) +@ stdcall SetupDiGetDeviceInterfaceDetailW(long ptr ptr long ptr ptr) +@ stub SetupDiGetHwProfileFriendlyNameA +@ stub SetupDiGetHwProfileFriendlyNameExA +@ stub SetupDiGetHwProfileFriendlyNameExW +@ stub SetupDiGetHwProfileFriendlyNameW +@ stub SetupDiGetHwProfileList +@ stub SetupDiGetHwProfileListExA +@ stub SetupDiGetHwProfileListExW +@ stub SetupDiGetINFClassA +@ stub SetupDiGetINFClassW +@ stub SetupDiGetSelectedDevice +@ stub SetupDiGetSelectedDriverA +@ stub SetupDiGetSelectedDriverW +@ stub SetupDiGetWizardPage +@ stdcall SetupDiInstallClassA(long str long ptr) +@ stub SetupDiInstallClassExA +@ stub SetupDiInstallClassExW +@ stdcall SetupDiInstallClassW(long wstr long ptr) +@ stub SetupDiInstallDevice +@ stub SetupDiInstallDriverFiles +@ stub SetupDiLoadClassIcon +@ stub SetupDiMoveDuplicateDevice +@ stdcall SetupDiOpenClassRegKey(ptr long) +@ stdcall SetupDiOpenClassRegKeyExA(ptr long long str ptr) +@ stdcall SetupDiOpenClassRegKeyExW(ptr long long wstr ptr) +@ stdcall SetupDiOpenDevRegKey(ptr ptr long long long long) +@ stub SetupDiOpenDeviceInfoA +@ stub SetupDiOpenDeviceInfoW +@ stdcall SetupDiOpenDeviceInterfaceA(ptr str long ptr) +@ stub SetupDiOpenDeviceInterfaceRegKey +@ stdcall SetupDiOpenDeviceInterfaceW(ptr wstr long ptr) +@ stub SetupDiRegisterDeviceInfo +@ stub SetupDiRemoveDevice +@ stub SetupDiRemoveDeviceInterface +@ stub SetupDiSelectDevice +@ stub SetupDiSelectOEMDrv +@ stdcall SetupDiSetClassInstallParamsA(ptr ptr ptr long) +@ stub SetupDiSetClassInstallParamsW +@ stub SetupDiSetDeviceInstallParamsA +@ stub SetupDiSetDeviceInstallParamsW +@ stub SetupDiSetDeviceRegistryPropertyA +@ stub SetupDiSetDeviceRegistryPropertyW +@ stub SetupDiSetDriverInstallParamsA +@ stub SetupDiSetDriverInstallParamsW +@ stub SetupDiSetSelectedDevice +@ stub SetupDiSetSelectedDriverA +@ stub SetupDiSetSelectedDriverW +@ stub SetupDiUnremoveDevice +@ stub SetupDuplicateDiskSpaceListA +@ stub SetupDuplicateDiskSpaceListW +@ stdcall SetupFindFirstLineA(long str str ptr) +@ stdcall SetupFindFirstLineW(long wstr wstr ptr) +@ stdcall SetupFindNextLine(ptr ptr) +@ stdcall SetupFindNextMatchLineA(ptr str ptr) +@ stdcall SetupFindNextMatchLineW(ptr wstr ptr) +@ stub SetupFreeSourceListA +@ stub SetupFreeSourceListW +@ stub SetupGetBackupInformationA +@ stub SetupGetBackupInformationW +@ stdcall SetupGetBinaryField(ptr long ptr long ptr) +@ stdcall SetupGetFieldCount(ptr) +@ stub SetupGetFileCompressionInfoA +@ stub SetupGetFileCompressionInfoW +@ stdcall SetupGetFileQueueCount(long long ptr) +@ stdcall SetupGetFileQueueFlags(long ptr) +@ stub SetupGetInfFileListA +@ stub SetupGetInfFileListW +@ stdcall SetupGetInfInformationA(ptr long ptr long ptr) +@ stub SetupGetInfInformationW +@ stub SetupGetInfSections +@ stdcall SetupGetIntField(ptr long ptr) +@ stdcall SetupGetLineByIndexA(long str long ptr) +@ stdcall SetupGetLineByIndexW(long wstr long ptr) +@ stdcall SetupGetLineCountA(long str) +@ stdcall SetupGetLineCountW(long wstr) +@ stdcall SetupGetLineTextA(ptr long str str ptr long ptr) +@ stdcall SetupGetLineTextW(ptr long wstr wstr ptr long ptr) +@ stdcall SetupGetMultiSzFieldA(ptr long ptr long ptr) +@ stdcall SetupGetMultiSzFieldW(ptr long ptr long ptr) +@ stub SetupGetSourceFileLocationA +@ stub SetupGetSourceFileLocationW +@ stub SetupGetSourceFileSizeA +@ stub SetupGetSourceFileSizeW +@ stub SetupGetSourceInfoA +@ stub SetupGetSourceInfoW +@ stdcall SetupGetStringFieldA(ptr long ptr long ptr) +@ stdcall SetupGetStringFieldW(ptr long ptr long ptr) +@ stub SetupGetTargetPathA +@ stub SetupGetTargetPathW +@ stdcall SetupInitDefaultQueueCallback(long) +@ stdcall SetupInitDefaultQueueCallbackEx(long long long long ptr) +@ stdcall SetupInitializeFileLogA (str long) +@ stdcall SetupInitializeFileLogW (wstr long) +@ stub SetupInstallFileA +@ stub SetupInstallFileExA +@ stub SetupInstallFileExW +@ stub SetupInstallFileW +@ stdcall SetupInstallFilesFromInfSectionA(long long long str str long) +@ stdcall SetupInstallFilesFromInfSectionW(long long long wstr wstr long) +@ stdcall SetupInstallFromInfSectionA(long long str long long str long ptr ptr long ptr) +@ stdcall SetupInstallFromInfSectionW(long long wstr long long wstr long ptr ptr long ptr) +@ stub SetupInstallServicesFromInfSectionA +@ stub SetupInstallServicesFromInfSectionExA +@ stub SetupInstallServicesFromInfSectionExW +@ stub SetupInstallServicesFromInfSectionW +@ stdcall SetupIterateCabinetA(str long ptr ptr) +@ stdcall SetupIterateCabinetW(wstr long ptr ptr) +@ stub SetupLogErrorA +@ stub SetupLogErrorW +@ stub SetupLogFileA +@ stub SetupLogFileW +@ stdcall SetupOpenAppendInfFileA(str long ptr) +@ stdcall SetupOpenAppendInfFileW(wstr long ptr) +@ stdcall SetupOpenFileQueue() +@ stdcall SetupOpenInfFileA(str str long ptr) +@ stdcall SetupOpenInfFileW(wstr wstr long ptr) +@ stdcall SetupOpenMasterInf() +@ stub SetupPromptForDiskA +@ stub SetupPromptForDiskW +@ stub SetupPromptReboot +@ stub SetupQueryDrivesInDiskSpaceListA +@ stub SetupQueryDrivesInDiskSpaceListW +@ stub SetupQueryFileLogA +@ stub SetupQueryFileLogW +@ stub SetupQueryInfFileInformationA +@ stub SetupQueryInfFileInformationW +@ stub SetupQueryInfOriginalFileInformationA +@ stub SetupQueryInfOriginalFileInformationW +@ stub SetupQueryInfVersionInformationA +@ stub SetupQueryInfVersionInformationW +@ stub SetupQuerySourceListA +@ stub SetupQuerySourceListW +@ stdcall SetupQuerySpaceRequiredOnDriveA(long str ptr ptr long) +@ stub SetupQuerySpaceRequiredOnDriveW +@ stdcall SetupQueueCopyA(long str str str str str str str long) +@ stdcall SetupQueueCopyIndirectA(ptr) +@ stdcall SetupQueueCopyIndirectW(ptr) +@ stdcall SetupQueueCopySectionA(long str long long str long) +@ stdcall SetupQueueCopySectionW(long wstr long long wstr long) +@ stdcall SetupQueueCopyW(long wstr wstr wstr wstr wstr wstr wstr long) +@ stdcall SetupQueueDefaultCopyA(long long str str str long) +@ stdcall SetupQueueDefaultCopyW(long long wstr wstr wstr long) +@ stdcall SetupQueueDeleteA(long str str) +@ stdcall SetupQueueDeleteSectionA(long long long str) +@ stdcall SetupQueueDeleteSectionW(long long long wstr) +@ stdcall SetupQueueDeleteW(long wstr wstr) +@ stdcall SetupQueueRenameA(long str str str str) +@ stdcall SetupQueueRenameSectionA(long long long str) +@ stdcall SetupQueueRenameSectionW(long long long wstr) +@ stdcall SetupQueueRenameW(long wstr wstr wstr wstr) +@ stub SetupRemoveFileLogEntryA +@ stub SetupRemoveFileLogEntryW +@ stub SetupRemoveFromDiskSpaceListA +@ stub SetupRemoveFromDiskSpaceListW +@ stub SetupRemoveFromSourceListA +@ stub SetupRemoveFromSourceListW +@ stub SetupRemoveInstallSectionFromDiskSpaceListA +@ stub SetupRemoveInstallSectionFromDiskSpaceListW +@ stub SetupRemoveSectionFromDiskSpaceListA +@ stub SetupRemoveSectionFromDiskSpaceListW +@ stub SetupRenameErrorA +@ stub SetupRenameErrorW +@ stub SetupScanFileQueue +@ stdcall SetupScanFileQueueA(long long long ptr ptr ptr) +@ stdcall SetupScanFileQueueW(long long long ptr ptr ptr) +@ stdcall SetupSetDirectoryIdA(long long str) +@ stub SetupSetDirectoryIdExA +@ stub SetupSetDirectoryIdExW +@ stdcall SetupSetDirectoryIdW(long long wstr) +@ stub SetupFileQueueAlternatePlatformA +@ stub SetupFileQueueAlternatePlatformW +@ stdcall SetupSetFileQueueFlags(long long long) +@ stub SetupSetPlatformPathOverrideA +@ stub SetupSetPlatformPathOverrideW +@ stub SetupSetSourceListA +@ stub SetupSetSourceListW +@ stdcall SetupTermDefaultQueueCallback(ptr) +@ stdcall SetupTerminateFileLog(long) +@ stub ShouldDeviceBeExcluded +@ stub StampFileSecurity +@ stub StringTableAddString +@ stub StringTableAddStringEx +@ stub StringTableDestroy +@ stub StringTableDuplicate +@ stub StringTableEnum +@ stub StringTableGetExtraData +@ stub StringTableInitialize +@ stub StringTableInitializeEx +@ stub StringTableLookUpString +@ stub StringTableLookUpStringEx +@ stub StringTableSetExtraData +@ stub StringTableStringFromId +@ stub StringTableTrim +@ stub TakeOwnershipOfFile +@ stub UnicodeToMultiByte +@ stub UnmapAndCloseFile +@ stub VerifyCatalogFile +@ stub VerifyFile +@ stub pSetupAccessRunOnceNodeList +@ stub pSetupAddMiniIconToList +@ stub pSetupAddTagToGroupOrderListEntry +@ stub pSetupAppendStringToMultiSz +@ stub pSetupDestroyRunOnceNodeList +@ stub pSetupDirectoryIdToPath +@ stub pSetupGetField +@ stub pSetupGetGlobalFlags +@ stub pSetupGetOsLoaderDriveAndPath +@ stub pSetupGetQueueFlags +@ stub pSetupGetVersionDatum +@ stub pSetupGuidFromString +@ stub pSetupIsGuidNull +@ stub pSetupMakeSurePathExists +@ stub pSetupSetGlobalFlags +@ stub pSetupSetQueueFlags +@ stub pSetupSetSystemSourceFlags +@ stub pSetupStringFromGuid +@ stub pSetupVerifyQueuedCatalogs diff --git a/reactos/lib/setupapi/setupapi_private.h b/reactos/lib/setupapi/setupapi_private.h new file mode 100644 index 00000000000..7cd40e4f146 --- /dev/null +++ b/reactos/lib/setupapi/setupapi_private.h @@ -0,0 +1,57 @@ +/* + * Copyright 2001 Andreas Mohr + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SETUPAPI_PRIVATE_H +#define __SETUPAPI_PRIVATE_H + +#define COPYFILEDLGORD 1000 +#define SOURCESTRORD 500 +#define DESTSTRORD 501 +#define PROGRESSORD 502 + + +#define REG_INSTALLEDFILES "System\\CurrentControlSet\\Control\\InstalledFiles" +#define REGPART_RENAME "\\Rename" +#define REG_VERSIONCONFLICT "Software\\Microsoft\\VersionConflictManager" + +/* string substitutions */ + +struct inf_file; +extern const WCHAR *DIRID_get_string( HINF hinf, int dirid ); +extern unsigned int PARSER_string_substA( struct inf_file *file, const WCHAR *text, + char *buffer, unsigned int size ); +extern unsigned int PARSER_string_substW( struct inf_file *file, const WCHAR *text, + WCHAR *buffer, unsigned int size ); +extern const WCHAR *PARSER_get_src_root( HINF hinf ); +extern WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ); + +/* support for Ascii queue callback functions */ + +struct callback_WtoA_context +{ + void *orig_context; + PSP_FILE_CALLBACK_A orig_handler; +}; + +UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, UINT_PTR, UINT_PTR ); + +/* from msvcrt/sys/stat.h */ +#define _S_IWRITE 0x0080 +#define _S_IREAD 0x0100 + +#endif /* __SETUPAPI_PRIVATE_H */ diff --git a/reactos/lib/setupapi/setupcab.c b/reactos/lib/setupapi/setupcab.c new file mode 100644 index 00000000000..6fc3001ca49 --- /dev/null +++ b/reactos/lib/setupapi/setupcab.c @@ -0,0 +1,684 @@ +/* + * Setupapi cabinet routines + * + * Copyright 2003 Gregory M. Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Many useful traces are commented in code, uncomment them if you have + * trouble and run with WINEDEBUG=+setupapi + * + */ + +#include +#include +#include + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "setupapi.h" +#include "setupapi_private.h" +#include "fdi.h" +#include "wine/unicode.h" + +#include "msvcrt/fcntl.h" +#include "msvcrt/share.h" + +#include "wine/debug.h" + +static HINSTANCE CABINET_hInstance = 0; + +static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN, + PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF); + +static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int, + PFNFDINOTIFY, PFNFDIDECRYPT, void *); + +static BOOL (__cdecl *sc_FDIDestroy)(HFDI); + +#define SC_HSC_A_MAGIC 0xACABFEED +typedef struct { + UINT magic; + HFDI hfdi; + PSP_FILE_CALLBACK_A msghandler; + PVOID context; + CHAR most_recent_cabinet_name[MAX_PATH]; +} SC_HSC_A, *PSC_HSC_A; + +#define SC_HSC_W_MAGIC 0x0CABFEED +typedef struct { + UINT magic; + HFDI hfdi; + PSP_FILE_CALLBACK_W msghandler; + PVOID context; + WCHAR most_recent_cabinet_name[MAX_PATH]; +} SC_HSC_W, *PSC_HSC_W; + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +static BOOL LoadCABINETDll(void) +{ + if (!CABINET_hInstance) { + CABINET_hInstance = LoadLibraryA("cabinet.dll"); + if (CABINET_hInstance) { + sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate"); + sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy"); + sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy"); + return TRUE; + } else { + ERR("load cabinet dll failed.\n"); + return FALSE; + } + } else + return TRUE; +} + +static void UnloadCABINETDll(void) +{ + if (CABINET_hInstance) { + FreeLibrary(CABINET_hInstance); + CABINET_hInstance = 0; + } +} + +/* FDICreate callbacks */ + +static void *sc_cb_alloc(ULONG cb) +{ + return malloc(cb); +} + +static void sc_cb_free(void *pv) +{ + free(pv); +} + +static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode) +{ + DWORD creation = 0, sharing = 0; + int ioflag = 0; + INT_PTR ret = 0; + SECURITY_ATTRIBUTES sa; + + /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */ + + switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + ioflag |= GENERIC_READ; + break; + case _O_WRONLY: + ioflag |= GENERIC_WRITE; + break; + case _O_RDWR: + ioflag |= GENERIC_READ & GENERIC_WRITE; + break; + case _O_WRONLY | _O_RDWR: /* hmmm.. */ + ERR("_O_WRONLY & _O_RDWR in oflag?\n"); + return -1; + } + + if (oflag & _O_CREAT) { + if (oflag & _O_EXCL) + creation = CREATE_NEW; + else if (oflag & _O_TRUNC) + creation = CREATE_ALWAYS; + else + creation = OPEN_ALWAYS; + } else /* no _O_CREAT */ { + if (oflag & _O_TRUNC) + creation = TRUNCATE_EXISTING; + else + creation = OPEN_EXISTING; + } + + switch( pmode & 0x70 ) { + case _SH_DENYRW: + sharing = 0L; + break; + case _SH_DENYWR: + sharing = FILE_SHARE_READ; + break; + case _SH_DENYRD: + sharing = FILE_SHARE_WRITE; + break; + case _SH_COMPAT: + case _SH_DENYNO: + sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + default: + ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode); + return -1; + } + + if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT)) + WARN("unsupported oflag 0x%04x\n",oflag); + + sa.nLength = sizeof( SECURITY_ATTRIBUTES ); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE; + + ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL); + + /* TRACE("<-- %d\n", ret); */ + + return ret; +} + +static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb) +{ + DWORD num_read; + BOOL rslt; + + /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ + + rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL); + + + /* eof and failure both give "-1" return */ + if ((! rslt) || ((cb > 0) && (num_read == 0))) { + /* TRACE("<-- -1\n"); */ + return -1; + } + + /* TRACE("<-- %lu\n", num_read); */ + return num_read; +} + +static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb) +{ + DWORD num_written; + /* BOOL rv; */ + + /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ + + if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */ + && (num_written == cb)) { + /* TRACE("<-- %lu\n", num_written); */ + return num_written; + } else { + /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */ + /* TRACE("<-- -1\n"); */ + return -1; + } +} + +static int sc_cb_close(INT_PTR hf) +{ + /* TRACE("(hf == %d)\n", hf); */ + + if (CloseHandle((HANDLE) hf)) + return 0; + else + return -1; +} + +static long sc_cb_lseek(INT_PTR hf, long dist, int seektype) +{ + DWORD ret; + + /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */ + + if (seektype < 0 || seektype > 2) + return -1; + + if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) { + /* TRACE("<-- %lu\n", ret); */ + return ret; + } else { + /* TRACE("<-- -1\n"); */ + return -1; + } +} + +#define SIZEOF_MYSTERIO (MAX_PATH*3) + +/* FDICopy callbacks */ + +static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) +{ + FILE_IN_CABINET_INFO_A fici; + PSC_HSC_A phsc; + CABINET_INFO_A ci; + FILEPATHS_A fp; + UINT err; + + CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */ + + memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO); + + TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin); + + if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC)) + phsc = (PSC_HSC_A) pfdin->pv; + else { + ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL); + return -1; + } + + switch (fdint) { + case fdintCABINET_INFO: + TRACE("Cabinet info notification\n"); + /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); + TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); + TRACE(" Cabinet Set#: %d\n", pfdin->setID); + TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ + WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n"); + ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); + ci.CabinetPath = pfdin->psz3; + ci.DiskName = pfdin->psz2; + ci.SetId = pfdin->setID; + ci.CabinetNumber = pfdin->iCabinet; + phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0); + return 0; + case fdintPARTIAL_FILE: + TRACE("Partial file notification\n"); + /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */ + return 0; + case fdintCOPY_FILE: + TRACE("Copy file notification\n"); + TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); + /* TRACE(" File size: %ld\n", pfdin->cb); + TRACE(" File date: %u\n", pfdin->date); + TRACE(" File time: %u\n", pfdin->time); + TRACE(" File attr: %u\n", pfdin->attribs); */ + fici.NameInCabinet = pfdin->psz1; + fici.FileSize = pfdin->cb; + fici.Win32Error = 0; + fici.DosDate = pfdin->date; + fici.DosTime = pfdin->time; + fici.DosAttribs = pfdin->attribs; + memset(&(fici.FullTargetName[0]), 0, MAX_PATH); + err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET, + (UINT) &fici, (UINT) pfdin->psz1); + if (err == FILEOP_DOIT) { + TRACE(" Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0]))); + if (!fici.FullTargetName[0]) { + WARN(" Empty return string causing abort.\n"); + SetLastError(ERROR_PATH_NOT_FOUND); + return -1; + } + return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); + } else { + TRACE(" Callback skipped file.\n"); + return 0; + } + case fdintCLOSE_FILE_INFO: + TRACE("Close file notification\n"); + /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No"); + TRACE(" File hndl: %d\n", pfdin->hf); */ + fp.Source = &(phsc->most_recent_cabinet_name[0]); + fp.Target = pfdin->psz1; + fp.Win32Error = 0; + fp.Flags = 0; + /* the following should be a fixme -- but it occurs too many times */ + WARN("Should set file date/time/attribs (and execute files?)\n"); + err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0); + if (sc_cb_close(pfdin->hf)) + WARN("_close failed.\n"); + if (err) { + SetLastError(err); + return FALSE; + } else + return TRUE; + case fdintNEXT_CABINET: + TRACE("Next cabinet notification\n"); + /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); + TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); + TRACE(" Cabinet Set#: %d\n", pfdin->setID); + TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ + ci.CabinetFile = pfdin->psz1; + ci.CabinetPath = pfdin->psz3; + ci.DiskName = pfdin->psz2; + ci.SetId = pfdin->setID; + ci.CabinetNumber = pfdin->iCabinet; + /* remember the new cabinet name */ + strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1); + err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0])); + if (err) { + SetLastError(err); + return -1; + } else { + if (mysterio[0]) { + /* some easy paranoia. no such carefulness exists on the wide API IIRC */ + mysterio[SIZEOF_MYSTERIO - 1] = '\0'; + strncpy(pfdin->psz3, &(mysterio[0]), 255); + mysterio[255] = '\0'; + } + return 0; + } + default: + FIXME("Unknown notification type %d.\n", fdint); + return 0; + } +} + +static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) +{ + FILE_IN_CABINET_INFO_W fici; + PSC_HSC_W phsc; + CABINET_INFO_W ci; + FILEPATHS_W fp; + UINT err; + int len; + + WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */ + WCHAR buf[MAX_PATH], buf2[MAX_PATH]; + CHAR charbuf[MAX_PATH]; + + memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR)); + memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR)); + memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR)); + memset(&(charbuf[0]), 0, MAX_PATH); + + TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin); + + if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_W_MAGIC)) + phsc = (PSC_HSC_W) pfdin->pv; + else { + ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL); + return -1; + } + + switch (fdint) { + case fdintCABINET_INFO: + TRACE("Cabinet info notification\n"); + /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); + TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); + TRACE(" Cabinet Set#: %d\n", pfdin->setID); + TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ + WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n"); + ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf[0] = '\0'; + ci.CabinetPath = &(buf[0]); + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf2[0] = '\0'; + ci.DiskName = &(buf2[0]); + ci.SetId = pfdin->setID; + ci.CabinetNumber = pfdin->iCabinet; + phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0); + return 0; + case fdintPARTIAL_FILE: + TRACE("Partial file notification\n"); + /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */ + return 0; + case fdintCOPY_FILE: + TRACE("Copy file notification\n"); + TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); + /* TRACE(" File size: %ld\n", pfdin->cb); + TRACE(" File date: %u\n", pfdin->date); + TRACE(" File time: %u\n", pfdin->time); + TRACE(" File attr: %u\n", pfdin->attribs); */ + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf2[0] = '\0'; + fici.NameInCabinet = &(buf2[0]); + fici.FileSize = pfdin->cb; + fici.Win32Error = 0; + fici.DosDate = pfdin->date; + fici.DosTime = pfdin->time; + fici.DosAttribs = pfdin->attribs; + memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR)); + err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET, + (UINT) &fici, (UINT) pfdin->psz1); + if (err == FILEOP_DOIT) { + TRACE(" Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0]))); + if (fici.FullTargetName[0]) { + len = strlenW(&(fici.FullTargetName[0])) + 1; + if ((len > MAX_PATH ) || (len <= 1)) + return 0; + if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0)) + return 0; + } else { + WARN("Empty buffer string caused abort.\n"); + SetLastError(ERROR_PATH_NOT_FOUND); + return -1; + } + return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); + } else { + TRACE(" Callback skipped file.\n"); + return 0; + } + case fdintCLOSE_FILE_INFO: + TRACE("Close file notification\n"); + /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No"); + TRACE(" File hndl: %d\n", pfdin->hf); */ + fp.Source = &(phsc->most_recent_cabinet_name[0]); + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf[0] = '\0'; + fp.Target = &(buf[0]); + fp.Win32Error = 0; + fp.Flags = 0; + /* a valid fixme -- but occurs too many times */ + /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */ + err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0); + if (sc_cb_close(pfdin->hf)) + WARN("_close failed.\n"); + if (err) { + SetLastError(err); + return FALSE; + } else + return TRUE; + case fdintNEXT_CABINET: + TRACE("Next cabinet notification\n"); + /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); + TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); + TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); + TRACE(" Cabinet Set#: %d\n", pfdin->setID); + TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ + /* remember the new cabinet name */ + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + phsc->most_recent_cabinet_name[0] = '\0'; + ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf[0] = '\0'; + ci.CabinetPath = &(buf[0]); + len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH); + if ((len > MAX_PATH) || (len <= 1)) + buf2[0] = '\0'; + ci.DiskName = &(buf2[0]); + ci.SetId = pfdin->setID; + ci.CabinetNumber = pfdin->iCabinet; + err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0])); + if (err) { + SetLastError(err); + return -1; + } else { + if (mysterio[0]) { + len = strlenW(&(mysterio[0])) + 1; + if ((len > 255) || (len <= 1)) + return 0; + if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0)) + return 0; + } + return 0; + } + default: + FIXME("Unknown notification type %d.\n", fdint); + return 0; + } +} + +/*********************************************************************** + * SetupIterateCabinetA (SETUPAPI.@) + */ +BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved, + PSP_FILE_CALLBACK_A MsgHandler, PVOID Context) +{ + + SC_HSC_A my_hsc; + ERF erf; + CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p; + DWORD fpnsize; + BOOL ret; + + + TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n", + debugstr_a(CabinetFile), Reserved, MsgHandler, Context); + + if (! LoadCABINETDll()) + return FALSE; + + memset(&my_hsc, 0, sizeof(SC_HSC_A)); + pszCabinet[0] = '\0'; + pszCabPath[0] = '\0'; + + fpnsize = strlen(CabinetFile); + if (fpnsize >= MAX_PATH) { + SetLastError(ERROR_BAD_PATHNAME); + return FALSE; + } + + fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p); + if (fpnsize > MAX_PATH) { + SetLastError(ERROR_BAD_PATHNAME); + return FALSE; + } + + if (p) { + strcpy(pszCabinet, p); + *p = '\0'; + } else { + strcpy(pszCabinet, CabinetFile); + pszCabPath[0] = '\0'; + } + + TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet)); + + /* remember the cabinet name */ + strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet); + + my_hsc.magic = SC_HSC_A_MAGIC; + my_hsc.msghandler = MsgHandler; + my_hsc.context = Context; + my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read, + sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf ); + + if (!my_hsc.hfdi) return FALSE; + + ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, + 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE; + + sc_FDIDestroy(my_hsc.hfdi); + return ret; +} + + +/*********************************************************************** + * SetupIterateCabinetW (SETUPAPI.@) + */ +BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved, + PSP_FILE_CALLBACK_W MsgHandler, PVOID Context) +{ + CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH]; + UINT len; + SC_HSC_W my_hsc; + ERF erf; + WCHAR pszCabPathW[MAX_PATH], *p; + DWORD fpnsize; + BOOL ret; + + TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n", + debugstr_w(CabinetFile), Reserved, MsgHandler, Context); + + if (!LoadCABINETDll()) + return FALSE; + + if (!CabinetFile) return FALSE; + + memset(&my_hsc, 0, sizeof(SC_HSC_W)); + + fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p); + if (fpnsize > MAX_PATH) { + SetLastError(ERROR_BAD_PATHNAME); + return FALSE; + } + + if (p) { + strcpyW(my_hsc.most_recent_cabinet_name, p); + *p = 0; + len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath, + MAX_PATH, 0, 0); + if (!len) return FALSE; + } else { + strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile); + pszCabPath[0] = '\0'; + } + + len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1, + pszCabinet, MAX_PATH, 0, 0); + if (!len) return FALSE; + + TRACE("path: %s, cabfile: %s\n", + debugstr_a(pszCabPath), debugstr_a(pszCabinet)); + + my_hsc.magic = SC_HSC_W_MAGIC; + my_hsc.msghandler = MsgHandler; + my_hsc.context = Context; + my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read, + sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf ); + + if (!my_hsc.hfdi) return FALSE; + + ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, + 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE; + + sc_FDIDestroy(my_hsc.hfdi); + return ret; +} + + +/*********************************************************************** + * DllMain + * + * PARAMS + * hinstDLL [I] handle to the DLL's instance + * fdwReason [I] + * lpvReserved [I] reserved, must be NULL + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + break; + case DLL_PROCESS_DETACH: + UnloadCABINETDll(); + break; + } + + return TRUE; +} diff --git a/reactos/lib/setupapi/setupx.spec b/reactos/lib/setupapi/setupx.spec new file mode 100644 index 00000000000..be6bcfd640f --- /dev/null +++ b/reactos/lib/setupapi/setupx.spec @@ -0,0 +1,269 @@ +1 stub WEP +2 pascal -ret16 IpOpen(str ptr) IpOpen16 +3 stub IpOpenAppend #(str word) +4 pascal -ret16 IpClose(word) IpClose16 +5 stub IpGetLongField #(word ptr word ptr) +6 stub IpGetStringField #(word ptr word ptr word ptr) +7 stub IpFindFirstLine #(word str str ptr) +8 stub IpGetLineCount #(word str ptr) +9 stub IpGetFieldCount #(word ptr ptr) +10 stub IpGetIntField #(word ptr word ptr) +11 stub IpFindNextLine #(word ptr) +12 stub IpGetFileName #(word ptr word) +13 pascal -ret16 VcpQueueCopy(str str str str word word ptr word long) VcpQueueCopy16 +14 stub NOAUTORUNWNDPROC +15 stub __DEBUGMSG +16 stub __ASSERTMSG +17 pascal -ret16 VcpQueueDelete(str str word long) VcpQueueDelete16 +18 stub TpOpenFile #(str ptr word) +19 stub TpCloseFile #(word) +20 stub TpOpenSection #(word ptr str word) +21 stub TpCloseSection #(word) +22 stub TpCommitSection #(word word str word) +23 stub TpGetLine #(word str str word word ptr) +24 stub TpGetNextLine #(word str str ptr) +25 stub TpInsertLine #(word str str word word word) +26 stub TpReplaceLine #(word str str word word word) +27 stub TpDeleteLine #(word word word word) +28 stub TpMoveLine #(word word word word word word) +29 stub TpGetLineContents #(word ptr word ptr word word word) +30 stub TpGetPrivateProfileString #(str str str ptr word str) +31 stub TpWritePrivateProfileString #(str str str str) +32 stub TpGetProfileString #(str str str ptr word) +33 pascal -ret16 CtlSetLdd(ptr) CtlSetLdd16 +34 pascal -ret16 CtlGetLdd(ptr) CtlGetLdd16 +35 pascal -ret16 CtlFindLdd(ptr) CtlFindLdd16 +36 pascal -ret16 CtlAddLdd(ptr) CtlAddLdd16 +37 pascal -ret16 CtlDelLdd(word) CtlDelLdd16 +38 pascal -ret16 CtlGetLddPath(word ptr) CtlGetLddPath16 +39 stub SURegCloseKey #(word) +40 stub SURegCreateKey #(word) +41 stub SURegDeleteKey #(word str) +42 stub SURegDeleteValue #(word str) +43 stub SURegEnumKey #(word long ptr long) +44 stub SURegEnumValue #(word long str ptr ptr ptr ptr ptr) +45 stub SURegFlush #() +46 stub SURegInit #() +47 pascal SURegOpenKey(word str ptr) SURegOpenKey +48 stub SURegQueryValue +49 stub SURegQueryValue16 #(word str ptr ptr) +50 pascal SURegQueryValueEx(long str ptr ptr ptr ptr) SURegQueryValueEx +51 stub SURegSetValue +52 stub SURegSetValue16 #(word str long ptr long) +53 stub SURegSetValueEx #(word str long long ptr long) +54 stub SURegSaveKey #(word str ptr) +55 stub SURegLoadKey #(word str str) +56 stub SURegUnLoadKey #(word str) +60 stub DiskInfoFromLdid #(word ptr) +61 pascal suErrorToIds(word word) suErrorToIds16 +62 pascal -ret16 TPWriteProfileString(str str str) TPWriteProfileString16 +63 stub SURPLSETUP +# does SUSTORELDIDPATH set the path of an LDID in the registry ? +64 stub SUSTORELDIDPATH +65 stub WILDCARDSTRCMPI +101 pascal -ret16 GenInstall(word str word) GenInstall16 +102 stub GenWinInitRename #(str str word) +103 pascal GenFormStrWithoutPlaceHolders(str str word) GenFormStrWithoutPlaceHolders16 +104 stub SETUPX +105 stub CfgSetupMerge #(word) +106 stub INITDEPENDANTLDIDS +107 stub CFGOBJFINDKEYCMD +108 stub GenSURegSetValueEx +109 stub GENINSTALLWITHQUEUE +110 stub GenInstallEx #(word str word word ptr long) +111 stub GenCopyLogConfig2Reg #(word word str) +112 stub SUGetSetSetupFlags #(ptr word) +114 stub CFGPARSELINE # returns array +115 stub CFGSETAUTOPROCESS +116 stub CFGOBJTOSTR +117 stub CFGLNTOOBJ +118 stub MATCHCMDEXT +119 stub IpFindNextMatchLine #(word str ptr) +120 stub P_SETDEFAULTOPTION +121 stub CFGCLEANBOOT +122 stub CFGMATCHCMDEXT +123 stub CFGWASFILEUPDATED +124 stub AUTOMATCHCMDEXT +125 stub P_VALIDATEOC +126 stub GENMAPROOTREGSTR2KEY +127 stub P_CDROMOC +128 stub P_MEDIAOC +129 stub CFGCLEAN1STBOOT +130 stub suFormatMessage +131 stub suvFormatMessage #(word str str word ptr) +132 stub suFormatMessageBox +#133 stub suHelp # W98SE conflict !! +135 stub suHelp #(word word) +#135 stub P_WEBTVOC # W98SE conflict !! +136 stub P_WBEMOC +137 stub P_THEMESOC +138 stub P_IMAGINGOC +139 stub P_SCHEMESOC +140 stub suVerConflict #(word ptr word ptr) +141 stub suVerConflictInit #(word) +142 stub suVerConflictTerm #(ptr) +# Emergency Boot Disk +143 stub suCreateEBD #(word ptr long) +144 stub suCopyToEBD +145 stub sxIsMSDOS7Running #() +150 stub DS_INIT +151 stub DS_DESTROY +152 stub DS_SSYNCDRIVES +153 stub DS_GETDRIVEDATA +154 stub DS_ADDSECTION +155 stub DS_ENABLESECTION +156 stub DS_DISABLESECTION +157 stub DS_SETSWAPSIZE +158 stub DS_SETREQUIREDPAD +159 stub DS_SETAVAILABLEPAD +160 stub SXUPDATEDS +170 stub SUSETMEM +171 stub WriteDMFBootData #(word ptr word) +200 pascal VcpOpen(segptr ptr) VcpOpen16 +201 pascal VcpClose(word str) VcpClose16 +202 pascal -ret16 vcpDefCallbackProc(ptr word word long long) vcpDefCallbackProc16 +203 stub vcpEnumFiles #(ptr long) +204 pascal -ret16 VcpQueueRename(str str str str word word long) VcpQueueRename16 +205 pascal -ret16 vsmGetStringName(word ptr word) vsmGetStringName16 +206 pascal -ret16 vsmStringDelete(word) vsmStringDelete16 +207 pascal -ret16 vsmStringAdd(str) vsmStringAdd16 +208 pascal vsmGetStringRawName(word) vsmGetStringRawName16 +209 stub IpSaveRestorePosition #(word word) +210 pascal -ret16 IpGetProfileString(word str str ptr word) IpGetProfileString16 +211 stub IpOpenEx #(str ptr word) +212 stub IpOpenAppendEx #(str word word) +213 pascal -ret16 vcpUICallbackProc(ptr word word long long) vcpUICallbackProc16 +214 stub VcpAddMRUPath #(str) +300 pascal -ret16 DiBuildCompatDrvList (ptr) DiBuildCompatDrvList16 +301 pascal -ret16 DiBuildClassDrvList (ptr) DiBuildClassDrvList16 +302 stub DiDestroyDriverNodeList #(ptr) +303 pascal -ret16 DiCreateDeviceInfo (ptr str long long str str word) DiCreateDeviceInfo16 +304 pascal -ret16 DiGetClassDevs(ptr str word word) DiGetClassDevs16 +305 pascal -ret16 DiDestroyDeviceInfoList (ptr) DiDestroyDeviceInfoList16 +306 stub DiRemoveDevice #(ptr) +308 pascal -ret16 DiCallClassInstaller (word ptr) DiCallClassInstaller16 +309 stub DiCreateDriverNode #(ptr word word word str str str str str str long) +310 stub DiDrawMiniIcon +311 stub DiGetClassBitmapIndex #(str ptr) +312 stub DiSelectDevice #(ptr) +313 stub DiInstallDevice #(ptr) +314 stub DiLoadClassIcon #(str ptr ptr) +315 stub DiAskForOEMDisk #(ptr) +316 stub Display_SetMode #(ptr word word word) +317 stub Display_ClassInstaller #(word ptr) +318 pascal -ret16 DiCreateDevRegKey (ptr ptr word str word) DiCreateDevRegKey16 +319 pascal -ret16 DiOpenDevRegKey (ptr ptr word) DiOpenDevRegKey16 +320 stub DiInstallDrvSection #(str str str str long) +321 stub DiInstallClass #(str long) +322 stub DiOpenClassRegKey #(ptr str) +323 stub Display_SetFontSize #(str) +324 stub Display_OpenFontSizeKey #(ptr) +325 stub DiBuildClassDrvListFromOldInf #(ptr str ptr long) +326 stub DiIsThereNeedToCopy #(word long) +333 stub DiChangeState #(ptr long long long) +334 stub WALKSUBTREE +340 stub GetFctn #(word str str ptr ptr) +341 stub DiBuildClassInfoList #(ptr) +342 stub DiDestroyClassInfoList #(ptr) +343 stub DiGetDeviceClassInfo #(ptr ptr) +344 pascal -ret16 DiDeleteDevRegKey (ptr word) DiDeleteDevRegKey16 +350 stub DiSelectOEMDrv #(word ptr) +351 stub DiGetINFClass #(str word str long) +353 stub DIPICKBESTDRIVER +355 stub COPYINFFILE +360 stub GenInfLCToDevNode #(word str word word long) +361 stub GETDOSMESSAGE +362 stub Mouse_ClassInstaller #(word ptr) +363 stub sxCompareDosAppVer #(str str) +364 stub MONITOR_CLASSINSTALLER +365 stub FCEGETRESDESOFFSET +366 stub FCEGETALLOCVALUE +367 stub FCEADDRESDES +368 stub FCEDELETERESDES +369 stub FCEINIT +370 stub FCEGETRESDES +371 stub FCEGETFIRSTVALUE +372 stub FCEGETOTHERVALUE +373 stub FCEGETVALIDATEVALUE +374 stub FCEWRITETHISFORCEDCONFIGNOW +375 stub SUCreatePropertySheetPage #(ptr) +376 stub SUDestroyPropertySheetPage #(word) +377 stub SUPropertySheet #(ptr) +380 stub DiReadRegLogConf #(ptr str ptr ptr) +381 stub DiReadRegConf #(ptr ptr ptr long) +390 stub DiBuildPotentialDuplicatesList #(ptr ptr long ptr ptr) +395 stub InitSubstrData #(ptr str) +396 stub GetFirstSubstr #(ptr) +397 stub GetNextSubstr #(ptr) +398 stub INITSUBSTRDATAEX +400 stub bIsFileInVMM32 #(str) +401 stub DiInstallDriverFiles #(ptr) +405 stub DiBuildClassInfoListEx #(ptr long) +406 stub DiGetClassDevsEx #(ptr str str word word) +407 stub DiCopyRegSubKeyValue #(word str str str) +408 stub IPGETDRIVERDATE +409 stub IPGETDRIVERVERSION +410 stub IpGetVersionString #(str str ptr word str) +411 pascal VcpExplain(ptr long) VcpExplain16 +412 stub DiBuildDriverIndex #(word) +413 stub DiAddSingleInfToDrvIdx #(str word word) +414 stub FCEGETFLAGS +450 stub UiMakeDlgNonBold #(word) +451 stub UiDeleteNonBoldFont #(word) +500 stub SUEBDPAGE +501 stub SUOCPAGE +502 stub SXLISTSUBPROC +503 stub SXFILLLB +504 stub SXOCPAGEDLG +506 stub SXOCBATCHSETTINGS +507 stub SXOCFIXNEEDS +508 pascal -ret16 CtlSetLddPath(word str) CtlSetLddPath16 +509 stub SXCALLOCPROC +510 stub BUILDINFOCS +511 stub BUILDREGOCS +512 stub DELETEOCS +520 stub DiBuildClassDrvInfoList #(ptr) +521 stub DiBuildCompatDrvInfoList #(ptr) +522 stub DiDestroyDrvInfoList #(ptr) +523 stub DiConvertDriverInfoToDriverNode #(ptr ptr) +524 stub DISELECTBESTCOMPATDRV +525 stub FirstBootMoveToDOSSTART #(str word) +526 stub DOSOptEnableCurCfg #(str) +527 pascal -ret16 InstallHinfSection(word word str word) InstallHinfSection16 +528 stub SXMAKEUNCPATH +529 stub SXISSBSSERVERFILE +530 stub SXFINDBATCHFILES +531 stub ISPANEUROPEAN +532 stub UPGRADENIGGLINGS +533 stub DISPLAY_ISSECONDDISPLAY +534 stub ISWINDOWSFILE +540 stub VERIFYSELECTEDDRIVER +575 stub SXCALLMIGRATIONDLLS +576 stub SXCALLMIGRATIONDLLS_RUNDLL +600 stub PidConstruct #(str str str word) +601 stub PidValidate #(str str) +602 stub GETJAPANESEKEYBOARDTYPE +610 stub CRC32COMPUTE +621 stub SXSAVEINFO +622 stub SXADDPAGEEX +623 stub OPKREMOVEINSTALLEDNETDEVICE +640 stub DOFIRSTRUNSCREENS +700 stub SXSHOWREBOOTDLG +701 stub SXSHOWREBOOTDLG_RUNDLL +750 stub UIPOSITIONDIALOG +775 stub ASPICLEAN +800 stub EXTRACTCABFILE +825 stub PIDGEN3 +826 stub GETSETUPINFO +827 stub SETSETUPINFO +828 stub GETKEYBOARDOPTIONS +829 stub GETLOCALEOPTIONS +830 stub SETINTLOPTIONS +831 stub GETPRODUCTTYPE +832 stub ISOPKMODE +833 stub AUDITONETIMEINSTALL +834 stub DISKDUP +835 stub OPKPREINSTALL +836 stub ISAUDITMODE +837 stub ISAUDITAUTO +838 stub GETVALIDEULA diff --git a/reactos/lib/setupapi/setupx16.h b/reactos/lib/setupapi/setupx16.h new file mode 100644 index 00000000000..4b5468fd5a3 --- /dev/null +++ b/reactos/lib/setupapi/setupx16.h @@ -0,0 +1,563 @@ +/* + * Copyright 2000 Andreas Mohr for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SETUPX16_H +#define __SETUPX16_H + +#include "wine/windef16.h" + +typedef UINT16 DI_FUNCTION16; +typedef UINT16 HINF16; +typedef UINT16 LOGDISKID16; +typedef UINT16 VHSTR; + +#define LINE_LEN 256 + +/* error codes stuff */ + +typedef UINT16 RETERR16; +#define OK 0 +#define IP_ERROR (UINT16)100 +#define TP_ERROR (UINT16)200 +#define VCP_ERROR (UINT16)300 +#define GEN_ERROR (UINT16)400 +#define DI_ERROR (UINT16)500 + +enum { + ERR_IP_INVALID_FILENAME = IP_ERROR+1, + ERR_IP_ALLOC_ERR, + ERR_IP_INVALID_SECT_NAME, + ERR_IP_OUT_OF_HANDLES, + ERR_IP_INF_NOT_FOUND, + ERR_IP_INVALID_INFFILE, + ERR_IP_INVALID_HINF, + ERR_IP_INVALID_FIELD, + ERR_IP_SECT_NOT_FOUND, + ERR_IP_END_OF_SECTION, + ERR_IP_PROFILE_NOT_FOUND, + ERR_IP_LINE_NOT_FOUND, + ERR_IP_FILEREAD, + ERR_IP_TOOMANYINFFILES, + ERR_IP_INVALID_SAVERESTORE, + ERR_IP_INVALID_INFTYPE +}; + +/****** virtual copy operations ******/ + +typedef DWORD LPEXPANDVTBL; + +typedef struct { + DWORD dwSoFar; + DWORD dwTotal; +} VCPPROGRESS, *LPVCPPROGRESS; + +typedef struct { + WORD cbSize; + LOGDISKID16 ldid; + VHSTR vhstrRoot; + VHSTR vhstrVolumeLabel; + VHSTR vhstrDiskName; + WORD wVolumeTime; + WORD wVolumeDate; + DWORD dwSerialNumber; + WORD fl; + LPARAM lparamRef; + + VCPPROGRESS prgFileRead; + VCPPROGRESS prgByteRead; + + VCPPROGRESS prgFileWrite; + VCPPROGRESS prgByteWrite; +} VCPDISKINFO, *LPVCPDISKINFO; + +typedef struct { + LOGDISKID16 ldid; + VHSTR vhstrDir; + VHSTR vhstrFileName; +} VCPFILESPEC, *LPVCPFILESPEC; + +typedef struct { + UINT16 uiMDate; + UINT16 uiMTime; + UINT16 uiADate; + UINT16 uiATime; + UINT16 uiAttr; + DWORD llenIn; + DWORD llenOut; +} VCPFATTR, *LPVCPFATTR; + +typedef struct { + UINT16 uDate; + UINT16 uTime; + DWORD dwSize; +} VCPFILESTAT, *LPVCPFILESTAT; + +typedef struct +{ + HFILE16 hFileSrc; + HFILE16 hFileDst; + VCPFATTR fAttr; + WORD dosError; + VHSTR vhstrFileName; + WPARAM vcpm; +} VIRTNODEEX, *LPVIRTNODEEX; + +typedef struct { + WORD cbSize; + VCPFILESPEC vfsSrc; + VCPFILESPEC vfsDst; + WORD fl; + LPARAM lParam; + LPEXPANDVTBL lpExpandVtbl; + LPVIRTNODEEX lpvnex; + VHSTR vhstrDstFinalName; + VCPFILESTAT vFileStat; +} VIRTNODE, *LPVIRTNODE; + +typedef struct { + WORD cbSize; + VCPPROGRESS prgDiskRead; + VCPPROGRESS prgFileRead; + VCPPROGRESS prgByteRead; + + VCPPROGRESS prgDiskWrite; + VCPPROGRESS prgFileWrite; + VCPPROGRESS prgByteWrite; + + LPVCPDISKINFO lpvdiIn; + LPVCPDISKINFO lpvdiOut; + LPVIRTNODE lpvn; +} VCPSTATUS, *LPVCPSTATUS; + +#define CNFL_BACKUP 0x0001 +#define CNFL_DELETEONFAILURE 0x0002 +#define CNFL_RENAMEONSUCCESS 0x0004 +#define CNFL_CONTINUATION 0x0008 +#define CNFL_SKIPPED 0x0010 +#define CNFL_IGNOREERRORS 0x0020 +#define CNFL_RETRYFILE 0x0040 +#define CNFL_COPIED 0x0080 +#define VNFL_UNIQUE 0x0000 +#define VNFL_MULTIPLEOK 0x0100 +#define VNFL_DESTROYOLD 0x0200 +#define VNFL_COPY 0x0000 +#define VNFL_DELETE 0x0800 +#define VNFL_RENAME 0x1000 +#define VNFL_NODE_TYPE (VNFL_RENAME|VNFL_DELETE|VNFL_COPY) +#define VNFL_CREATED 0x2000 +#define VNFL_REJECTED 0x4000 +#define VNFL_DEVICEINSTALLER 0x8000 + +enum { + ERR_VCP_IOFAIL = VCP_ERROR+1, + ERR_VCP_STRINGTOOLONG, + ERR_VCP_NOMEM, + ERR_VCP_QUEUEFULL, + ERR_VCP_NOVHSTR, + ERR_VCP_OVERFLOW, + ERR_VCP_BADARG, + ERR_VCP_UNINIT, + ERR_VCP_NOTFOUND, + ERR_VCP_BUSY, + ERR_VCP_INTERRUPTED, + ERR_VCP_BADDEST, + ERR_VCP_SKIPPED, + ERR_VCP_IO, + ERR_VCP_LOCKED, + ERR_VCP_WRONGDISK, + ERR_VCP_CHANGEMODE, + ERR_VCP_LDDINVALID, + ERR_VCP_LDDFIND, + ERR_VCP_LDDUNINIT, + ERR_VCP_LDDPATH_INVALID, + ERR_VCP_NOEXPANSION, + ERR_VCP_NOTOPEN, + ERR_VCP_NO_DIGITAL_SIGNATURE_CATALOG, + ERR_VCP_NO_DIGITAL_SIGNATURE_FILE +}; + +#define VCPN_OK 0 +#define VCPN_PROCEED 0 +#define VCPN_ABORT -1 +#define VCPN_RETRY -2 +#define VCPN_IGNORE -3 +#define VCPN_SKIP -4 +#define VCPN_FORCE -5 +#define VCPN_DEFER -6 +#define VCPN_FAIL -7 +#define VCPN_RETRYFILE -8 + +#define VCPFL_ABANDON 0x00 +#define VCPFL_BACKUP 0x01 +#define VCPFL_COPY 0x02 +#define VCPFL_BACKUPANDCOPY (VCPFL_BACKUP|VCPFL_COPY) +#define VCPFL_INSPECIFIEDORDER 0x04 +#define VCPFL_DELETE 0x08 +#define VCPFL_RENAME 0x10 +#define VCPFL_ALL (VCPFL_COPY|VCPFL_DELETE|VCPFL_RENAME) + +#define CFNL_BACKUP 0x0001 +#define CFNL_DELETEONFAILURE 0x0002 +#define CFNL_RENAMEONSUCCESS 0x0004 +#define CFNL_CONTINUATION 0x0008 +#define CFNL_SKIPPED 0x0010 +#define CFNL_IGNOREERRORS 0x0020 +#define CFNL_RETRYFILE 0x0040 +#define CFNL_COPIED 0x0080 +#define VFNL_MULTIPLEOK 0x0100 +#define VFNL_DESTROYOLD 0x0200 +#define VFNL_NOW 0x0400 +#define VFNL_COPY 0x0000 +#define VFNL_DELETE 0x0800 +#define VFNL_RENAME 0x1000 +#define VFNL_CREATED 0x2000 +#define VFNL_REJECTED 0x4000 +#define VCPM_DISKCLASS 0x01 +#define VCPM_DISKFIRST 0x0100 +#define VCPM_DISKLAST 0x01ff + +enum { + VCPM_DISKCREATEINFO = VCPM_DISKFIRST, + VCPM_DISKGETINFO, + VCPM_DISKDESTROYINFO, + VCPM_DISKPREPINFO, + VCPM_DISKENSURE, + VCPM_DISKPROMPT, + VCPM_DISKFORMATBEGIN, + VCPM_DISKFORMATTING, + VCPM_DISKFORMATEND +}; + +#define VCPM_FILEINCLASS 0x02 +#define VCPM_FILEOUTCLASS 0x03 +#define VCPM_FILEFIRSTIN 0x0200 +#define VCPM_FILEFIRSTOUT 0x0300 +#define VCPM_FILELAST 0x03ff + +enum { + VCPM_FILEOPENIN = VCPM_FILEFIRSTIN, + VCPM_FILEGETFATTR, + VCPM_FILECLOSEIN, + VCPM_FILECOPY, + VCPM_FILENEEDED, + + VCPM_FILEOPENOUT = VCPM_FILEFIRSTOUT, + VCPM_FILESETFATTR, + VCPM_FILECLOSEOUT, + VCPM_FILEFINALIZE, + VCPM_FILEDELETE, + VCPM_FILERENAME +}; + +#define VCPM_NODECLASS 0x04 +#define VCPM_NODEFIRST 0x0400 +#define VCPM_NODELAST 0x04ff + +enum { + VCPM_NODECREATE = VCPM_NODEFIRST, + VCPM_NODEACCEPT, + VCPM_NODEREJECT, + VCPM_NODEDESTROY, + VCPM_NODECHANGEDESTDIR, + VCPM_NODECOMPARE +}; + +#define VCPM_TALLYCLASS 0x05 +#define VCPM_TALLYFIRST 0x0500 +#define VCPM_TALLYLAST 0x05ff + +enum { + VCPM_TALLYSTART = VCPM_TALLYFIRST, + VCPM_TALLYEND, + VCPM_TALLYFILE, + VCPM_TALLYDISK +}; + +#define VCPM_VERCLASS 0x06 +#define VCPM_VERFIRST 0x0600 +#define VCPM_VERLAST 0x06ff + +enum { + VCPM_VERCHECK = VCPM_VERFIRST, + VCPM_VERCHECKDONE, + VCPM_VERRESOLVECONFLICT +}; + +#define VCPM_VSTATCLASS 0x07 +#define VCPM_VSTATFIRST 0x0700 +#define VCPM_VSTATLAST 0x07ff + +enum { + VCPM_VSTATSTART = VCPM_VSTATFIRST, + VCPM_VSTATEND, + VCPM_VSTATREAD, + VCPM_VSTATWRITE, + VCPM_VSTATNEWDISK, + VCPM_VSTATCLOSESTART, + VCPM_VSTATCLOSEEND, + VCPM_VSTATBACKUPSTART, + VCPM_VSTATBACKUPEND, + VCPM_VSTATRENAMESTART, + VCPM_VSTATRENAMEEND, + VCPM_VSTATCOPYSTART, + VCPM_VSTATCOPYEND, + VCPM_VSTATDELETESTART, + VCPM_VSTATDELETEEND, + VCPM_VSTATPATHCHECKSTART, + VCPM_VSTATPATHCHECKEND, + VCPM_VSTATCERTIFYSTART, + VCPM_VSTATCERTIFYEND, + VCPM_VSTATUSERABORT, + VCPM_VSTATYIELD +}; + +#define VCPM_PATHCLASS 0x08 +#define VCPM_PATHFIRST 0x0800 +#define VCPM_PATHLAST 0x08ff + +enum { + VCPM_BUILDPATH = VCPM_PATHFIRST, + VCPM_UNIQUEPATH, + VCPM_CHECKPATH +}; + +#define VCPM_PATCHCLASS 0x09 +#define VCPM_PATCHFIRST 0x0900 +#define VCPM_PATCHLAST 0x09ff + +enum { + VCPM_FILEPATCHBEFORECPY = VCPM_PATCHFIRST, + VCPM_FILEPATCHAFTERCPY, + VCPM_FILEPATCHINFOPEN, + VCPM_FILEPATCHINFCLOSE +}; + +#define VCPM_CERTCLASS 0x0a +#define VCPM_CERTFIRST 0x0a00 +#define VCPM_CERTLAST 0x0aff + +enum { + VCPM_FILECERTIFY = VCPM_CERTFIRST, + VCPM_FILECERTIFYWARN +}; + +typedef LRESULT (CALLBACK *VIFPROC)(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam, LPARAM lParam, LPARAM lparamRef); + +typedef int (CALLBACK *VCPENUMPROC)(LPVIRTNODE lpvn, LPARAM lparamRef); + +RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef); + +/* VcpQueueCopy flags */ +#define VNLP_SYSCRITICAL 0x0001 +#define VNLP_SETUPCRITICAL 0x0002 +#define VNLP_NOVERCHECK 0x0004 +#define VNLP_FORCETEMP 0x0008 +#define VNLP_IFEXISTS 0x0010 +#define VNLP_KEEPNEWER 0x0020 +#define VNLP_PATCHIFEXIST 0x0040 +#define VNLP_NOPATCH 0x0080 +#define VNLP_CATALOGCERT 0x0100 +#define VNLP_NEEDCERTIFY 0x0200 +#define VNLP_COPYIFEXISTS 0x0400 + +RETERR16 WINAPI VcpQueueCopy16( + LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName, + LPCSTR lpszSrcDir, LPCSTR lpszDstDir, + LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst, + LPEXPANDVTBL lpExpandVtbl, + WORD fl, LPARAM lParam +); +RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest); +RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest); + +/* VcpExplain flags */ +enum { + VCPEX_SRC_DISK, + VCPEX_SRC_CABINET, + VCPEX_SRC_LOCN, + VCPEX_DST_LOCN, + VCPEX_SRC_FILE, + VCPEX_DST_FILE, + VCPEX_DST_FILE_FINAL, + VCPEX_DOS_ERROR, + VCPEX_MESSAGE, + VCPEX_DOS_SOLUTION, + VCPEX_SRC_FULL, + VCPEX_DST_FULL, + VCPEX_DST_FULL_FINAL +}; + +LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat); + +/****** logical disk management ******/ + +typedef struct _LOGDISKDESC_S { /* ldd */ + WORD cbSize; /* struct size */ + LOGDISKID16 ldid; /* logical disk ID */ + LPSTR pszPath; /* path this descriptor points to */ + LPSTR pszVolLabel; /* volume label of the disk related to it */ + LPSTR pszDiskName; /* name of this disk */ + WORD wVolTime; /* modification time of volume label */ + WORD wVolDate; /* modification date */ + DWORD dwSerNum; /* serial number of disk */ + WORD wFlags; +} LOGDISKDESC_S, *LPLOGDISKDESC; + +/** logical disk identifiers (LDID) **/ + +/* predefined LDIDs */ +#define LDID_PREDEF_START 0x0001 +#define LDID_PREDEF_END 0x7fff + +/* registry-assigned LDIDs */ +#define LDID_VAR_START 0x7000 +#define LDID_VAR_END 0x7fff + +/* dynamically assigned LDIDs */ +#define LDID_ASSIGN_START 0x8000 +#define LDID_ASSIGN_END 0xbfff + +#define LDID_NULL 0 +#define LDID_ABSOLUTE ((UINT)-1) +#define LDID_SRCPATH 1 /* setup source path */ +#define LDID_SETUPTEMP 2 /* setup temp dir */ +#define LDID_UNINSTALL 3 /* uninstall dir */ +#define LDID_BACKUP 4 /* backup dir */ +#define LDID_SETUPSCRATCH 5 /* setup scratch dir */ +#define LDID_WIN 10 /* win dir */ +#define LDID_SYS 11 /* win system dir */ +#define LDID_IOS 12 /* win Iosubsys dir */ +#define LDID_CMD 13 /* win command dir */ +#define LDID_CPL 14 /* win control panel dir */ +#define LDID_PRINT 15 /* win printer dir */ +#define LDID_MAIL 16 /* win mail dir */ +#define LDID_INF 17 /* win inf dir */ +#define LDID_HELP 18 /* win help dir */ +#define LDID_WINADMIN 19 /* admin dir */ +#define LDID_FONTS 20 /* win fonts dir */ +#define LDID_VIEWERS 21 /* win viewers dir */ +#define LDID_VMM32 22 /* win VMM32 dir */ +#define LDID_COLOR 23 /* win color mngment dir */ +#define LDID_APPS 24 /* win apps dir */ +#define LDID_SHARED 25 /* win shared dir */ +#define LDID_WINBOOT 26 /* guaranteed win boot drive */ +#define LDID_MACHINE 27 /* machine specific files */ +#define LDID_HOST_WINBOOT 28 +#define LDID_BOOT 30 /* boot drive root dir */ +#define LDID_BOOT_HOST 31 /* boot drive host root dir */ +#define LDID_OLD_WINBOOT 32 /* root subdir */ +#define LDID_OLD_WIN 33 /* old windows dir */ + +/* flags for GenInstall() */ +#define GENINSTALL_DO_FILES 1 +#define GENINSTALL_DO_INI 2 +#define GENINSTALL_DO_REG 4 +#define GENINSTALL_DO_INI2REG 8 +#define GENINSTALL_DO_CFGAUTO 16 +#define GENINSTALL_DO_LOGCONFIG 32 +#define GENINSTALL_DO_REGSRCPATH 64 +#define GENINSTALL_DO_PERUSER 128 + +#define GEINISTALL_DO_INIREG 14 +#define GENINSTALL_DO_ALL 255 + +/* + * flags for InstallHinfSection() + * 128 can be added, too. This means that the .inf file is provided by you + * instead of being a 32 bit file (i.e. Windows .inf file). + * In this case all files you install must be in the same dir + * as your .inf file on the install disk. + */ +#define HOW_NEVER_REBOOT 0 +#define HOW_ALWAYS_SILENT_REBOOT 1 +#define HOW_ALWAYS_PROMPT_REBOOT 2 +#define HOW_SILENT_REBOOT 3 +#define HOW_PROMPT_REBOOT 4 + +/****** device installation stuff ******/ + +#define MAX_CLASS_NAME_LEN 32 +#define MAX_DEVNODE_ID_LEN 256 +#define MAX_GUID_STR 50 + +typedef struct _DEVICE_INFO +{ + UINT16 cbSize; + struct _DEVICE_INFO *lpNextDi; + char szDescription[LINE_LEN]; + DWORD dnDevnode; + HKEY hRegKey; + char szRegSubkey[MAX_DEVNODE_ID_LEN]; + char szClassName[MAX_CLASS_NAME_LEN]; + DWORD Flags; + HWND16 hwndParent; + /*LPDRIVER_NODE*/ LPVOID lpCompatDrvList; + /*LPDRIVER_NODE*/ LPVOID lpClassDrvList; + /*LPDRIVER_NODE*/ LPVOID lpSelectedDriver; + ATOM atDriverPath; + ATOM atTempInfFile; + HINSTANCE16 hinstClassInstaller; + HINSTANCE16 hinstClassPropProvidor; + HINSTANCE16 hinstDevicePropProvidor; + HINSTANCE16 hinstBasicPropProvidor; + FARPROC16 fpClassInstaller; + FARPROC16 fpClassEnumPropPages; + FARPROC16 fpDeviceEnumPropPages; + FARPROC16 fpEnumBasicProperties; + DWORD dwSetupReserved; + DWORD dwClassInstallReserved; + /*GENCALLBACKPROC*/ LPVOID gicpGenInstallCallBack; + + LPARAM gicplParam; + UINT16 InfType; + + HINSTANCE16 hinstPrivateProblemHandler; + FARPROC16 fpPrivateProblemHandler; + LPARAM lpClassInstallParams; + struct _DEVICE_INFO *lpdiChildList; + DWORD dwFlagsEx; + /*LPDRIVER_INFO*/ LPVOID lpCompatDrvInfoList; + /*LPDRIVER_INFO*/ LPVOID lpClassDrvInfoList; + char szClassGUID[MAX_GUID_STR]; +} DEVICE_INFO16, *LPDEVICE_INFO16, **LPLPDEVICE_INFO16; + + +extern void WINAPI GenFormStrWithoutPlaceHolders16(LPSTR,LPCSTR,HINF16); +extern RETERR16 WINAPI IpOpen16(LPCSTR,HINF16 *); +extern RETERR16 WINAPI IpClose16(HINF16); +extern RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC); +extern RETERR16 WINAPI CtlDelLdd16(LOGDISKID16); +extern RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath); +extern RETERR16 WINAPI GenInstall16(HINF16,LPCSTR,WORD); + +typedef struct tagLDD_LIST { + LPLOGDISKDESC pldd; + struct tagLDD_LIST *next; +} LDD_LIST; + +#define INIT_LDD(ldd, LDID) \ + do { \ + memset(&(ldd), 0, sizeof(LOGDISKDESC_S)); \ + (ldd).cbSize = sizeof(LOGDISKDESC_S); \ + ldd.ldid = LDID; \ + } while(0) + +#endif /* __SETUPX16_H */ diff --git a/reactos/lib/setupapi/setupx_main.c b/reactos/lib/setupapi/setupx_main.c new file mode 100644 index 00000000000..8610ce0a55f --- /dev/null +++ b/reactos/lib/setupapi/setupx_main.c @@ -0,0 +1,615 @@ +/* + * SETUPX library + * + * Copyright 1998,2000 Andreas Mohr + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: Rather non-functional functions for now. + * + * See: + * http://www.geocities.com/SiliconValley/Network/5317/drivers.html + * http://willemer.de/informatik/windows/inf_info.htm (German) + * http://www.microsoft.com/ddk/ddkdocs/win98ddk/devinst_12uw.htm + * DDK: setupx.h + * http://mmatrix.tripod.com/customsystemfolder/infsysntaxfull.html + * http://www.rdrop.com/~cary/html/inf_faq.html + * http://support.microsoft.com/support/kb/articles/q194/6/40.asp + * + * Stuff tested with: + * - rs405deu.exe (German Acroread 4.05 setup) + * - ie5setup.exe + * - Netmeeting + * + * FIXME: + * - string handling is... weird ;) (buflen etc.) + * - memory leaks ? + * - separate that mess (but probably only when it's done completely) + * + * SETUPX consists of several parts with the following acronyms/prefixes: + * Di device installer (devinst.c ?) + * Gen generic installer (geninst.c ?) + * Ip .INF parsing (infparse.c) + * LDD logical device descriptor (ldd.c ?) + * LDID logical device ID + * SU setup (setup.c ?) + * Tp text processing (textproc.c ?) + * Vcp virtual copy module (vcp.c ?) + * ... + * + * The SETUPX DLL is NOT thread-safe. That's why many installers urge you to + * "close all open applications". + * All in all the design of it seems to be a bit weak. + * Not sure whether my implementation of it is better, though ;-) + */ + +#include +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" +#include "wine/winuser16.h" +#include "wownt32.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "setupapi.h" +#include "setupx16.h" +#include "setupapi_private.h" +#include "winerror.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) + +/*********************************************************************** + * SURegOpenKey (SETUPX.47) + */ +DWORD WINAPI SURegOpenKey( HKEY hkey, LPCSTR lpszSubKey, PHKEY retkey ) +{ + FIXME("(%p,%s,%p), semi-stub.\n",hkey,debugstr_a(lpszSubKey),retkey); + return RegOpenKeyA( hkey, lpszSubKey, retkey ); +} + +/*********************************************************************** + * SURegQueryValueEx (SETUPX.50) + */ +DWORD WINAPI SURegQueryValueEx( HKEY hkey, LPSTR lpszValueName, + LPDWORD lpdwReserved, LPDWORD lpdwType, + LPBYTE lpbData, LPDWORD lpcbData ) +{ + FIXME("(%p,%s,%p,%p,%p,%ld), semi-stub.\n",hkey,debugstr_a(lpszValueName), + lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0); + return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType, + lpbData, lpcbData ); +} + + +/*********************************************************************** + * InstallHinfSection (SETUPX.527) + * + * hwnd = parent window + * hinst = instance of SETUPX.DLL + * lpszCmdLine = e.g. "DefaultInstall 132 C:\MYINSTALL\MYDEV.INF" + * Here "DefaultInstall" is the .inf file section to be installed (optional). + * The 132 value is made of the HOW_xxx flags and sometimes 128 (-> setupx16.h). + * + * nCmdShow = nCmdShow of CreateProcess + */ +RETERR16 WINAPI InstallHinfSection16( HWND16 hwnd, HINSTANCE16 hinst, LPCSTR lpszCmdLine, INT16 nCmdShow) +{ + InstallHinfSectionA( HWND_32(hwnd), HINSTANCE_32(hinst), lpszCmdLine, nCmdShow ); + return OK; +} + +typedef struct +{ + LPCSTR RegValName; + LPCSTR StdString; /* fallback string; sub dir of windows directory */ +} LDID_DATA; + +static const LDID_DATA LDID_Data[34] = +{ + { /* 0 (LDID_NULL) -- not defined */ + NULL, + NULL + }, + { /* 1 (LDID_SRCPATH) = source of installation. hmm, what to do here ? */ + "SourcePath", /* hmm, does SETUPX have to care about updating it ?? */ + NULL + }, + { /* 2 (LDID_SETUPTEMP) = setup temp dir */ + "SetupTempDir", + NULL + }, + { /* 3 (LDID_UNINSTALL) = uninstall backup dir */ + "UninstallDir", + NULL + }, + { /* 4 (LDID_BACKUP) = backup dir */ + "BackupDir", + NULL + }, + { /* 5 (LDID_SETUPSCRATCH) = setup scratch dir */ + "SetupScratchDir", + NULL + }, + { /* 6 -- not defined */ + NULL, + NULL + }, + { /* 7 -- not defined */ + NULL, + NULL + }, + { /* 8 -- not defined */ + NULL, + NULL + }, + { /* 9 -- not defined */ + NULL, + NULL + }, + { /* 10 (LDID_WIN) = windows dir */ + "WinDir", + "" + }, + { /* 11 (LDID_SYS) = system dir */ + "SysDir", + NULL /* call GetSystemDirectory() instead */ + }, + { /* 12 (LDID_IOS) = IOSubSys dir */ + NULL, /* FIXME: registry string ? */ + "SYSTEM\\IOSUBSYS" + }, + { /* 13 (LDID_CMD) = COMMAND dir */ + NULL, /* FIXME: registry string ? */ + "COMMAND" + }, + { /* 14 (LDID_CPL) = control panel dir */ + NULL, + "" + }, + { /* 15 (LDID_PRINT) = windows printer dir */ + NULL, + "SYSTEM" /* correct ?? */ + }, + { /* 16 (LDID_MAIL) = destination mail dir */ + NULL, + "" + }, + { /* 17 (LDID_INF) = INF dir */ + "SetupScratchDir", /* correct ? */ + "INF" + }, + { /* 18 (LDID_HELP) = HELP dir */ + NULL, /* ??? */ + "HELP" + }, + { /* 19 (LDID_WINADMIN) = Admin dir */ + "WinAdminDir", + "" + }, + { /* 20 (LDID_FONTS) = Fonts dir */ + NULL, /* ??? */ + "FONTS" + }, + { /* 21 (LDID_VIEWERS) = Viewers */ + NULL, /* ??? */ + "SYSTEM\\VIEWERS" + }, + { /* 22 (LDID_VMM32) = VMM32 dir */ + NULL, /* ??? */ + "SYSTEM\\VMM32" + }, + { /* 23 (LDID_COLOR) = ICM dir */ + "ICMPath", + "SYSTEM\\COLOR" + }, + { /* 24 (LDID_APPS) = root of boot drive ? */ + "AppsDir", + "C:\\" + }, + { /* 25 (LDID_SHARED) = shared dir */ + "SharedDir", + "" + }, + { /* 26 (LDID_WINBOOT) = Windows boot dir */ + "WinBootDir", + "" + }, + { /* 27 (LDID_MACHINE) = machine specific files */ + "MachineDir", + NULL + }, + { /* 28 (LDID_HOST_WINBOOT) = Host Windows boot dir */ + "HostWinBootDir", + NULL + }, + { /* 29 -- not defined */ + NULL, + NULL + }, + { /* 30 (LDID_BOOT) = Root of boot drive */ + "BootDir", + NULL + }, + { /* 31 (LDID_BOOT_HOST) = Root of boot drive host */ + "BootHost", + NULL + }, + { /* 32 (LDID_OLD_WINBOOT) = subdir of root */ + "OldWinBootDir", + NULL + }, + { /* 33 (LDID_OLD_WIN) = old win dir */ + "OldWinDir", + NULL + } + /* the rest (34-38) isn't too interesting, so I'll forget about it */ +}; + +/* + * LDD == Logical Device Descriptor + * LDID == Logical Device ID + * + * The whole LDD/LDID business might go into a separate file named + * ldd.c. + * At the moment I don't know what the hell these functions are really doing. + * That's why I added reporting stubs. + * The only thing I do know is that I need them for the LDD/LDID infrastructure. + * That's why I implemented them in a way that's suitable for my purpose. + */ +static LDD_LIST *pFirstLDD = NULL; + +static BOOL std_LDDs_done = FALSE; + +void SETUPX_CreateStandardLDDs(void) +{ + HKEY hKey = 0; + WORD n; + DWORD type, len; + LOGDISKDESC_S ldd; + char buffer[MAX_PATH]; + + /* has to be here, otherwise loop */ + std_LDDs_done = TRUE; + + RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", &hKey); + + for (n=0; n < sizeof(LDID_Data)/sizeof(LDID_DATA); n++) + { + buffer[0] = '\0'; + + len = MAX_PATH; + if ( (hKey) && (LDID_Data[n].RegValName) + && (RegQueryValueExA(hKey, LDID_Data[n].RegValName, + NULL, &type, buffer, &len) == ERROR_SUCCESS) + && (type == REG_SZ) ) + { + TRACE("found value '%s' for LDID %d\n", buffer, n); + } + else + switch(n) + { + case LDID_SRCPATH: + FIXME("LDID_SRCPATH: what exactly do we have to do here ?\n"); + strcpy(buffer, "X:\\FIXME"); + break; + case LDID_SYS: + GetSystemDirectoryA(buffer, MAX_PATH); + break; + case LDID_APPS: + case LDID_MACHINE: + case LDID_HOST_WINBOOT: + case LDID_BOOT: + case LDID_BOOT_HOST: + strcpy(buffer, "C:\\"); + break; + default: + if (LDID_Data[n].StdString) + { + DWORD len = GetWindowsDirectoryA(buffer, MAX_PATH); + LPSTR p; + p = buffer + len; + *p++ = '\\'; + strcpy(p, LDID_Data[n].StdString); + } + break; + } + if (buffer[0]) + { + INIT_LDD(ldd, n); + ldd.pszPath = buffer; + TRACE("LDID %d -> '%s'\n", ldd.ldid, ldd.pszPath); + CtlSetLdd16(&ldd); + } + } + if (hKey) RegCloseKey(hKey); +} + +/*********************************************************************** + * CtlDelLdd (SETUPX.37) + * + * RETURN + * ERR_VCP_LDDINVALID if ldid < LDID_ASSIGN_START. + */ +RETERR16 SETUPX_DelLdd(LOGDISKID16 ldid) +{ + LDD_LIST *pCurr, *pPrev = NULL; + + TRACE("(%d)\n", ldid); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (ldid < LDID_ASSIGN_START) + return ERR_VCP_LDDINVALID; + + pCurr = pFirstLDD; + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if ( (pCurr == NULL) /* hit end of list */ + || (ldid != pCurr->pldd->ldid) ) + return ERR_VCP_LDDFIND; /* correct ? */ + + /* ok, found our victim: eliminate it */ + + if (pPrev) + pPrev->next = pCurr->next; + + if (pCurr == pFirstLDD) + pFirstLDD = NULL; + HeapFree(GetProcessHeap(), 0, pCurr); + + return OK; +} + +/*********************************************************************** + * CtlDelLdd (SETUPX.37) + */ +RETERR16 WINAPI CtlDelLdd16(LOGDISKID16 ldid) +{ + FIXME("(%d); - please report this!\n", ldid); + return SETUPX_DelLdd(ldid); +} + +/*********************************************************************** + * CtlFindLdd (SETUPX.35) + * + * doesn't check pldd ptr validity: crash (W98SE) + * + * RETURN + * ERR_VCP_LDDINVALID if pldd->cbSize != structsize + * 1 in all other cases ?? + * + */ +RETERR16 WINAPI CtlFindLdd16(LPLOGDISKDESC pldd) +{ + LDD_LIST *pCurr, *pPrev = NULL; + + TRACE("(%p)\n", pldd); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; + + pCurr = pFirstLDD; + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if ( (pCurr == NULL) /* hit end of list */ + || (pldd->ldid != pCurr->pldd->ldid) ) + return ERR_VCP_LDDFIND; /* correct ? */ + + memcpy(pldd, pCurr->pldd, pldd->cbSize); + /* hmm, we probably ought to strcpy() the string ptrs here */ + + return 1; /* what is this ?? */ +} + +/*********************************************************************** + * CtlSetLdd (SETUPX.33) + * + * Set an LDD entry. + * + * RETURN + * ERR_VCP_LDDINVALID if pldd.cbSize != sizeof(LOGDISKDESC_S) + * + */ +RETERR16 WINAPI CtlSetLdd16(LPLOGDISKDESC pldd) +{ + LDD_LIST *pCurr, *pPrev = NULL; + LPLOGDISKDESC pCurrLDD; + HANDLE heap; + BOOL is_new = FALSE; + + TRACE("(%p)\n", pldd); + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; + + heap = GetProcessHeap(); + pCurr = pFirstLDD; + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if (!pCurr || pldd->ldid != pCurr->pldd->ldid) + { + is_new = TRUE; + pCurr = HeapAlloc(heap, 0, sizeof(LDD_LIST)); + pCurr->pldd = HeapAlloc(heap, 0, sizeof(LOGDISKDESC_S)); + pCurr->next = NULL; + pCurrLDD = pCurr->pldd; + } + else + { + pCurrLDD = pCurr->pldd; + HeapFree(heap, 0, pCurrLDD->pszPath); + HeapFree(heap, 0, pCurrLDD->pszVolLabel); + HeapFree(heap, 0, pCurrLDD->pszDiskName); + } + + memcpy(pCurrLDD, pldd, sizeof(LOGDISKDESC_S)); + + if (pldd->pszPath) + { + pCurrLDD->pszPath = HeapAlloc( heap, 0, strlen(pldd->pszPath)+1 ); + strcpy( pCurrLDD->pszPath, pldd->pszPath ); + } + if (pldd->pszVolLabel) + { + pCurrLDD->pszVolLabel = HeapAlloc( heap, 0, strlen(pldd->pszVolLabel)+1 ); + strcpy( pCurrLDD->pszVolLabel, pldd->pszVolLabel ); + } + if (pldd->pszDiskName) + { + pCurrLDD->pszDiskName = HeapAlloc( heap, 0, strlen(pldd->pszDiskName)+1 ); + strcpy( pCurrLDD->pszDiskName, pldd->pszDiskName ); + } + + if (is_new) /* link into list */ + { + if (pPrev) + { + pCurr->next = pPrev->next; + pPrev->next = pCurr; + } + if (!pFirstLDD) + pFirstLDD = pCurr; + } + + return OK; +} + + +/*********************************************************************** + * CtlAddLdd (SETUPX.36) + * + * doesn't check pldd ptr validity: crash (W98SE) + * + */ +static LOGDISKID16 ldid_to_add = LDID_ASSIGN_START; +RETERR16 WINAPI CtlAddLdd16(LPLOGDISKDESC pldd) +{ + pldd->ldid = ldid_to_add++; + return CtlSetLdd16(pldd); +} + +/*********************************************************************** + * CtlGetLdd (SETUPX.34) + * + * doesn't check pldd ptr validity: crash (W98SE) + * What the !@#$%&*( is the difference between CtlFindLdd() and CtlGetLdd() ?? + * + * RETURN + * ERR_VCP_LDDINVALID if pldd->cbSize != structsize + * + */ +static RETERR16 SETUPX_GetLdd(LPLOGDISKDESC pldd) +{ + LDD_LIST *pCurr, *pPrev = NULL; + + if (!std_LDDs_done) + SETUPX_CreateStandardLDDs(); + + if (pldd->cbSize != sizeof(LOGDISKDESC_S)) + return ERR_VCP_LDDINVALID; + + pCurr = pFirstLDD; + /* search until we find the appropriate LDD or hit the end */ + while ((pCurr != NULL) && (pldd->ldid > pCurr->pldd->ldid)) + { + pPrev = pCurr; + pCurr = pCurr->next; + } + if (pCurr == NULL) /* hit end of list */ + return ERR_VCP_LDDFIND; /* correct ? */ + + memcpy(pldd, pCurr->pldd, pldd->cbSize); + /* hmm, we probably ought to strcpy() the string ptrs here */ + + return OK; +} + +/**********************************************************************/ + +RETERR16 WINAPI CtlGetLdd16(LPLOGDISKDESC pldd) +{ + FIXME("(%p); - please report this!\n", pldd); + return SETUPX_GetLdd(pldd); +} + +/*********************************************************************** + * CtlGetLddPath (SETUPX.38) + * + * Gets the path of an LDD. + * No crash if szPath == NULL. + * szPath has to be at least MAX_PATH_LEN bytes long. + * RETURN + * ERR_VCP_LDDUNINIT if LDD for LDID not found. + */ +RETERR16 WINAPI CtlGetLddPath16(LOGDISKID16 ldid, LPSTR szPath) +{ + TRACE("(%d, %p);\n", ldid, szPath); + + if (szPath) + { + LOGDISKDESC_S ldd; + INIT_LDD(ldd, ldid); + if (CtlFindLdd16(&ldd) == ERR_VCP_LDDFIND) + return ERR_VCP_LDDUNINIT; + SETUPX_GetLdd(&ldd); + strcpy(szPath, ldd.pszPath); + TRACE("ret '%s' for LDID %d\n", szPath, ldid); + } + return OK; +} + +/*********************************************************************** + * CtlSetLddPath (SETUPX.508) + * + * Sets the path of an LDD. + * Creates LDD for LDID if not existing yet. + */ +RETERR16 WINAPI CtlSetLddPath16(LOGDISKID16 ldid, LPSTR szPath) +{ + LOGDISKDESC_S ldd; + TRACE("(%d, '%s');\n", ldid, szPath); + + SetupSetDirectoryIdA( 0, ldid, szPath ); + INIT_LDD(ldd, ldid); + ldd.pszPath = szPath; + return CtlSetLdd16(&ldd); +} diff --git a/reactos/lib/setupapi/stubs.c b/reactos/lib/setupapi/stubs.c new file mode 100644 index 00000000000..f722a0cc20d --- /dev/null +++ b/reactos/lib/setupapi/stubs.c @@ -0,0 +1,176 @@ +/* + * SetupAPI stubs + * + * Copyright 2000 James Hatheway + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "setupapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/*********************************************************************** + * TPWriteProfileString (SETUPX.62) + */ +BOOL WINAPI TPWriteProfileString16( LPCSTR section, LPCSTR entry, LPCSTR string ) +{ + FIXME( "%s %s %s: stub\n", debugstr_a(section), debugstr_a(entry), debugstr_a(string) ); + return TRUE; +} + + +/*********************************************************************** + * suErrorToIds (SETUPX.61) + */ +DWORD WINAPI suErrorToIds16( WORD w1, WORD w2 ) +{ + FIXME( "%x %x: stub\n", w1, w2 ); + return 0; +} + +/*********************************************************************** + * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, PSP_DEVINFO_LIST_DETAIL_DATA_A devinfo_data ) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, PSP_DEVINFO_LIST_DETAIL_DATA_W devinfo_data ) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * (SETUPAPI.@) + * + * NO WINAPI in description given + */ +HDEVINFO WINAPI SetupDiGetClassDevsExA(const GUID *class, PCSTR filter, HWND parent, DWORD flags, HDEVINFO deviceset, PCSTR machine, PVOID reserved) +{ + FIXME("filter %s machine %s\n",debugstr_a(filter),debugstr_a(machine)); + return FALSE; +} + +/*********************************************************************** + * (SETUPAPI.@) + * + * NO WINAPI in description given + */ +HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR filter, HWND parent, DWORD flags, HDEVINFO deviceset, PCWSTR machine, PVOID reserved) +{ + FIXME("\n"); + return FALSE; +} + +/*********************************************************************** + * CM_Connect_MachineW (SETUPAPI.@) + */ +DWORD WINAPI CM_Connect_MachineW(LPCWSTR name, void * machine) +{ +#define CR_SUCCESS 0x00000000 +#define CR_ACCESS_DENIED 0x00000033 + FIXME("\n"); + return CR_ACCESS_DENIED; +} + +/*********************************************************************** + * CM_Disconnect_Machine (SETUPAPI.@) + */ +DWORD WINAPI CM_Disconnect_Machine(DWORD handle) +{ + FIXME("\n"); + return CR_SUCCESS; + +} + +/*********************************************************************** + * CM_Get_Device_ID_ListA (SETUPAPI.@) + */ + +DWORD WINAPI CM_Get_Device_ID_ListA( + PCSTR pszFilter, PCHAR Buffer, ULONG BufferLen, ULONG ulFlags ) +{ + FIXME("%p %p %ld %ld\n", pszFilter, Buffer, BufferLen, ulFlags ); + memset(Buffer,0,2); + return CR_SUCCESS; +} + + +/*********************************************************************** + * SetupCopyOEMInfA (SETUPAPI.@) + */ +BOOL WINAPI SetupCopyOEMInfA(PCSTR sourceinffile, PCSTR sourcemedialoc, + DWORD mediatype, DWORD copystyle, PSTR destinfname, + DWORD destnamesize, PDWORD required, + PSTR *destinfnamecomponent) +{ + FIXME("stub: source %s location %s...\n",sourceinffile, sourcemedialoc); + return FALSE; +} + +/*********************************************************************** + * SetupGetInfInformationA (SETUPAPI.@) + */ +BOOL WINAPI SetupGetInfInformationA( LPCVOID InfSpec, DWORD SearchControl, + PSP_INF_INFORMATION ReturnBuffer, + DWORD ReturnBufferSize, PDWORD RequiredSize) +{ + FIXME("(%p, %ld, %p, %ld, %p) Stub!\n", + InfSpec, SearchControl, ReturnBuffer, ReturnBufferSize, RequiredSize ); + return TRUE; +} + +/*********************************************************************** + * SetupInitializeFileLogW(SETUPAPI.@) + */ +HANDLE WINAPI SetupInitializeFileLogW(LPWSTR LogFileName, DWORD Flags) +{ + FIXME("Stub %s, 0x%lx\n",debugstr_w(LogFileName),Flags); + return INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupInitializeFileLogA(SETUPAPI.@) + */ +HANDLE WINAPI SetupInitializeFileLogA(LPSTR LogFileName, DWORD Flags) +{ + FIXME("Stub %s, 0x%lx\n",debugstr_a(LogFileName),Flags); + return INVALID_HANDLE_VALUE; +} + +/*********************************************************************** + * SetupTerminateFileLog(SETUPAPI.@) + */ +BOOL WINAPI SetupTerminateFileLog(HANDLE FileLogHandle) +{ + FIXME ("Stub %p\n",FileLogHandle); + return TRUE; +} diff --git a/reactos/lib/setupapi/virtcopy.c b/reactos/lib/setupapi/virtcopy.c new file mode 100644 index 00000000000..8ffbfdddc85 --- /dev/null +++ b/reactos/lib/setupapi/virtcopy.c @@ -0,0 +1,789 @@ +/* + * SetupAPI virtual copy operations + * + * Copyright 2001 Andreas Mohr + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: we now rely on builtin setupapi.dll for dialog resources. + * This is bad ! We ought to have 16bit resource handling working. + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "wownt32.h" +#include "wingdi.h" +#include "winnls.h" +#include "setupapi.h" +#include "setupx16.h" +#include "setupapi_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +static FARPROC16 VCP_Proc = NULL; +static LPARAM VCP_MsgRef = 0; + +static BOOL VCP_opened = FALSE; + +static VCPSTATUS vcp_status; + +static HINSTANCE SETUPAPI_hInstance; + +static WORD VCP_Callback( LPVOID obj, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LPARAM lParamRef ) +{ + WORD args[8]; + DWORD ret = OK; + if (VCP_Proc) + { + args[7] = HIWORD(obj); + args[6] = LOWORD(obj); + args[5] = msg; + args[4] = wParam; + args[3] = HIWORD(lParam); + args[2] = LOWORD(lParam); + args[1] = HIWORD(lParamRef); + args[0] = LOWORD(lParamRef); + WOWCallback16Ex( (DWORD)VCP_Proc, WCB16_PASCAL, sizeof(args), args, &ret ); + } + return (WORD)ret; +} + +/****************************** VHSTR management ******************************/ + +/* + * This is a totally braindead implementation for now; + * I don't care about speed at all ! Size and implementation time + * is much more important IMHO. I could have created some sophisticated + * tree structure, but... what the hell ! :-) + */ +typedef struct { + DWORD refcount; + LPCSTR pStr; +} VHSTR_STRUCT; + +static VHSTR_STRUCT **vhstrlist = NULL; +static VHSTR vhstr_alloc = 0; + +#define VALID_VHSTR(x) ((x < vhstr_alloc) && (vhstrlist[x]) && (vhstrlist[x]->refcount)) + +/*********************************************************************** + * vsmStringAdd (SETUPX.207) + */ +VHSTR WINAPI vsmStringAdd16(LPCSTR lpszName) +{ + VHSTR n; + VHSTR index = 0xffff; + HANDLE heap; + + TRACE("add string '%s'\n", lpszName); + /* search whether string already inserted */ + TRACE("searching for existing string...\n"); + for (n = 0; n < vhstr_alloc; n++) + { + if ((vhstrlist[n]) && (vhstrlist[n]->refcount)) + { + TRACE("checking item: %d\n", n); + if (!strcmp(vhstrlist[n]->pStr, lpszName)) + { + TRACE("found\n"); + vhstrlist[n]->refcount++; + return n; + } + } + } + + /* hmm, not found yet, let's insert it */ + TRACE("inserting item\n"); + for (n = 0; n < vhstr_alloc; n++) + { + if ((!(vhstrlist[n])) || (!(vhstrlist[n]->refcount))) + { + index = n; + break; + } + } + heap = GetProcessHeap(); + if (n == vhstr_alloc) /* hmm, no free index found yet */ + { + index = vhstr_alloc; + vhstr_alloc += 20; + + if (vhstrlist) + vhstrlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, vhstrlist, + sizeof(VHSTR_STRUCT *) * vhstr_alloc); + else + vhstrlist = HeapAlloc(heap, HEAP_ZERO_MEMORY, + sizeof(VHSTR_STRUCT *) * vhstr_alloc); + } + if (index == 0xffff) + return 0xffff; /* failure */ + if (!vhstrlist[index]) + vhstrlist[index] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VHSTR_STRUCT)); + vhstrlist[index]->refcount = 1; + vhstrlist[index]->pStr = HeapAlloc(heap, 0, strlen(lpszName)+1); + strcpy((LPSTR)vhstrlist[index]->pStr, lpszName); + return index; +} + +/*********************************************************************** + * vsmStringDelete (SETUPX.206) + */ +INT16 WINAPI vsmStringDelete16(VHSTR vhstr) +{ + if (VALID_VHSTR(vhstr)) + { + vhstrlist[vhstr]->refcount--; + if (!vhstrlist[vhstr]->refcount) + { + HeapFree(GetProcessHeap(), 0, (LPSTR)vhstrlist[vhstr]->pStr); + vhstrlist[vhstr]->pStr = NULL; + } + return VCPN_OK; + } + + /* string not found */ + return VCPN_FAIL; +} + +/* + * vsmStringFind() - not exported from a standard SETUPX.DLL, it seems + */ +VHSTR WINAPI vsmStringFind16(LPCSTR lpszName) +{ + WORD n; + for (n = 0; n < vhstr_alloc; n++) + if ((vhstrlist[n]) && (vhstrlist[n]->refcount) && (!strcmp(vhstrlist[n]->pStr, lpszName))) + return n; + return 0xffff; +} + +/*********************************************************************** + * vsmGetStringName (SETUPX.205) + * + * Pretty correct, I guess + */ +INT16 WINAPI vsmGetStringName16(VHSTR vhstr, LPSTR lpszBuffer, int cbBuffer) +{ + if (VALID_VHSTR(vhstr)) + { + int len = strlen(vhstrlist[vhstr]->pStr)+1; + if (cbBuffer >= len) + { + if (lpszBuffer) + strcpy(lpszBuffer, vhstrlist[vhstr]->pStr); + return len; + } + } + return VCPN_FAIL; +} + +/*********************************************************************** + * vsmStringCompare (not exported from a standard SETUPX.DLL, it seems) + */ +INT16 WINAPI vsmStringCompare16(VHSTR vhstrA, VHSTR vhstrB) +{ + if ((!VALID_VHSTR(vhstrA)) || (!VALID_VHSTR(vhstrB))) + return VCPN_FAIL; /* correct ? */ + return strcmp(vhstrlist[vhstrA]->pStr, vhstrlist[vhstrB]->pStr); +} + +/*********************************************************************** + * vsmGetStringRawName (SETUPX.208) + */ +LPCSTR WINAPI vsmGetStringRawName16(VHSTR vhstr) +{ + return (VALID_VHSTR(vhstr)) ? vhstrlist[vhstr]->pStr : NULL; +} + + +/***************************** VIRTNODE management ****************************/ +static LPVIRTNODE *pvnlist = NULL; +static DWORD vn_num = 0; +static DWORD vn_last = 0; + +RETERR16 VCP_VirtnodeCreate(LPVCPFILESPEC vfsSrc, LPVCPFILESPEC vfsDst, WORD fl, LPARAM lParam, LPEXPANDVTBL lpExpandVtbl) +{ + HANDLE heap; + LPVIRTNODE lpvn; + RETERR16 cbres; + + while (vn_last < vn_num) + { + if (pvnlist[vn_last] == NULL) + break; + vn_last++; + } + heap = GetProcessHeap(); + if (vn_last == vn_num) + { + vn_num += 20; + if (pvnlist) + pvnlist = HeapReAlloc(heap, HEAP_ZERO_MEMORY, pvnlist, + sizeof(LPVIRTNODE *) * vn_num); + else + pvnlist = HeapAlloc(heap, HEAP_ZERO_MEMORY, + sizeof(LPVIRTNODE *) * vn_num); + } + pvnlist[vn_last] = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(VIRTNODE)); + lpvn = pvnlist[vn_last]; + vn_last++; + + lpvn->cbSize = sizeof(VIRTNODE); + + if (vfsSrc) + memcpy(&lpvn->vfsSrc, vfsSrc, sizeof(VCPFILESPEC)); + + if (vfsDst) + memcpy(&lpvn->vfsDst, vfsDst, sizeof(VCPFILESPEC)); + + lpvn->fl = fl; + lpvn->lParam = lParam; + lpvn->lpExpandVtbl = lpExpandVtbl; + + lpvn->vhstrDstFinalName = 0xffff; /* FIXME: what is this ? */ + + cbres = VCP_Callback(lpvn, VCPM_NODECREATE, 0, 0, VCP_MsgRef); + lpvn->fl |= VFNL_CREATED; + cbres = VCP_Callback(lpvn, VCPM_NODEACCEPT, 0, 0, VCP_MsgRef); + + return OK; +} + +BOOL VCP_VirtnodeDelete(LPVIRTNODE lpvnDel) +{ + DWORD n; + RETERR16 cbres; + + for (n = 0; n < vn_last; n++) + { + if (pvnlist[n] == lpvnDel) + { + cbres = VCP_Callback(lpvnDel, VCPM_NODEDESTROY, 0, 0, VCP_MsgRef); + HeapFree(GetProcessHeap(), 0, lpvnDel); + pvnlist[n] = NULL; + return TRUE; + } + } + return FALSE; +} + +/*********************************************************************** + * VcpOpen (SETUPX.200) + * + * Sets up a virtual copy operation. + * This means that functions such as GenInstall() + * create a VIRTNODE struct for every file to be touched in a .INF file + * instead of actually touching the file. + * The actual copy/move/rename gets started when VcpClose or + * VcpFlush is called; several different callbacks are made + * (copy, rename, open, close, version conflicts, ...) on every file copied. + */ +RETERR16 WINAPI VcpOpen16(VIFPROC vifproc, LPARAM lparamMsgRef) +{ + TRACE("(%p, %08lx)\n", vifproc, lparamMsgRef); + if (VCP_opened) + return ERR_VCP_BUSY; + + VCP_Proc = (FARPROC16)vifproc; + VCP_MsgRef = lparamMsgRef; + + /* load SETUPAPI needed for dialog resources etc. */ + SETUPAPI_hInstance = LoadLibraryA("setupapi.dll"); + if (!SETUPAPI_hInstance) + { + ERR("Could not load sibling setupapi.dll\n"); + return ERR_VCP_NOMEM; + } + VCP_opened = TRUE; + return OK; +} + +/*********************************************************************** + * VcpQueueCopy [SETUPX.13] + * + * lpExpandVtbl seems to be deprecated. + * fl are the CNFL_xxx and VNFL_xxx flags. + * lParam are the VNLP_xxx flags. + */ +RETERR16 WINAPI VcpQueueCopy16( + LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName, + LPCSTR lpszSrcDir, LPCSTR lpszDstDir, + LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst, + LPEXPANDVTBL lpExpandVtbl, + WORD fl, LPARAM lParam +) +{ + VCPFILESPEC vfsSrc, vfsDst; + + if (!VCP_opened) + return ERR_VCP_NOTOPEN; + + TRACE("srcdir: %s, srcfile: %s, dstdir: %s, dstfile: %s\n", + lpszSrcDir, lpszSrcFileName, lpszDstDir, lpszDstFileName); + + TRACE("ldidSrc == %d, ldidDst == %d\n", ldidSrc, ldidDst); + + vfsSrc.ldid = ldidSrc; + vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir); + vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName); + + vfsDst.ldid = ldidDst; + vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir); + vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName); + + return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, fl, lParam, + lpExpandVtbl); +} + +/*********************************************************************** + * VcpQueueDelete [SETUPX.17] + * + * Is lParamRef the same as lParam in VcpQueueCopy ? + * Damn docu !! Err... which docu ? + */ +RETERR16 WINAPI VcpQueueDelete16( + LPCSTR lpszDstFileName, + LPCSTR lpszDstDir, + LOGDISKID16 ldidDst, + LPARAM lParamRef +) +{ + VCPFILESPEC vfsDst; + + if (!VCP_opened) + return ERR_VCP_NOTOPEN; + + vfsDst.ldid = ldidDst; + vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir); + vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName); + + return VCP_VirtnodeCreate(NULL, &vfsDst, VNFL_DELETE, lParamRef, 0); +} + +/*********************************************************************** + * VcpQueueRename [SETUPX.204] + * + */ +RETERR16 WINAPI VcpQueueRename16( + LPCSTR lpszSrcFileName, LPCSTR lpszDstFileName, + LPCSTR lpszSrcDir, LPCSTR lpszDstDir, + LOGDISKID16 ldidSrc, LOGDISKID16 ldidDst, + LPARAM lParam +) +{ + VCPFILESPEC vfsSrc, vfsDst; + + if (!VCP_opened) + return ERR_VCP_NOTOPEN; + + vfsSrc.ldid = ldidSrc; + vfsSrc.vhstrDir = vsmStringAdd16(lpszSrcDir); + vfsSrc.vhstrFileName = vsmStringAdd16(lpszSrcFileName); + + vfsDst.ldid = ldidDst; + vfsDst.vhstrDir = vsmStringAdd16(lpszDstDir); + vfsDst.vhstrFileName = vsmStringAdd16(lpszDstFileName); + + return VCP_VirtnodeCreate(&vfsSrc, &vfsDst, VNFL_RENAME, lParam, + 0); +} + +/*********************************************************************** + * VcpEnumFiles (SETUPX.@) + */ +INT16 WINAPI VcpEnumFiles(VCPENUMPROC vep, LPARAM lParamRef) +{ + WORD n; + + for (n = 0; n < vn_last; n++) + vep(pvnlist[n], lParamRef); + + return 0; /* FIXME: return value ? */ +} + +/*********************************************************************** + * VcpExplain (SETUPX.411) + */ +LPCSTR WINAPI VcpExplain16(LPVIRTNODE lpVn, DWORD dwWhat) +{ + static char buffer[MAX_PATH]; /* FIXME: is this how it's done ? */ + buffer[0] = '\0'; + switch (dwWhat) + { + case VCPEX_SRC_FULL: + case VCPEX_DST_FULL: + { + LPVCPFILESPEC lpvfs = + (dwWhat == VCPEX_SRC_FULL) ? &lpVn->vfsSrc : &lpVn->vfsDst; + + /* if we have an ldid, use it, otherwise use the string */ + /* from the vhstrlist array */ + if (lpvfs->ldid != 0xffff) + CtlGetLddPath16(lpvfs->ldid, buffer); + else + strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrDir)); + + strcat(buffer, "\\"); + strcat(buffer, vsmGetStringRawName16(lpvfs->vhstrFileName)); + } + break; + default: + FIXME("%ld unimplemented !\n", dwWhat); + strcpy(buffer, "Unknown error"); + break; + } + return buffer; +} + +RETERR16 VCP_CheckPaths(void) +{ + DWORD n; + LPVIRTNODE lpvn; + RETERR16 cbres; + + cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKSTART, 0, 0, VCP_MsgRef); + for (n = 0; n < vn_num; n++) + { + lpvn = pvnlist[n]; + if (!lpvn) continue; + /* FIXME: check paths of all VIRTNODEs here ! */ + cbres = VCP_Callback(&lpvn->vfsDst, VCPM_CHECKPATH, 0, (DWORD)lpvn, VCP_MsgRef); + } + cbres = VCP_Callback(&vcp_status, VCPM_VSTATPATHCHECKEND, 0, 0, VCP_MsgRef); + return OK; +} + +RETERR16 VCP_CopyFiles(void) +{ + char fn_src[MAX_PATH], fn_dst[MAX_PATH]; + RETERR16 res = OK, cbres; + DWORD n; + LPVIRTNODE lpvn; + + cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYSTART, 0, 0, VCP_MsgRef); + for (n = 0; n < vn_num; n++) + { + lpvn = pvnlist[n]; + if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_COPY)) continue; + /* FIXME: need to send VCPM_VSTATNEWDISK notification sometimes */ + strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL)); + strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL)); + /* FIXME: what is this VCPM_VSTATWRITE here for ? + * I guess it's to signal successful destination file creation */ + cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef); + + /* FIXME: need to do the file copy in small chunks for notifications */ + TRACE("copying '%s' to '%s'\n", fn_src, fn_dst); + /* perform the file copy */ + if (!(CopyFileA(fn_src, fn_dst, + (lpvn->fl & VNLP_COPYIFEXISTS) ? FALSE : TRUE ))) + { + ERR("error copying, src: %s -> dst: %s\n", fn_src, fn_dst); + res = ERR_VCP_IOFAIL; + } + + vcp_status.prgFileRead.dwSoFar++; + cbres = VCP_Callback(&vcp_status, VCPM_VSTATREAD, 0, 0, VCP_MsgRef); + vcp_status.prgFileWrite.dwSoFar++; + cbres = VCP_Callback(&vcp_status, VCPM_VSTATWRITE, 0, 0, VCP_MsgRef); + } + + cbres = VCP_Callback(&vcp_status, VCPM_VSTATCOPYEND, 0, 0, VCP_MsgRef); + return res; +} + +/*********************************************************************** + * VcpFlush - internal (not exported), but documented + * + * VNFL_NOW is used for VcpFlush. + */ +RETERR16 VcpFlush16(WORD fl, LPCSTR lpszBackupDest) +{ + return OK; +} + +/*********************************************************************** + * VcpClose (SETUPX.201) + * + * Does callbacks (-> vifproc) with VCPM_VSTATCLOSESTART, + * VCPM_VSTATCLOSEEND. + * + * fl gets VCPFL_xxx flags to indicate what to do with the + * VIRTNODEs (files to mess with) created by e.g. GenInstall() + */ +RETERR16 WINAPI VcpClose16(WORD fl, LPCSTR lpszBackupDest) +{ + RETERR16 res = OK; + WORD cbres = VCPN_PROCEED; + + TRACE("(%04x, '%s')\n", fl, lpszBackupDest); + + /* FIXME: needs to sort virtnodes in case VCPFL_INSPECIFIEDORDER + * is not set. This is done by VCP_Callback(VCPM_NODECOMPARE) */ + + TRACE("#1\n"); + memset(&vcp_status, 0, sizeof(VCPSTATUS)); + /* yes, vcp_status.cbSize is 0 ! */ + TRACE("#2\n"); + cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSESTART, 0, 0, VCP_MsgRef); + TRACE("#3\n"); + + res = VCP_CheckPaths(); + TRACE("#4\n"); + if (res != OK) + return res; /* is this ok ? */ + VCP_CopyFiles(); + + TRACE("#5\n"); + cbres = VCP_Callback(&vcp_status, VCPM_VSTATCLOSEEND, 0, 0, VCP_MsgRef); + TRACE("#6\n"); + VCP_Proc = NULL; + FreeLibrary(SETUPAPI_hInstance); + VCP_opened = FALSE; + return OK; +} + +RETERR16 VCP_RenameFiles(void) +{ + char fn_src[MAX_PATH], fn_dst[MAX_PATH]; + RETERR16 res = OK, cbres; + DWORD n; + LPVIRTNODE lpvn; + + cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMESTART, 0, 0, VCP_MsgRef); + for (n = 0; n < vn_num; n++) + { + lpvn = pvnlist[n]; + if ((!lpvn) || ((lpvn->fl & VNFL_NODE_TYPE) != VNFL_RENAME)) continue; + strcpy(fn_src, VcpExplain16(lpvn, VCPEX_SRC_FULL)); + strcpy(fn_dst, VcpExplain16(lpvn, VCPEX_DST_FULL)); + cbres = VCP_Callback(&lpvn->vfsDst, VCPM_FILEOPENOUT, 0, (LPARAM)lpvn, VCP_MsgRef); + if (!(MoveFileExA(fn_src, fn_dst, MOVEFILE_REPLACE_EXISTING))) + res = ERR_VCP_IOFAIL; + else + VCP_VirtnodeDelete(lpvn); + } + cbres = VCP_Callback(&vcp_status, VCPM_VSTATRENAMEEND, 0, 0, VCP_MsgRef); + return res; +} + +/*********************************************************************** + * vcpDefCallbackProc (SETUPX.202) + */ +RETERR16 WINAPI vcpDefCallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam, + LPARAM lParam, LPARAM lParamRef) +{ + static int count = 0; + if (count < 10) + FIXME("(%p, %04x, %04x, %08lx, %08lx) - what to do here ?\n", + lpvObj, uMsg, wParam, lParam, lParamRef); + count++; + return OK; +} + +/********************* point-and-click stuff from here ***********************/ + +static HWND hDlgCopy = 0; +static HKEY hKeyFiles = 0, hKeyRename = 0, hKeyConflict = 0; +static char BackupDir[12]; + +static INT_PTR CALLBACK VCP_UI_FileCopyDlgProc(HWND hWndDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + INT_PTR retval = FALSE; + + if (iMsg == WM_INITDIALOG) + { + ShowWindow(hWndDlg, SW_SHOWNORMAL); + UpdateWindow(hWndDlg); + retval = TRUE; + } + return retval; +} + +BOOL VCP_UI_GetDialogTemplate(LPCVOID *template32) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + + if (!(hResInfo = FindResourceA(SETUPAPI_hInstance, MAKEINTRESOURCEA(COPYFILEDLGORD), (LPSTR)RT_DIALOG))) + return FALSE; + if (!(hDlgTmpl32 = LoadResource(SETUPAPI_hInstance, hResInfo )) || + !(*template32 = LockResource( hDlgTmpl32 ))) + return FALSE; + return TRUE; +} + +static LRESULT WINAPI +VCP_UI_FileCopyWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg != WM_CREATE) + return DefWindowProcA (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + return 0; + default: + FIXME("%04x: unhandled.\n", uMsg); + } + + return 0; +} + +void VCP_UI_RegisterProgressClass(void) +{ + static BOOL registered = FALSE; + WNDCLASSA wndClass; + + if (registered) + return; + + registered = TRUE; + ZeroMemory (&wndClass, sizeof(WNDCLASSA)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndClass.lpfnWndProc = VCP_UI_FileCopyWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW); + wndClass.hbrBackground = NULL; + wndClass.lpszClassName = "setupx_progress"; + + RegisterClassA (&wndClass); +} + +RETERR16 VCP_UI_NodeCompare(LPVIRTNODE vn1, LPVIRTNODE vn2) +{ + LPCSTR file1, file2; + file1 = vsmGetStringRawName16(vn1->vfsSrc.vhstrFileName); + file2 = vsmGetStringRawName16(vn2->vfsSrc.vhstrFileName); + return (RETERR16)strcmp(file1, file2); +} + +RETERR16 VCP_UI_CopyStart(void) +{ + LPCVOID template32; + char buf[256]; /* plenty */ + BOOL dirty; + DWORD len; + + /* FIXME: should be registered at DLL startup instead */ + VCP_UI_RegisterProgressClass(); + if (!(VCP_UI_GetDialogTemplate(&template32))) + return VCPN_FAIL; + + if (vn_num > 10) /* hack */ + { + hDlgCopy = CreateDialogIndirectParamA(SETUPAPI_hInstance, template32, 0, + VCP_UI_FileCopyDlgProc, 0); + if (!hDlgCopy) + return VCPN_FAIL; + SetDlgItemTextA(hDlgCopy, SOURCESTRORD, "Scanning ..."); + SetDlgItemTextA(hDlgCopy, DESTSTRORD, "NOT_IMPLEMENTED_YET"); + } + strcpy(buf, REG_INSTALLEDFILES); + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyFiles)) + return VCPN_FAIL; + strcat(buf, REGPART_RENAME); + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, buf, &hKeyRename)) + return VCPN_FAIL; + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT, &hKeyConflict)) + return VCPN_FAIL; + len = 1; + if (!(RegQueryValueExA(hKeyConflict, "Dirty", NULL, 0, (LPBYTE)&dirty, &len))) + { + /* FIXME: what does SETUPX.DLL do in this case ? */ + MESSAGE("Warning: another program using SETUPX is already running ! Failed.\n"); + return VCPN_FAIL; + } + dirty = TRUE; + if (RegSetValueExA(hKeyConflict, "Dirty", 0, REG_BINARY, (LPBYTE)&dirty, 1)) + return VCPN_FAIL; + len = 12; + if (!(RegQueryValueExA(hKeyConflict, "BackupDirectory", NULL, 0, BackupDir, &len))) + strcpy(BackupDir, "VCM"); + + /* create C:\WINDOWS\[BackupDir] and set registry key to it */ + GetWindowsDirectoryA(buf, 256); + strcat(buf, "\\"); + strcat(buf, BackupDir); + if (!(CreateDirectoryA(buf, NULL))) + return VCPN_FAIL; + if (RegSetValueExA(hKeyConflict, "BackupDirectory", 0, REG_SZ, (LPBYTE)buf, strlen(buf)+1)) + return VCPN_FAIL; + RegCloseKey(hKeyConflict); + + return VCPN_OK; +} + +/*********************************************************************** + * vcpUICallbackProc (SETUPX.213) + */ +RETERR16 WINAPI vcpUICallbackProc16(LPVOID lpvObj, UINT16 uMsg, WPARAM wParam, + LPARAM lParam, LPARAM lParamRef) +{ + static int count = 0; + RETERR16 res = VCPN_OK, cbres; + + if (count < 5) + FIXME("(%p, %04x, %04x, %08lx, %08lx) - semi-stub\n", + lpvObj, uMsg, wParam, lParam, lParamRef); + count++; + switch (uMsg) + { + /* unused messages, it seems */ + case VCPM_DISKPREPINFO: + + case VCPM_FILENEEDED: + + case VCPM_NODECREATE: + case VCPM_NODEACCEPT: + + case VCPM_VSTATCLOSESTART: + case VCPM_VSTATPATHCHECKSTART: + case VCPM_VSTATPATHCHECKEND: + + case VCPM_CHECKPATH: + break; + + /* the real stuff */ + case VCPM_NODECOMPARE: + res = VCP_UI_NodeCompare((LPVIRTNODE)lpvObj, (LPVIRTNODE)lParam); + break; + case VCPM_VSTATREAD: + break; + case VCPM_VSTATWRITE: + cbres = VCP_Callback(&vcp_status, VCPM_DISKPREPINFO, 0, 0, VCP_MsgRef); + break; + case VCPM_VSTATCLOSEEND: + RegCloseKey(hKeyFiles); + RegCloseKey(hKeyRename); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, REG_VERSIONCONFLICT); + break; + case VCPM_VSTATCOPYSTART: + res = VCP_UI_CopyStart(); + break; + case VCPM_VSTATCOPYEND: + if (hDlgCopy) DestroyWindow(hDlgCopy); + break; + default: + FIXME("unhandled msg 0x%04x\n", uMsg); + } + return res; +}