winex11.drv: Support multiple adapter display settings in registry.
[wine.git] / dlls / version / version.c
blob5cb4fcd0457855ef05767ea4c26cfe5ddf550ff3
1 /*
2 * Implementation of VERSION.DLL
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 * Copyright 1999 Ulrich Weigand
7 * Copyright 2005 Paul Vriens
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
30 #include <sys/types.h>
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winver.h"
37 #include "winnls.h"
38 #include "lzexpand.h"
39 #include "winerror.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ver);
44 static LPBYTE
45 _fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) {
46 DWORD alloclen;
47 LPBYTE buf;
48 DWORD ret;
50 alloclen = 1000;
51 buf=HeapAlloc(GetProcessHeap(), 0, alloclen);
52 if(buf == NULL) {
53 WARN("Memory exhausted while fetching version info!\n");
54 return NULL;
56 while (1) {
57 ret = GetFileVersionInfoA(fn,0,alloclen,buf);
58 if (!ret) {
59 HeapFree(GetProcessHeap(), 0, buf);
60 return NULL;
62 if (alloclen<*(WORD*)buf) {
63 alloclen = *(WORD*)buf;
64 HeapFree(GetProcessHeap(), 0, buf);
65 buf = HeapAlloc(GetProcessHeap(), 0, alloclen);
66 if(buf == NULL) {
67 WARN("Memory exhausted while fetching version info!\n");
68 return NULL;
70 } else {
71 *vffi = (VS_FIXEDFILEINFO*)(buf+0x14);
72 if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */
73 *vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
74 if ((*vffi)->dwSignature != VS_FFI_SIGNATURE)
75 WARN("Bad VS_FIXEDFILEINFO signature 0x%08x\n",(*vffi)->dwSignature);
76 return buf;
81 static DWORD
82 _error2vif(DWORD error) {
83 switch (error) {
84 case ERROR_ACCESS_DENIED:
85 return VIF_ACCESSVIOLATION;
86 case ERROR_SHARING_VIOLATION:
87 return VIF_SHARINGVIOLATION;
88 default:
89 return 0;
94 /******************************************************************************
95 * VerInstallFileA [VERSION.@]
97 DWORD WINAPI VerInstallFileA(
98 DWORD flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
99 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,PUINT tmpfilelen )
101 LPCSTR pdest;
102 char destfn[260],tmpfn[260],srcfn[260];
103 HFILE hfsrc,hfdst;
104 DWORD attr,xret,tmplast;
105 LONG ret;
106 LPBYTE buf1,buf2;
107 OFSTRUCT ofs;
109 TRACE("(%x,%s,%s,%s,%s,%s,%p,%d)\n",
110 flags,debugstr_a(srcfilename),debugstr_a(destfilename),
111 debugstr_a(srcdir),debugstr_a(destdir),debugstr_a(curdir),
112 tmpfile,*tmpfilelen);
113 xret = 0;
114 if (!srcdir || !srcfilename) return VIF_CANNOTREADSRC;
115 sprintf(srcfn,"%s\\%s",srcdir,srcfilename);
116 if (!destdir || !*destdir) pdest = srcdir;
117 else pdest = destdir;
118 sprintf(destfn,"%s\\%s",pdest,destfilename);
119 hfsrc=LZOpenFileA(srcfn,&ofs,OF_READ);
120 if (hfsrc < 0)
121 return VIF_CANNOTREADSRC;
122 sprintf(tmpfn,"%s\\%s",pdest,destfilename);
123 tmplast=strlen(pdest)+1;
124 attr = GetFileAttributesA(tmpfn);
125 if (attr != INVALID_FILE_ATTRIBUTES) {
126 if (attr & FILE_ATTRIBUTE_READONLY) {
127 LZClose(hfsrc);
128 return VIF_WRITEPROT;
130 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
132 attr = INVALID_FILE_ATTRIBUTES;
133 if (flags & VIFF_FORCEINSTALL) {
134 if (tmpfile[0]) {
135 sprintf(tmpfn,"%s\\%s",pdest,tmpfile);
136 tmplast = strlen(pdest)+1;
137 attr = GetFileAttributesA(tmpfn);
138 /* if it exists, it has been copied by the call before.
139 * we jump over the copy part...
143 if (attr == INVALID_FILE_ATTRIBUTES) {
144 char *s;
146 GetTempFileNameA(pdest,"ver",0,tmpfn); /* should not fail ... */
147 s=strrchr(tmpfn,'\\');
148 if (s)
149 tmplast = s-tmpfn;
150 else
151 tmplast = 0;
152 hfdst = OpenFile(tmpfn,&ofs,OF_CREATE);
153 if (hfdst == HFILE_ERROR) {
154 LZClose(hfsrc);
155 return VIF_CANNOTCREATE; /* | translated dos error */
157 ret = LZCopy(hfsrc,hfdst);
158 _lclose(hfdst);
159 if (ret < 0) {
160 /* translate LZ errors into VIF_xxx */
161 switch (ret) {
162 case LZERROR_BADINHANDLE:
163 case LZERROR_READ:
164 case LZERROR_BADVALUE:
165 case LZERROR_UNKNOWNALG:
166 xret = VIF_CANNOTREADSRC;
167 break;
168 case LZERROR_BADOUTHANDLE:
169 case LZERROR_WRITE:
170 xret = VIF_OUTOFSPACE;
171 break;
172 case LZERROR_GLOBALLOC:
173 case LZERROR_GLOBLOCK:
174 xret = VIF_OUTOFMEMORY;
175 break;
176 default: /* unknown error, should not happen */
177 FIXME("Unknown LZCopy error %d, ignoring.\n", ret);
178 xret = 0;
179 break;
181 if (xret) {
182 LZClose(hfsrc);
183 return xret;
187 if (!(flags & VIFF_FORCEINSTALL)) {
188 VS_FIXEDFILEINFO *destvffi,*tmpvffi;
189 buf1 = _fetch_versioninfo(destfn,&destvffi);
190 if (buf1) {
191 buf2 = _fetch_versioninfo(tmpfn,&tmpvffi);
192 if (buf2) {
193 char *tbuf1,*tbuf2;
194 static const CHAR trans_array[] = "\\VarFileInfo\\Translation";
195 UINT len1,len2;
197 len1=len2=40;
199 /* compare file versions */
200 if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)||
201 ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&&
202 (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS)
205 xret |= VIF_MISMATCH|VIF_SRCOLD;
206 /* compare filetypes and filesubtypes */
207 if ((destvffi->dwFileType!=tmpvffi->dwFileType) ||
208 (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype)
210 xret |= VIF_MISMATCH|VIF_DIFFTYPE;
211 if (VerQueryValueA(buf1,trans_array,(LPVOID*)&tbuf1,&len1) &&
212 VerQueryValueA(buf2,trans_array,(LPVOID*)&tbuf2,&len2)
214 /* Do something with tbuf1 and tbuf2
215 * generates DIFFLANG|MISMATCH
218 HeapFree(GetProcessHeap(), 0, buf2);
219 } else
220 xret=VIF_MISMATCH|VIF_SRCOLD;
221 HeapFree(GetProcessHeap(), 0, buf1);
224 if (xret) {
225 if (*tmpfilelen<strlen(tmpfn+tmplast)) {
226 xret|=VIF_BUFFTOOSMALL;
227 DeleteFileA(tmpfn);
228 } else {
229 strcpy(tmpfile,tmpfn+tmplast);
230 *tmpfilelen = strlen(tmpfn+tmplast)+1;
231 xret|=VIF_TEMPFILE;
233 } else {
234 if (INVALID_FILE_ATTRIBUTES!=GetFileAttributesA(destfn))
235 if (!DeleteFileA(destfn)) {
236 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
237 DeleteFileA(tmpfn);
238 LZClose(hfsrc);
239 return xret;
241 if ((!(flags & VIFF_DONTDELETEOLD)) &&
242 curdir &&
243 *curdir &&
244 lstrcmpiA(curdir,pdest)
246 char curfn[260];
248 sprintf(curfn,"%s\\%s",curdir,destfilename);
249 if (INVALID_FILE_ATTRIBUTES != GetFileAttributesA(curfn)) {
250 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
251 if (!DeleteFileA(curfn))
252 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
255 if (!MoveFileA(tmpfn,destfn)) {
256 xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
257 DeleteFileA(tmpfn);
260 LZClose(hfsrc);
261 return xret;
265 /******************************************************************************
266 * VerInstallFileW [VERSION.@]
268 DWORD WINAPI VerInstallFileW(
269 DWORD flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
270 LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,PUINT tmpfilelen )
272 LPSTR wsrcf = NULL, wsrcd = NULL, wdestf = NULL, wdestd = NULL, wtmpf = NULL, wcurd = NULL;
273 DWORD ret = 0;
274 UINT len;
276 if (srcfilename)
278 len = WideCharToMultiByte( CP_ACP, 0, srcfilename, -1, NULL, 0, NULL, NULL );
279 if ((wsrcf = HeapAlloc( GetProcessHeap(), 0, len )))
280 WideCharToMultiByte( CP_ACP, 0, srcfilename, -1, wsrcf, len, NULL, NULL );
281 else
282 ret = VIF_OUTOFMEMORY;
284 if (srcdir && !ret)
286 len = WideCharToMultiByte( CP_ACP, 0, srcdir, -1, NULL, 0, NULL, NULL );
287 if ((wsrcd = HeapAlloc( GetProcessHeap(), 0, len )))
288 WideCharToMultiByte( CP_ACP, 0, srcdir, -1, wsrcd, len, NULL, NULL );
289 else
290 ret = VIF_OUTOFMEMORY;
292 if (destfilename && !ret)
294 len = WideCharToMultiByte( CP_ACP, 0, destfilename, -1, NULL, 0, NULL, NULL );
295 if ((wdestf = HeapAlloc( GetProcessHeap(), 0, len )))
296 WideCharToMultiByte( CP_ACP, 0, destfilename, -1, wdestf, len, NULL, NULL );
297 else
298 ret = VIF_OUTOFMEMORY;
300 if (destdir && !ret)
302 len = WideCharToMultiByte( CP_ACP, 0, destdir, -1, NULL, 0, NULL, NULL );
303 if ((wdestd = HeapAlloc( GetProcessHeap(), 0, len )))
304 WideCharToMultiByte( CP_ACP, 0, destdir, -1, wdestd, len, NULL, NULL );
305 else
306 ret = VIF_OUTOFMEMORY;
308 if (curdir && !ret)
310 len = WideCharToMultiByte( CP_ACP, 0, curdir, -1, NULL, 0, NULL, NULL );
311 if ((wcurd = HeapAlloc( GetProcessHeap(), 0, len )))
312 WideCharToMultiByte( CP_ACP, 0, curdir, -1, wcurd, len, NULL, NULL );
313 else
314 ret = VIF_OUTOFMEMORY;
316 if (!ret)
318 len = *tmpfilelen * sizeof(WCHAR);
319 wtmpf = HeapAlloc( GetProcessHeap(), 0, len );
320 if (!wtmpf)
321 ret = VIF_OUTOFMEMORY;
323 if (!ret)
324 ret = VerInstallFileA(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,&len);
325 if (!ret)
326 *tmpfilelen = MultiByteToWideChar( CP_ACP, 0, wtmpf, -1, tmpfile, *tmpfilelen );
327 else if (ret & VIF_BUFFTOOSMALL)
328 *tmpfilelen = len; /* FIXME: not correct */
330 HeapFree( GetProcessHeap(), 0, wsrcf );
331 HeapFree( GetProcessHeap(), 0, wsrcd );
332 HeapFree( GetProcessHeap(), 0, wdestf );
333 HeapFree( GetProcessHeap(), 0, wdestd );
334 HeapFree( GetProcessHeap(), 0, wtmpf );
335 HeapFree( GetProcessHeap(), 0, wcurd );
336 return ret;