2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Blažević
4 * Copyright 2015,2016 Mark Jansen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_NO_STATUS
27 #include "wine/unicode.h"
30 static BOOL WINAPI
SdbpFileExists(LPCWSTR path
)
32 DWORD attr
= GetFileAttributesW(path
);
33 return (attr
!= INVALID_FILE_ATTRIBUTES
&& !(attr
& FILE_ATTRIBUTE_DIRECTORY
));
38 * Opens specified shim database file Handle returned by this function may only be used by
39 * functions which take HSDB param thus differing it from SdbOpenDatabase.
41 * @param [in] flags Specifies type of path or predefined database.
42 * @param [in] path Path to the shim database file.
44 * @return Success: Handle to the opened shim database, NULL otherwise.
46 HSDB WINAPI
SdbInitDatabase(DWORD flags
, LPCWSTR path
)
48 static const WCHAR shim
[] = {'\\','s','y','s','m','a','i','n','.','s','d','b',0};
49 static const WCHAR msi
[] = {'\\','m','s','i','m','a','i','n','.','s','d','b',0};
50 static const WCHAR drivers
[] = {'\\','d','r','v','m','a','i','n','.','s','d','b',0};
55 sdb
= SdbAlloc(sizeof(SDB
));
60 /* Check for predefined databases */
61 if ((flags
& HID_DATABASE_TYPE_MASK
) && path
== NULL
)
63 switch (flags
& HID_DATABASE_TYPE_MASK
)
65 case SDB_DATABASE_MAIN_SHIM
: name
= shim
; break;
66 case SDB_DATABASE_MAIN_MSI
: name
= msi
; break;
67 case SDB_DATABASE_MAIN_DRIVERS
: name
= drivers
; break;
70 SdbGetAppPatchDir(NULL
, buffer
, 128);
71 memcpy(buffer
+ lstrlenW(buffer
), name
, SdbpStrlen(name
));
74 sdb
->db
= SdbOpenDatabase(path
? path
: buffer
, (flags
& 0xF) - 1);
76 /* If database could not be loaded, a handle doesn't make sense either */
79 SdbReleaseDatabase(sdb
);
87 * Closes shim database opened by SdbInitDatabase.
89 * @param [in] hsdb Handle to the shim database.
91 void WINAPI
SdbReleaseDatabase(HSDB hsdb
)
93 SdbCloseDatabase(hsdb
->db
);
98 * Queries database for a specified exe If hsdb is NULL default database shall be loaded and
101 * @param [in] hsdb Handle to the shim database.
102 * @param [in] path Path to executable for which we query database.
103 * @param [in] module_name Unused.
104 * @param [in] env Unused.
105 * @param [in] flags 0 or SDBGMEF_IGNORE_ENVIRONMENT.
106 * @param [out] result Pointer to structure in which query result shall be stored.
108 * @return TRUE if it succeeds, FALSE if it fails.
110 BOOL WINAPI
SdbGetMatchingExe(HSDB hsdb
, LPCWSTR path
, LPCWSTR module_name
,
111 LPCWSTR env
, DWORD flags
, PSDBQUERYRESULT result
)
113 static const WCHAR fmt
[] = {'%','s','%','s',0};
115 TAGID database
, iter
, attr
;
116 PATTRINFO attribs
= NULL
;
117 /*DWORD attr_count;*/
123 /* Load default database if one is not specified */
126 /* To reproduce windows behaviour HID_DOS_PATHS needs
127 * to be specified when loading default database */
128 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
130 hsdb
->auto_loaded
= TRUE
;
133 /* No database could be loaded */
139 /* Extract file name */
140 file_name
= strrchrW(path
, '\\') + 1;
142 /* Extract directory path */
143 memcpy(dir_path
, path
, (size_t)(file_name
- path
) * sizeof(WCHAR
));
145 /* Get information about executable required to match it with database entry */
146 /*if (!SdbGetFileAttributes(path, &attribs, &attr_count))
149 /* DATABASE is list TAG which contains all executables */
150 database
= SdbFindFirstTag(db
, TAGID_ROOT
, TAG_DATABASE
);
151 if (database
== TAGID_NULL
)
154 /* EXE is list TAG which contains data required to match executable */
155 iter
= SdbFindFirstTag(db
, database
, TAG_EXE
);
157 /* Search for entry in database */
158 while (iter
!= TAGID_NULL
)
160 /* Check if exe name matches */
161 attr
= SdbFindFirstTag(db
, iter
, TAG_NAME
);
162 if (lstrcmpiW(SdbGetStringTagPtr(db
, attr
), file_name
) == 0)
164 /* Assume that entry is found (in case there are no "matching files") */
167 /* Check if all "matching files" exist */
168 /* TODO: check size/checksum as well */
169 for (attr
= SdbFindFirstTag(db
, attr
, TAG_MATCHING_FILE
);
170 attr
!= TAGID_NULL
; attr
= SdbFindNextTag(db
, iter
, attr
))
172 snprintfW(buffer
, 256, fmt
, dir_path
, SdbGetStringTagPtr(db
, attr
));
173 if (!SdbpFileExists(buffer
))
180 /* TODO: fill result data */
181 /* TODO: there may be multiple matches */
187 /* Continue iterating */
188 iter
= SdbFindNextTag(db
, database
, iter
);
195 SdbFreeFileAttributes(attribs
);
196 if (hsdb
->auto_loaded
) SdbReleaseDatabase(hsdb
);
201 * Retrieves AppPatch directory.
203 * @param [in] db Handle to the shim database.
204 * @param [out] path Pointer to memory in which path shall be written.
205 * @param [in] size Size of the buffer in characters.
207 BOOL WINAPI
SdbGetAppPatchDir(HSDB db
, LPWSTR path
, DWORD size
)
209 static WCHAR
* default_dir
= NULL
;
210 static CONST WCHAR szAppPatch
[] = {'\\','A','p','p','P','a','t','c','h',0};
212 /* In case function fails, path holds empty string */
219 UINT len
= GetSystemWindowsDirectoryW(NULL
, 0) + lstrlenW(szAppPatch
);
220 tmp
= SdbAlloc((len
+ 1)* sizeof(WCHAR
));
223 UINT r
= GetSystemWindowsDirectoryW(tmp
, len
+1);
226 if (SUCCEEDED(StringCchCatW(tmp
, len
+1, szAppPatch
)))
228 if (InterlockedCompareExchangePointer((void**)&default_dir
, tmp
, NULL
) == NULL
)
237 SHIM_ERR("Unable to obtain default AppPatch directory\n");
244 return SUCCEEDED(StringCchCopyW(path
, size
, default_dir
));
248 SHIM_ERR("Unimplemented for db != NULL\n");
255 * Translates the given trWhich to a specific database / tagid
257 * @param [in] hsdb Handle to the database.
258 * @param [in] trWhich Tagref to find
259 * @param [out,opt] ppdb The Shim database that trWhich belongs to.
260 * @param [out,opt] ptiWhich The tagid that trWhich corresponds to.
262 * @return TRUE if it succeeds, FALSE if it fails.
264 BOOL WINAPI
SdbTagRefToTagID(HSDB hsdb
, TAGREF trWhich
, PDB
* ppdb
, TAGID
* ptiWhich
)
266 if (trWhich
& 0xf0000000)
268 SHIM_ERR("Multiple shim databases not yet implemented!\n");
272 *ptiWhich
= TAG_NULL
;
276 /* There seems to be no range checking on trWhich.. */
280 *ptiWhich
= trWhich
& 0x0fffffff;
286 * Translates the given trWhich to a specific database / tagid
288 * @param [in] hsdb Handle to the database.
289 * @param [in] pdb The Shim database that tiWhich belongs to.
290 * @param [in] tiWhich Path to executable for which we query database.
291 * @param [out,opt] ptrWhich The tagid that tiWhich corresponds to.
293 * @return TRUE if it succeeds, FALSE if it fails.
295 BOOL WINAPI
SdbTagIDToTagRef(HSDB hsdb
, PDB pdb
, TAGID tiWhich
, TAGREF
* ptrWhich
)
299 SHIM_ERR("Multiple shim databases not yet implemented!\n");
301 *ptrWhich
= TAGREF_NULL
;
306 *ptrWhich
= tiWhich
& 0x0fffffff;