In c++, I've created a application launcher DLL for .ekccafile file types. This extensions stands for EK CEF Client App. Obviously, .ekccafile are file dependent to CEF dlls. If that file type is double clicked in explorer, my dll gets called via rundll.exe and its exported function is executed. Inside that function, it checks for the folder path set in the target file's configuration. See if the files required by the target file are all present. If all goes well it then calls SetDLLDirectory pointing to that path then launches the target file via CreateProcess. My goal here is to put all CEF dlls in one location so that I don't have multiple copies of half gigabytes of CEF resources in my drive. I've just came to know about SetDLLDirectory very recently and my question is, how does SetDLLDirectory affects other executables?
Here’s the DLL functions
static bool wmCmdProcd;
static WCHAR _path[MAX_PATH];
template<size_t size>
static bool CheckDepends(HWND hwnd, WCHAR(&cefpath)[size]) {
static LPCWSTR __cefBins[] = {
L"libcef.dll",
L"chrome_elf.dll",
L"icudtl.dat",
L"v8_context_snapshot.bin"
};
std::wstring base = cefpath, missing;
FILE* f;
for (auto path: __cefBins) {
std::wstring w = base + L"\\" + path;
f = nullptr;
auto err = _wfopen_s(&f, w.c_str(), L"r");
if (err || !f) {
if (missing.size())
missing += L"\n";
missing += L"\t";
missing += path;
}
else
fclose(f);
}
if (missing.size()) {
missing = L"The followig files are missing in " + std::wstring(cefpath) + L"\n" + missing + L".\nDo you want to browse the folder where the CefSharp binaries are located?";
wmCmdProcd = false;
return ek::Window::HookedMsgBox([](ek::Window::HookedMsgBox& mbox, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& res)->bool {
if (uMsg == WM_COMMAND) {
if (LOWORD(wParam) == IDYES) {
if (!wmCmdProcd) {
ek::Window::FileDialog fd;
fd.Options = ek::Window::FDlgOpts::PickFolders | fd.Options;
if (fd.Show(mbox)) {
wmCmdProcd = true;
wcscpy_s((LPWSTR)mbox.Param(), MAX_PATH, fd.Result);
char sz[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, fd.Result, -1, sz, MAX_PATH, nullptr, nullptr);
std::wstring wsz = _path;
wsz += L"\\cefshared.bin";
ek::io::FileStream fs(wsz, L"w");
fs.Write(sz, strlen(sz));
SendMessage(mbox, uMsg, wParam, lParam);
}
return true;
}
}
}
return false;
},(LPARAM)cefpath).Show(hwnd, missing.c_str(), L"Missing Important CEF Files", MB_ICONINFORMATION | MB_YESNO) == IDYES;
}
return true;
}
void CALLBACK LaunchFile(HWND hwnd, HINSTANCE hinst, LPSTR lpCmdLine, int nCmdShow) {
if (!szCefPath[0]) {
GetModuleFileName(reinterpret_cast<HINSTANCE>(&__ImageBase), _path, MAX_PATH);
WCHAR* ptr = wcsrchr(_path, '\\');
*ptr = 0;
wcscpy_s(szCefPath, _path);
wcscat_s(szCefPath, L"\\cefshared.bin");
ek::io::FileStream fs(szCefPath, L"r");
if (!fs.is_open) {
*(wcsrchr(szCefPath, '\\')) = 0;
}
else {
char sz[MAX_PATH];
auto size = fs.Read(sz, MAX_PATH);
sz[size] = 0;
MultiByteToWideChar(CP_ACP, 0, sz, -1, szCefPath, MAX_PATH);
}
}
if (!CheckDepends(hwnd, szCefPath))
return;
SetDllDirectory(szCefPath);
WCHAR wsz[MAX_PATH] = {};
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
MultiByteToWideChar(CP_ACP, 0, lpCmdLine, -1, wsz, MAX_PATH);
if (wsz[0] == '"') {
WCHAR* p1 = wsz, * p2 = wsz + 1;
while (*p2) {
if (*p2 == '"')break;
*p1++ = *p2++;
}
*p1 = 0;
}
if (!CheckHeader(wsz)) {
MessageBox(hwnd, (std::wstring(wsz) + L" is not a valid executable.").c_str(), L"Invalid File", MB_ICONINFORMATION);
return;
}
BOOL a = CreateProcess(
wsz, // Application path
nullptr, // Command line args
nullptr, nullptr, // Security attributes
FALSE, // Inherit handles
0, // Creation flags
nullptr, // Environment
szCefPath, // Current directory
&si, &pi // Startup info and process info
);
if (a) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
Please ignore the following since they are just calls to built-in windows native DLL functions:
- ek::Window::HookedMsgBox
- ek::Window::FileDialog fd;