mirror of https://github.com/AxioDL/metaforce.git
Windows refactors
This commit is contained in:
parent
199b8e7c32
commit
e4f53eaa7c
|
@ -9,6 +9,11 @@
|
||||||
#include <LogVisor/LogVisor.hpp>
|
#include <LogVisor/LogVisor.hpp>
|
||||||
#include "BlenderConnection.hpp"
|
#include "BlenderConnection.hpp"
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace HECL
|
namespace HECL
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -17,8 +22,6 @@ BlenderConnection* SharedBlenderConnection = nullptr;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
|
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
|
||||||
#elif _WIN32
|
|
||||||
#define DEFAULT_BLENDER_BIN _S("%ProgramFiles%\\Blender Foundation\\Blender\\blender.exe")
|
|
||||||
#else
|
#else
|
||||||
#define DEFAULT_BLENDER_BIN "blender"
|
#define DEFAULT_BLENDER_BIN "blender"
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,6 +29,19 @@ BlenderConnection* SharedBlenderConnection = nullptr;
|
||||||
extern "C" uint8_t HECL_BLENDERSHELL[];
|
extern "C" uint8_t HECL_BLENDERSHELL[];
|
||||||
extern "C" size_t HECL_BLENDERSHELL_SZ;
|
extern "C" size_t HECL_BLENDERSHELL_SZ;
|
||||||
|
|
||||||
|
extern "C" uint8_t HECL_ADDON[];
|
||||||
|
extern "C" size_t HECL_ADDON_SZ;
|
||||||
|
|
||||||
|
static bool InstallAddon(const SystemChar* path)
|
||||||
|
{
|
||||||
|
FILE* fp = HECL::Fopen(path, _S("wb"));
|
||||||
|
if (!fp)
|
||||||
|
BlenderLog.report(LogVisor::FatalError, _S("Unable to install blender addon at '%s'"), path);
|
||||||
|
fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp);
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
||||||
{
|
{
|
||||||
size_t readBytes = 0;
|
size_t readBytes = 0;
|
||||||
|
@ -37,15 +53,9 @@ size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
||||||
*(buf-1) = '\0';
|
*(buf-1) = '\0';
|
||||||
return bufSz - 1;
|
return bufSz - 1;
|
||||||
}
|
}
|
||||||
#if _WIN32
|
int ret = read(m_readpipe[0], buf, 1);
|
||||||
DWORD ret = 0;
|
|
||||||
if (!ReadFile(m_readpipe[0], buf, 1, &ret, NULL))
|
|
||||||
goto err;
|
|
||||||
#else
|
|
||||||
ssize_t ret = read(m_readpipe[0], buf, 1);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
|
||||||
else if (ret == 1)
|
else if (ret == 1)
|
||||||
{
|
{
|
||||||
if (*buf == '\n')
|
if (*buf == '\n')
|
||||||
|
@ -69,21 +79,13 @@ err:
|
||||||
|
|
||||||
size_t BlenderConnection::_writeLine(const char* buf)
|
size_t BlenderConnection::_writeLine(const char* buf)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
int ret, nlerr;
|
||||||
DWORD ret = 0;
|
|
||||||
if (!WriteFile(m_writepipe[1], buf, strlen(buf), &ret, NULL))
|
|
||||||
goto err;
|
|
||||||
if (!WriteFile(m_writepipe[1], "\n", 1, NULL, NULL))
|
|
||||||
goto err;
|
|
||||||
#else
|
|
||||||
ssize_t ret, nlerr;
|
|
||||||
ret = write(m_writepipe[1], buf, strlen(buf));
|
ret = write(m_writepipe[1], buf, strlen(buf));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
nlerr = write(m_writepipe[1], "\n", 1);
|
nlerr = write(m_writepipe[1], "\n", 1);
|
||||||
if (nlerr < 0)
|
if (nlerr < 0)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
|
||||||
return (size_t)ret;
|
return (size_t)ret;
|
||||||
err:
|
err:
|
||||||
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
||||||
|
@ -92,15 +94,9 @@ err:
|
||||||
|
|
||||||
size_t BlenderConnection::_readBuf(char* buf, size_t len)
|
size_t BlenderConnection::_readBuf(char* buf, size_t len)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
int ret = read(m_readpipe[0], buf, len);
|
||||||
DWORD ret = 0;
|
|
||||||
if (!ReadFile(m_readpipe[0], buf, len, &ret, NULL))
|
|
||||||
goto err;
|
|
||||||
#else
|
|
||||||
ssize_t ret = read(m_readpipe[0], buf, len);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
err:
|
err:
|
||||||
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
||||||
|
@ -109,15 +105,9 @@ err:
|
||||||
|
|
||||||
size_t BlenderConnection::_writeBuf(const char* buf, size_t len)
|
size_t BlenderConnection::_writeBuf(const char* buf, size_t len)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
int ret = write(m_writepipe[1], buf, len);
|
||||||
DWORD ret = 0;
|
|
||||||
if (!WriteFile(m_writepipe[1], buf, len, &ret, NULL))
|
|
||||||
goto err;
|
|
||||||
#else
|
|
||||||
ssize_t ret = write(m_writepipe[1], buf, len);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
err:
|
err:
|
||||||
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
||||||
|
@ -126,13 +116,8 @@ err:
|
||||||
|
|
||||||
void BlenderConnection::_closePipe()
|
void BlenderConnection::_closePipe()
|
||||||
{
|
{
|
||||||
#if _WIN32
|
|
||||||
CloseHandle(m_readpipe[0]);
|
|
||||||
CloseHandle(m_writepipe[1]);
|
|
||||||
#else
|
|
||||||
close(m_readpipe[0]);
|
close(m_readpipe[0]);
|
||||||
close(m_writepipe[1]);
|
close(m_writepipe[1]);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlenderConnection::BlenderConnection(bool silenceBlender)
|
BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
|
@ -155,11 +140,21 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp);
|
fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
HECL::SystemString blenderAddonPath(TMPDIR);
|
||||||
|
blenderAddonPath += _S("/hecl_blenderaddon.zip");
|
||||||
|
|
||||||
|
int installAttempt = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
/* Construct communication pipes */
|
/* Construct communication pipes */
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
_pipe(m_readpipe, 2048, _O_BINARY);
|
||||||
CreatePipe(&m_readpipe[0], &m_readpipe[1], &sattrs, 0);
|
_pipe(m_writepipe, 2048, _O_BINARY);
|
||||||
CreatePipe(&m_writepipe[0], &m_writepipe[1], &sattrs, 0);
|
HANDLE writehandle = HANDLE(_get_osfhandle(m_writepipe[0]));
|
||||||
|
SetHandleInformation(writehandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||||
|
HANDLE readhandle = HANDLE(_get_osfhandle(m_readpipe[1]));
|
||||||
|
SetHandleInformation(readhandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||||
#else
|
#else
|
||||||
pipe(m_readpipe);
|
pipe(m_readpipe);
|
||||||
pipe(m_writepipe);
|
pipe(m_writepipe);
|
||||||
|
@ -177,33 +172,27 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
if (!blenderBin)
|
if (!blenderBin)
|
||||||
{
|
{
|
||||||
/* Environment not set; use registry */
|
/* Environment not set; use default */
|
||||||
HKEY blenderKey;
|
wchar_t progFiles[256];
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\BlenderFoundation", 0, KEY_READ, &blenderKey) == ERROR_SUCCESS)
|
if (!GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256))
|
||||||
{
|
BlenderLog.report(LogVisor::FatalError, L"unable to determine 'Program Files' path");
|
||||||
DWORD bufSz = sizeof(BLENDER_BIN_BUF);
|
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender\\blender.exe", progFiles);
|
||||||
if (RegGetValueW(blenderKey, NULL, L"Install_Dir", REG_SZ, NULL, BLENDER_BIN_BUF, &bufSz) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
wcscat_s(BLENDER_BIN_BUF, 2048, L"\\blender.exe");
|
|
||||||
blenderBin = BLENDER_BIN_BUF;
|
blenderBin = BLENDER_BIN_BUF;
|
||||||
}
|
}
|
||||||
RegCloseKey(blenderKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!blenderBin)
|
|
||||||
{
|
|
||||||
Log.report(LogVisor::FatalError, "unable to find blender");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t cmdLine[2048];
|
wchar_t cmdLine[2048];
|
||||||
_snwprintf(cmdLine, 2048, L" --background -P shellscript.py -- %08X %08X",
|
if (installAttempt == 1)
|
||||||
(uint32_t)m_writepipe[0], (uint32_t)m_readpipe[1]);
|
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %d %d \"%s\"",
|
||||||
|
blenderShellPath.c_str(), int(writehandle), int(readhandle), blenderAddonPath.c_str());
|
||||||
|
else
|
||||||
|
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %d %d",
|
||||||
|
blenderShellPath.c_str(), int(writehandle), int(readhandle));
|
||||||
|
|
||||||
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
||||||
HANDLE nulHandle = NULL;
|
HANDLE nulHandle = NULL;
|
||||||
if (silenceBlender)
|
if (silenceBlender)
|
||||||
{
|
{
|
||||||
|
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||||
nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
sinfo.hStdError = nulHandle;
|
sinfo.hStdError = nulHandle;
|
||||||
sinfo.hStdOutput = nulHandle;
|
sinfo.hStdOutput = nulHandle;
|
||||||
|
@ -212,10 +201,15 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
|
|
||||||
PROCESS_INFORMATION pinfo;
|
PROCESS_INFORMATION pinfo;
|
||||||
if (!CreateProcessW(blenderBin, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo))
|
if (!CreateProcessW(blenderBin, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo))
|
||||||
Log.report(LogVisor::FatalError, "unable to launch blender");
|
{
|
||||||
|
LPWSTR messageBuffer = nullptr;
|
||||||
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
|
||||||
|
BlenderLog.report(LogVisor::FatalError, L"unable to launch blender from %s: %s", blenderBin, messageBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(m_writepipe[1]);
|
close(m_writepipe[0]);
|
||||||
CloseHandle(m_readpipe[0]);
|
close(m_readpipe[1]);
|
||||||
|
|
||||||
if (nulHandle)
|
if (nulHandle)
|
||||||
CloseHandle(nulHandle);
|
CloseHandle(nulHandle);
|
||||||
|
@ -243,6 +237,11 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
/* Try user-specified blender first */
|
/* Try user-specified blender first */
|
||||||
if (blenderBin)
|
if (blenderBin)
|
||||||
{
|
{
|
||||||
|
if (installAttempt == 1)
|
||||||
|
execlp(blenderBin, blenderBin,
|
||||||
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
|
"--", readfds, writefds, blenderAddonPath.c_str(), NULL);
|
||||||
|
else
|
||||||
execlp(blenderBin, blenderBin,
|
execlp(blenderBin, blenderBin,
|
||||||
"--background", "-P", blenderShellPath.c_str(),
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
"--", readfds, writefds, NULL);
|
"--", readfds, writefds, NULL);
|
||||||
|
@ -255,6 +254,11 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise default blender */
|
/* Otherwise default blender */
|
||||||
|
if (installAttempt == 1)
|
||||||
|
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
||||||
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
|
"--", readfds, writefds, blenderAddonPath.c_str(), NULL);
|
||||||
|
else
|
||||||
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
||||||
"--background", "-P", blenderShellPath.c_str(),
|
"--background", "-P", blenderShellPath.c_str(),
|
||||||
"--", readfds, writefds, NULL);
|
"--", readfds, writefds, NULL);
|
||||||
|
@ -296,7 +300,11 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
else if (!strcmp(lineBuf, "NOADDON"))
|
else if (!strcmp(lineBuf, "NOADDON"))
|
||||||
{
|
{
|
||||||
_closePipe();
|
_closePipe();
|
||||||
BlenderLog.report(LogVisor::FatalError, "HECL addon not installed within blender");
|
InstallAddon(blenderAddonPath.c_str());
|
||||||
|
++installAttempt;
|
||||||
|
if (installAttempt >= 2)
|
||||||
|
BlenderLog.report(LogVisor::FatalError, "unable to install blender addon using '%s'", blenderAddonPath.c_str());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (strcmp(lineBuf, "READY"))
|
else if (strcmp(lineBuf, "READY"))
|
||||||
{
|
{
|
||||||
|
@ -305,6 +313,8 @@ BlenderConnection::BlenderConnection(bool silenceBlender)
|
||||||
}
|
}
|
||||||
_writeLine("ACK");
|
_writeLine("ACK");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BlenderConnection::~BlenderConnection()
|
BlenderConnection::~BlenderConnection()
|
||||||
|
@ -326,7 +336,7 @@ bool BlenderConnection::createBlend(const SystemString& path)
|
||||||
_readLine(lineBuf, sizeof(lineBuf));
|
_readLine(lineBuf, sizeof(lineBuf));
|
||||||
if (!strcmp(lineBuf, "FINISHED"))
|
if (!strcmp(lineBuf, "FINISHED"))
|
||||||
{
|
{
|
||||||
m_loadedBlend = pathView.str();
|
m_loadedBlend = path;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -346,7 +356,7 @@ bool BlenderConnection::openBlend(const SystemString& path)
|
||||||
_readLine(lineBuf, sizeof(lineBuf));
|
_readLine(lineBuf, sizeof(lineBuf));
|
||||||
if (!strcmp(lineBuf, "FINISHED"))
|
if (!strcmp(lineBuf, "FINISHED"))
|
||||||
{
|
{
|
||||||
m_loadedBlend = pathView.str();
|
m_loadedBlend = path;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -373,12 +383,12 @@ void BlenderConnection::deleteBlend()
|
||||||
if (m_loadedBlend.size())
|
if (m_loadedBlend.size())
|
||||||
{
|
{
|
||||||
HECL::Unlink(m_loadedBlend.c_str());
|
HECL::Unlink(m_loadedBlend.c_str());
|
||||||
BlenderLog.report(LogVisor::Info, "Deleted '%s'", m_loadedBlend.c_str());
|
BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.c_str());
|
||||||
m_loadedBlend.clear();
|
m_loadedBlend.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlenderConnection::PyOutStream::linkBlend(const SystemString& target, const std::string& objName,
|
void BlenderConnection::PyOutStream::linkBlend(const std::string& target, const std::string& objName,
|
||||||
bool link)
|
bool link)
|
||||||
{
|
{
|
||||||
format("if '%s' not in bpy.data.scenes:\n"
|
format("if '%s' not in bpy.data.scenes:\n"
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
#define BLENDERCONNECTION_HPP
|
#define BLENDERCONNECTION_HPP
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#define _WIN32_LEAN_AND_MEAN 1
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -23,17 +25,15 @@ extern class BlenderConnection* SharedBlenderConnection;
|
||||||
|
|
||||||
class BlenderConnection
|
class BlenderConnection
|
||||||
{
|
{
|
||||||
bool m_lock;
|
bool m_lock = false;
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
HANDLE m_blenderProc;
|
HANDLE m_blenderProc;
|
||||||
HANDLE m_readpipe[2];
|
|
||||||
HANDLE m_writepipe[2];
|
|
||||||
#else
|
#else
|
||||||
pid_t m_blenderProc;
|
pid_t m_blenderProc;
|
||||||
|
#endif
|
||||||
int m_readpipe[2];
|
int m_readpipe[2];
|
||||||
int m_writepipe[2];
|
int m_writepipe[2];
|
||||||
#endif
|
SystemString m_loadedBlend;
|
||||||
std::string m_loadedBlend;
|
|
||||||
size_t _readLine(char* buf, size_t bufSz);
|
size_t _readLine(char* buf, size_t bufSz);
|
||||||
size_t _writeLine(const char* buf);
|
size_t _writeLine(const char* buf);
|
||||||
size_t _readBuf(char* buf, size_t len);
|
size_t _readBuf(char* buf, size_t len);
|
||||||
|
@ -75,11 +75,12 @@ public:
|
||||||
{
|
{
|
||||||
if (!m_parent.m_parent || !m_parent.m_parent->m_lock)
|
if (!m_parent.m_parent || !m_parent.m_parent->m_lock)
|
||||||
BlenderLog.report(LogVisor::FatalError, "lock not held for PyOutStream writing");
|
BlenderLog.report(LogVisor::FatalError, "lock not held for PyOutStream writing");
|
||||||
if (ch != traits_type::eof() && ch != '\n')
|
if (ch != traits_type::eof() && ch != '\n' && ch != '\0')
|
||||||
{
|
{
|
||||||
m_lineBuf += char_type(ch);
|
m_lineBuf += char_type(ch);
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
//printf("FLUSHING %s\n", m_lineBuf.c_str());
|
||||||
m_parent.m_parent->_writeLine(m_lineBuf.c_str());
|
m_parent.m_parent->_writeLine(m_lineBuf.c_str());
|
||||||
char readBuf[16];
|
char readBuf[16];
|
||||||
m_parent.m_parent->_readLine(readBuf, 16);
|
m_parent.m_parent->_readLine(readBuf, 16);
|
||||||
|
@ -109,7 +110,8 @@ public:
|
||||||
public:
|
public:
|
||||||
PyOutStream(const PyOutStream& other) = delete;
|
PyOutStream(const PyOutStream& other) = delete;
|
||||||
PyOutStream(PyOutStream&& other)
|
PyOutStream(PyOutStream&& other)
|
||||||
: m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf))
|
: m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)),
|
||||||
|
std::ostream(&m_sbuf)
|
||||||
{other.m_parent = nullptr;}
|
{other.m_parent = nullptr;}
|
||||||
~PyOutStream() {close();}
|
~PyOutStream() {close();}
|
||||||
void close()
|
void close()
|
||||||
|
@ -131,13 +133,19 @@ public:
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
char* result = nullptr;
|
char* result = nullptr;
|
||||||
|
#ifdef _WIN32
|
||||||
|
int length = _vscprintf(fmt, ap);
|
||||||
|
result = (char*)malloc(length);
|
||||||
|
vsnprintf(result, length, fmt, ap);
|
||||||
|
#else
|
||||||
int length = vasprintf(&result, fmt, ap);
|
int length = vasprintf(&result, fmt, ap);
|
||||||
|
#endif
|
||||||
|
va_end(ap);
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
this->write(result, length);
|
this->write(result, length);
|
||||||
free(result);
|
free(result);
|
||||||
va_end(ap);
|
|
||||||
}
|
}
|
||||||
void linkBlend(const SystemString& target, const std::string& objName, bool link=true);
|
void linkBlend(const std::string& target, const std::string& objName, bool link=true);
|
||||||
};
|
};
|
||||||
inline PyOutStream beginPythonOut(bool deleteOnError=false)
|
inline PyOutStream beginPythonOut(bool deleteOnError=false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,9 +13,20 @@ list(APPEND PY_SOURCES
|
||||||
|
|
||||||
bintoc(hecl_blendershell.c hecl_blendershell.py HECL_BLENDERSHELL)
|
bintoc(hecl_blendershell.c hecl_blendershell.py HECL_BLENDERSHELL)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/hecl.zip)
|
||||||
|
message("-- Generating addon package")
|
||||||
|
execute_process(COMMAND python zip_package.py
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/hecl.zip)
|
||||||
|
message(FATAL_ERROR "Unable to generate ${CMAKE_CURRENT_SOURCE_DIR}/hecl.zip; is python installed?")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
bintoc(hecl_addon.c hecl.zip HECL_ADDON)
|
||||||
|
|
||||||
add_library(HECLBlender
|
add_library(HECLBlender
|
||||||
BlenderConnection.cpp
|
BlenderConnection.cpp
|
||||||
BlenderConnection.hpp
|
BlenderConnection.hpp
|
||||||
hecl_blendershell.py
|
hecl_blendershell.py
|
||||||
hecl_blendershell.c
|
hecl_blendershell.c
|
||||||
|
hecl_addon.c
|
||||||
${PY_SOURCES})
|
${PY_SOURCES})
|
||||||
|
|
|
@ -9,6 +9,10 @@ if '--' not in sys.argv:
|
||||||
args = sys.argv[sys.argv.index('--')+1:]
|
args = sys.argv[sys.argv.index('--')+1:]
|
||||||
readfd = int(args[0])
|
readfd = int(args[0])
|
||||||
writefd = int(args[1])
|
writefd = int(args[1])
|
||||||
|
if sys.platform == "win32":
|
||||||
|
import msvcrt
|
||||||
|
readfd = msvcrt.open_osfhandle(readfd, os.O_RDONLY | os.O_BINARY)
|
||||||
|
writefd = msvcrt.open_osfhandle(writefd, os.O_WRONLY | os.O_BINARY)
|
||||||
|
|
||||||
def readpipeline():
|
def readpipeline():
|
||||||
retval = bytearray()
|
retval = bytearray()
|
||||||
|
@ -29,14 +33,23 @@ def quitblender():
|
||||||
writepipeline(b'QUITTING')
|
writepipeline(b'QUITTING')
|
||||||
bpy.ops.wm.quit_blender()
|
bpy.ops.wm.quit_blender()
|
||||||
|
|
||||||
# Check that HECL addon is installed/enabled
|
# If there's a third argument, use it as the .zip path containing the addon
|
||||||
if 'hecl' not in bpy.context.user_preferences.addons:
|
if len(args) >= 3:
|
||||||
if 'FINISHED' not in bpy.ops.wm.addon_enable(module='hecl'):
|
bpy.ops.wm.addon_install(overwrite=True, target='DEFAULT', filepath=args[2])
|
||||||
writepipeline(b'NOADDON')
|
bpy.ops.wm.addon_refresh()
|
||||||
bpy.ops.wm.quit_blender()
|
|
||||||
|
|
||||||
# Make addon available to commands
|
# Make addon available to commands
|
||||||
import hecl
|
if bpy.context.user_preferences.addons.find('hecl') == -1:
|
||||||
|
try:
|
||||||
|
bpy.ops.wm.addon_enable(module='hecl')
|
||||||
|
bpy.ops.wm.save_userpref()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
import hecl
|
||||||
|
except:
|
||||||
|
writepipeline(b'NOADDON')
|
||||||
|
bpy.ops.wm.quit_blender()
|
||||||
|
|
||||||
# Intro handshake
|
# Intro handshake
|
||||||
writepipeline(b'READY')
|
writepipeline(b'READY')
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import sys, os
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
def zipdir(path, ziph):
|
||||||
|
# ziph is zipfile handle
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for file in files:
|
||||||
|
ziph.write(os.path.join(root, file))
|
||||||
|
|
||||||
|
package_path = 'hecl'
|
||||||
|
target_zip = 'hecl.zip'
|
||||||
|
|
||||||
|
zf = zipfile.ZipFile(target_zip, mode='w', compression=zipfile.ZIP_DEFLATED)
|
||||||
|
print('GENERATING', target_zip)
|
||||||
|
if os.path.isdir(package_path):
|
||||||
|
zipdir(package_path, zf)
|
||||||
|
|
||||||
|
zf.close()
|
|
@ -1,7 +1,3 @@
|
||||||
if(WIN32)
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCLUDE:HECLDataSpecs")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(hecl main.cpp
|
add_executable(hecl main.cpp
|
||||||
ToolBase.hpp
|
ToolBase.hpp
|
||||||
ToolPackage.hpp
|
ToolPackage.hpp
|
||||||
|
@ -24,8 +20,12 @@ list(APPEND DATA_SPEC_LIBS
|
||||||
DNAMP1
|
DNAMP1
|
||||||
DNACommon)
|
DNACommon)
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
list(APPEND PLAT_LIBS pthread)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(hecl
|
target_link_libraries(hecl
|
||||||
${DATA_SPEC_LIBS}
|
${DATA_SPEC_LIBS}
|
||||||
HECLDatabase HECLBlender HECLCommon AthenaCore NOD
|
HECLDatabase HECLBlender HECLCommon AthenaCore NOD
|
||||||
LogVisor AthenaLibYaml png squish blowfish z lzo2 pthread
|
LogVisor AthenaLibYaml png squish blowfish z lzo2 ${PLAT_LIBS}
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
LogModule.report(LogVisor::FatalError, "hecl extract must be ran within a project directory");
|
LogModule.report(LogVisor::FatalError, "hecl extract must be ran within a project directory");
|
||||||
|
|
||||||
size_t ErrorRef = LogVisor::ErrorCount;
|
size_t ErrorRef = LogVisor::ErrorCount;
|
||||||
HECL::SystemString rootDir = info.cwd + '/' + baseFile;
|
HECL::SystemString rootDir = info.cwd + _S('/') + baseFile;
|
||||||
HECL::ProjectRootPath newProjRoot(rootDir);
|
HECL::ProjectRootPath newProjRoot(rootDir);
|
||||||
newProjRoot.makeDir();
|
newProjRoot.makeDir();
|
||||||
m_fallbackProj.reset(new HECL::Database::Project(newProjRoot));
|
m_fallbackProj.reset(new HECL::Database::Project(newProjRoot));
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#define WIN_PAUSE 1
|
#define WIN_PAUSE 1
|
||||||
|
#include <objbase.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <clocale>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -89,6 +91,12 @@ int wmain(int argc, const wchar_t** argv)
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#if _WIN32
|
||||||
|
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#else
|
||||||
|
std::setlocale(LC_ALL, "en-US.UTF-8");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Xterm check */
|
/* Xterm check */
|
||||||
const char* term = getenv("TERM");
|
const char* term = getenv("TERM");
|
||||||
if (term && !strncmp(term, "xterm", 5))
|
if (term && !strncmp(term, "xterm", 5))
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 66cb6c982e8824fa887807bf8ba42376b301478b
|
Subproject commit 488a0100e2e6044361a494a280c7f1a28911762e
|
|
@ -1,5 +1,5 @@
|
||||||
add_subdirectory(libpng)
|
|
||||||
add_subdirectory(libSquish)
|
add_subdirectory(libSquish)
|
||||||
add_subdirectory(blowfish)
|
add_subdirectory(blowfish)
|
||||||
add_subdirectory(LogVisor)
|
add_subdirectory(LogVisor)
|
||||||
add_subdirectory(Athena EXCLUDE_FROM_ALL)
|
add_subdirectory(Athena EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(libpng)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 154b84413050cdb03f281c42861b9af6eaef7d14
|
Subproject commit 828db515ba316903c367b9dc7acf9d0bec0969e7
|
|
@ -10,11 +10,12 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#else
|
#else
|
||||||
#define _WIN32_LEAN_AND_MEAN 1
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include "winsupport.h"
|
#include "winsupport.hpp"
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -29,8 +30,10 @@
|
||||||
#include "../extern/blowfish/blowfish.h"
|
#include "../extern/blowfish/blowfish.h"
|
||||||
|
|
||||||
/* Handy MIN/MAX macros */
|
/* Handy MIN/MAX macros */
|
||||||
|
#ifndef MAX
|
||||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace HECL
|
namespace HECL
|
||||||
{
|
{
|
||||||
|
@ -135,11 +138,11 @@ static inline void Unlink(const SystemChar* file)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void MakeDir(const SystemChar* dir)
|
static inline void MakeDir(const char* dir)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
HRESULT err;
|
HRESULT err;
|
||||||
if (!CreateDirectory(dir, NULL))
|
if (!CreateDirectoryA(dir, NULL))
|
||||||
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
||||||
LogModule.report(LogVisor::FatalError, _S("MakeDir(%s)"), dir);
|
LogModule.report(LogVisor::FatalError, _S("MakeDir(%s)"), dir);
|
||||||
#else
|
#else
|
||||||
|
@ -149,11 +152,29 @@ static inline void MakeDir(const SystemChar* dir)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
static inline void MakeDir(const wchar_t* dir)
|
||||||
|
{
|
||||||
|
HRESULT err;
|
||||||
|
if (!CreateDirectoryW(dir, NULL))
|
||||||
|
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
||||||
|
LogModule.report(LogVisor::FatalError, _S("MakeDir(%s)"), dir);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void MakeLink(const SystemChar* target, const SystemChar* linkPath)
|
static inline void MakeLink(const SystemChar* target, const SystemChar* linkPath)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
HRESULT res = CreateShellLink(target, linkPath, _S("HECL Link")); /* :(( */
|
||||||
|
if (!SUCCEEDED(res))
|
||||||
|
{
|
||||||
|
LPWSTR messageBuffer = nullptr;
|
||||||
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); /* :((( */
|
||||||
|
LogModule.report(LogVisor::FatalError, _S("MakeLink(%s, %s): %s"), target, linkPath, messageBuffer);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (symlink(target, linkPath))
|
if (symlink(target, linkPath)) /* :) */
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
LogModule.report(LogVisor::FatalError, "MakeLink(%s, %s): %s", target, linkPath, strerror(errno));
|
LogModule.report(LogVisor::FatalError, "MakeLink(%s, %s): %s", target, linkPath, strerror(errno));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifndef _HECL_WINSUPPORT_H_
|
|
||||||
#define _HECL_WINSUPPORT_H_
|
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void* memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen);
|
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _HECL_WINSUPPORT_H_
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef _HECL_WINSUPPORT_H_
|
||||||
|
#define _HECL_WINSUPPORT_H_
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
void* memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen);
|
||||||
|
HRESULT CreateShellLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink, LPCWSTR lpszDesc);
|
||||||
|
HRESULT ResolveShellLink(LPCWSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize);
|
||||||
|
|
||||||
|
#endif // _HECL_WINSUPPORT_H_
|
|
@ -4,7 +4,7 @@ add_subdirectory(Frontend)
|
||||||
add_subdirectory(Runtime)
|
add_subdirectory(Runtime)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND PLAT_SRCS winsupport.c ../include/HECL/winsupport.h)
|
list(APPEND PLAT_SRCS winsupport.cpp ../include/HECL/winsupport.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(HECLCommon
|
add_library(HECLCommon
|
||||||
|
|
|
@ -5,29 +5,45 @@ namespace HECL
|
||||||
|
|
||||||
std::string WideToUTF8(const std::wstring& src)
|
std::string WideToUTF8(const std::wstring& src)
|
||||||
{
|
{
|
||||||
|
#if _WIN32
|
||||||
|
int len = WideCharToMultiByte(CP_UTF8, 0, src.c_str(), src.size(), nullptr, 0, nullptr, nullptr);
|
||||||
|
std::string retval(len, '\0');
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, src.c_str(), src.size(), &retval[0], len, nullptr, nullptr);
|
||||||
|
return retval;
|
||||||
|
#else
|
||||||
std::string retval;
|
std::string retval;
|
||||||
retval.reserve(src.length());
|
retval.reserve(src.length());
|
||||||
|
std::mbstate_t state = {};
|
||||||
for (wchar_t ch : src)
|
for (wchar_t ch : src)
|
||||||
{
|
{
|
||||||
char mb[4];
|
char mb[MB_LEN_MAX];
|
||||||
int c = std::wctomb(mb, ch);
|
int c = std::wcrtomb(mb, ch, &state);
|
||||||
retval.append(mb, c);
|
retval.append(mb, c);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring UTF8ToWide(const std::string& src)
|
std::wstring UTF8ToWide(const std::string& src)
|
||||||
{
|
{
|
||||||
|
#if _WIN32
|
||||||
|
int len = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), src.size(), nullptr, 0);
|
||||||
|
std::wstring retval(len, L'\0');
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, src.c_str(), src.size(), &retval[0], len);
|
||||||
|
return retval;
|
||||||
|
#else
|
||||||
std::wstring retval;
|
std::wstring retval;
|
||||||
retval.reserve(src.length());
|
retval.reserve(src.length());
|
||||||
const char* buf = src.c_str();
|
const char* buf = src.c_str();
|
||||||
|
std::mbstate_t state = {};
|
||||||
while (*buf)
|
while (*buf)
|
||||||
{
|
{
|
||||||
wchar_t wc;
|
wchar_t wc;
|
||||||
buf += std::mbtowc(&wc, buf, MB_CUR_MAX);
|
buf += std::mbrtowc(&wc, buf, MB_LEN_MAX, &state);
|
||||||
retval += wc;
|
retval += wc;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The memmem() function finds the start of the first occurrence of the
|
|
||||||
* substring 'needle' of length 'nlen' in the memory area 'haystack' of
|
|
||||||
* length 'hlen'.
|
|
||||||
*
|
|
||||||
* The return value is a pointer to the beginning of the sub-string, or
|
|
||||||
* NULL if the substring is not found.
|
|
||||||
*/
|
|
||||||
void *memmem(const uint8_t *haystack, size_t hlen, const void *needle, size_t nlen)
|
|
||||||
{
|
|
||||||
int needle_first;
|
|
||||||
const uint8_t *p = haystack;
|
|
||||||
size_t plen = hlen;
|
|
||||||
|
|
||||||
if (!nlen)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
needle_first = *(unsigned char *)needle;
|
|
||||||
|
|
||||||
while (plen >= nlen && (p = memchr(p, needle_first, plen - nlen + 1)))
|
|
||||||
{
|
|
||||||
if (!memcmp(p, needle, nlen))
|
|
||||||
return (void *)p;
|
|
||||||
|
|
||||||
p++;
|
|
||||||
plen = hlen - (p - haystack);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include "HECL/winsupport.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The memmem() function finds the start of the first occurrence of the
|
||||||
|
* substring 'needle' of length 'nlen' in the memory area 'haystack' of
|
||||||
|
* length 'hlen'.
|
||||||
|
*
|
||||||
|
* The return value is a pointer to the beginning of the sub-string, or
|
||||||
|
* NULL if the substring is not found.
|
||||||
|
*/
|
||||||
|
void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen)
|
||||||
|
{
|
||||||
|
int needle_first;
|
||||||
|
const uint8_t *p = static_cast<const uint8_t*>(haystack);
|
||||||
|
size_t plen = hlen;
|
||||||
|
|
||||||
|
if (!nlen)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
needle_first = *(unsigned char *)needle;
|
||||||
|
|
||||||
|
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1))))
|
||||||
|
{
|
||||||
|
if (!memcmp(p, needle, nlen))
|
||||||
|
return (void *)p;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
plen = hlen - (p - static_cast<const uint8_t*>(haystack));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clearly, MS doesn't require enough headers for this */
|
||||||
|
#include "winnls.h"
|
||||||
|
#include "shobjidl.h"
|
||||||
|
#include "objbase.h"
|
||||||
|
#include "objidl.h"
|
||||||
|
#include "shlguid.h"
|
||||||
|
#include "strsafe.h"
|
||||||
|
|
||||||
|
HRESULT CreateShellLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink, LPCWSTR lpszDesc)
|
||||||
|
{
|
||||||
|
std::wstring targetStr(lpszPathObj);
|
||||||
|
for (wchar_t& ch : targetStr)
|
||||||
|
if (ch == L'/')
|
||||||
|
ch = L'\\';
|
||||||
|
std::wstring linkStr(lpszPathLink);
|
||||||
|
linkStr += L".lnk";
|
||||||
|
for (wchar_t& ch : linkStr)
|
||||||
|
if (ch == L'/')
|
||||||
|
ch = L'\\';
|
||||||
|
|
||||||
|
HRESULT hres;
|
||||||
|
IShellLink* psl;
|
||||||
|
|
||||||
|
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
|
||||||
|
// has already been called.
|
||||||
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
IPersistFile* ppf;
|
||||||
|
|
||||||
|
// Set the path to the shortcut target and add the description.
|
||||||
|
WCHAR targetBuf[MAX_PATH];
|
||||||
|
WCHAR linkBuf[MAX_PATH];
|
||||||
|
WCHAR* linkFinalPart = nullptr;
|
||||||
|
GetFullPathNameW(linkStr.c_str(), MAX_PATH, linkBuf, &linkFinalPart);
|
||||||
|
if (linkFinalPart != linkBuf)
|
||||||
|
*(linkFinalPart-1) = L'\0';
|
||||||
|
StringCbPrintfW(targetBuf, MAX_PATH, L"%s\\%s", linkBuf, targetStr.c_str());
|
||||||
|
if (linkFinalPart != linkBuf)
|
||||||
|
*(linkFinalPart - 1) = L'\\';
|
||||||
|
psl->SetPath(targetBuf);
|
||||||
|
psl->SetRelativePath(linkBuf, 0);
|
||||||
|
psl->SetDescription(lpszDesc);
|
||||||
|
|
||||||
|
// Query IShellLink for the IPersistFile interface, used for saving the
|
||||||
|
// shortcut in persistent storage.
|
||||||
|
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
// Save the link by calling IPersistFile::Save.
|
||||||
|
hres = ppf->Save(linkBuf, TRUE);
|
||||||
|
ppf->Release();
|
||||||
|
}
|
||||||
|
psl->Release();
|
||||||
|
}
|
||||||
|
return hres;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT ResolveShellLink(LPCWSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize)
|
||||||
|
{
|
||||||
|
HRESULT hres;
|
||||||
|
IShellLink* psl;
|
||||||
|
WCHAR szGotPath[MAX_PATH];
|
||||||
|
WCHAR szDescription[MAX_PATH];
|
||||||
|
WIN32_FIND_DATA wfd;
|
||||||
|
|
||||||
|
*lpszPath = 0; // Assume failure
|
||||||
|
|
||||||
|
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
|
||||||
|
// has already been called.
|
||||||
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
IPersistFile* ppf;
|
||||||
|
|
||||||
|
// Get a pointer to the IPersistFile interface.
|
||||||
|
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
// Load the shortcut.
|
||||||
|
hres = ppf->Load(lpszLinkFile, STGM_READ);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
// Resolve the link.
|
||||||
|
HWND hwnd = GetConsoleWindow();
|
||||||
|
if (!hwnd)
|
||||||
|
hwnd = GetTopWindow(nullptr);
|
||||||
|
hres = psl->Resolve(hwnd, 0);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
// Get the path to the link target.
|
||||||
|
hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
// Get the description of the target.
|
||||||
|
hres = psl->GetDescription(szDescription, MAX_PATH);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the pointer to the IPersistFile interface.
|
||||||
|
ppf->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the pointer to the IShellLink interface.
|
||||||
|
psl->Release();
|
||||||
|
}
|
||||||
|
return hres;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue