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;
69 SdbReleaseDatabase(sdb
);
72 SdbGetAppPatchDir(NULL
, buffer
, 128);
73 memcpy(buffer
+ lstrlenW(buffer
), name
, SdbpStrlen(name
));
76 sdb
->db
= SdbOpenDatabase(path
? path
: buffer
, (flags
& 0xF) - 1);
78 /* If database could not be loaded, a handle doesn't make sense either */
81 SdbReleaseDatabase(sdb
);
89 * Closes shim database opened by SdbInitDatabase.
91 * @param [in] hsdb Handle to the shim database.
93 void WINAPI
SdbReleaseDatabase(HSDB hsdb
)
95 SdbCloseDatabase(hsdb
->db
);
100 * Queries database for a specified exe If hsdb is NULL default database shall be loaded and
103 * @param [in] hsdb Handle to the shim database.
104 * @param [in] path Path to executable for which we query database.
105 * @param [in] module_name Unused.
106 * @param [in] env Unused.
107 * @param [in] flags 0 or SDBGMEF_IGNORE_ENVIRONMENT.
108 * @param [out] result Pointer to structure in which query result shall be stored.
110 * @return TRUE if it succeeds, FALSE if it fails.
112 BOOL WINAPI
SdbGetMatchingExe(HSDB hsdb
, LPCWSTR path
, LPCWSTR module_name
,
113 LPCWSTR env
, DWORD flags
, PSDBQUERYRESULT result
)
115 static const WCHAR fmt
[] = {'%','s','%','s',0};
117 TAGID database
, iter
, attr
;
118 PATTRINFO attribs
= NULL
;
119 /*DWORD attr_count;*/
125 /* Load default database if one is not specified */
128 /* To reproduce windows behaviour HID_DOS_PATHS needs
129 * to be specified when loading default database */
130 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
132 hsdb
->auto_loaded
= TRUE
;
135 /* No database could be loaded */
141 /* Extract file name */
142 file_name
= strrchrW(path
, '\\') + 1;
144 /* Extract directory path */
145 memcpy(dir_path
, path
, (size_t)(file_name
- path
) * sizeof(WCHAR
));
147 /* Get information about executable required to match it with database entry */
148 /*if (!SdbGetFileAttributes(path, &attribs, &attr_count))
151 /* DATABASE is list TAG which contains all executables */
152 database
= SdbFindFirstTag(db
, TAGID_ROOT
, TAG_DATABASE
);
153 if (database
== TAGID_NULL
)
156 /* EXE is list TAG which contains data required to match executable */
157 iter
= SdbFindFirstTag(db
, database
, TAG_EXE
);
159 /* Search for entry in database */
160 while (iter
!= TAGID_NULL
)
162 /* Check if exe name matches */
163 attr
= SdbFindFirstTag(db
, iter
, TAG_NAME
);
164 if (lstrcmpiW(SdbGetStringTagPtr(db
, attr
), file_name
) == 0)
166 /* Assume that entry is found (in case there are no "matching files") */
169 /* Check if all "matching files" exist */
170 /* TODO: check size/checksum as well */
171 for (attr
= SdbFindFirstTag(db
, attr
, TAG_MATCHING_FILE
);
172 attr
!= TAGID_NULL
; attr
= SdbFindNextTag(db
, iter
, attr
))
174 snprintfW(buffer
, 256, fmt
, dir_path
, SdbGetStringTagPtr(db
, attr
));
175 if (!SdbpFileExists(buffer
))
182 /* TODO: fill result data */
183 /* TODO: there may be multiple matches */
189 /* Continue iterating */
190 iter
= SdbFindNextTag(db
, database
, iter
);
197 SdbFreeFileAttributes(attribs
);
198 if (hsdb
->auto_loaded
) SdbReleaseDatabase(hsdb
);
203 * Retrieves AppPatch directory.
205 * @param [in] db Handle to the shim database.
206 * @param [out] path Pointer to memory in which path shall be written.
207 * @param [in] size Size of the buffer in characters.
209 BOOL WINAPI
SdbGetAppPatchDir(HSDB db
, LPWSTR path
, DWORD size
)
211 static WCHAR
* default_dir
= NULL
;
212 static CONST WCHAR szAppPatch
[] = {'\\','A','p','p','P','a','t','c','h',0};
214 /* In case function fails, path holds empty string */
221 UINT len
= GetSystemWindowsDirectoryW(NULL
, 0) + lstrlenW(szAppPatch
);
222 tmp
= SdbAlloc((len
+ 1)* sizeof(WCHAR
));
225 UINT r
= GetSystemWindowsDirectoryW(tmp
, len
+1);
228 if (SUCCEEDED(StringCchCatW(tmp
, len
+1, szAppPatch
)))
230 if (InterlockedCompareExchangePointer((void**)&default_dir
, tmp
, NULL
) == NULL
)
239 SHIM_ERR("Unable to obtain default AppPatch directory\n");
246 return SUCCEEDED(StringCchCopyW(path
, size
, default_dir
));
250 SHIM_ERR("Unimplemented for db != NULL\n");
257 * Translates the given trWhich to a specific database / tagid
259 * @param [in] hsdb Handle to the database.
260 * @param [in] trWhich Tagref to find
261 * @param [out,opt] ppdb The Shim database that trWhich belongs to.
262 * @param [out,opt] ptiWhich The tagid that trWhich corresponds to.
264 * @return TRUE if it succeeds, FALSE if it fails.
266 BOOL WINAPI
SdbTagRefToTagID(HSDB hsdb
, TAGREF trWhich
, PDB
* ppdb
, TAGID
* ptiWhich
)
268 if (trWhich
& 0xf0000000)
270 SHIM_ERR("Multiple shim databases not yet implemented!\n");
274 *ptiWhich
= TAG_NULL
;
278 /* There seems to be no range checking on trWhich.. */
282 *ptiWhich
= trWhich
& 0x0fffffff;
288 * Translates the given trWhich to a specific database / tagid
290 * @param [in] hsdb Handle to the database.
291 * @param [in] pdb The Shim database that tiWhich belongs to.
292 * @param [in] tiWhich Path to executable for which we query database.
293 * @param [out,opt] ptrWhich The tagid that tiWhich corresponds to.
295 * @return TRUE if it succeeds, FALSE if it fails.
297 BOOL WINAPI
SdbTagIDToTagRef(HSDB hsdb
, PDB pdb
, TAGID tiWhich
, TAGREF
* ptrWhich
)
301 SHIM_ERR("Multiple shim databases not yet implemented!\n");
303 *ptrWhich
= TAGREF_NULL
;
308 *ptrWhich
= tiWhich
& 0x0fffffff;