mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2025-01-13 07:33:53 +08:00
.
This commit is contained in:
parent
3a037da085
commit
d4f16add89
@ -1,20 +1,4 @@
|
|||||||
struct AutoHandle
|
|
||||||
{
|
|
||||||
HANDLE _handle;
|
|
||||||
AutoHandle(HANDLE handle) : _handle(handle) {};
|
|
||||||
~AutoHandle()
|
|
||||||
{
|
|
||||||
CloseHandle(_handle);
|
|
||||||
}
|
|
||||||
operator HANDLE()
|
|
||||||
{
|
|
||||||
return _handle;
|
|
||||||
}
|
|
||||||
operator bool()
|
|
||||||
{
|
|
||||||
return _handle == INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inline SECURITY_ATTRIBUTES allAccess = std::invoke([] // allows non-admin processes to access kernel objects made by admin processes
|
inline SECURITY_ATTRIBUTES allAccess = std::invoke([] // allows non-admin processes to access kernel objects made by admin processes
|
||||||
{
|
{
|
||||||
static SECURITY_DESCRIPTOR sd = {};
|
static SECURITY_DESCRIPTOR sd = {};
|
||||||
|
@ -323,11 +323,11 @@ int main()
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
// 当更新进行时,禁止启动
|
// 当更新进行时,禁止启动
|
||||||
AutoHandle hMutex = CreateMutex(NULL, FALSE, L"LUNA_UPDATER_SINGLE");
|
CHandle hMutex{CreateMutex(NULL, FALSE, L"LUNA_UPDATER_SINGLE")};
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto __handle = AutoHandle(CreateMutexA(&allAccess, FALSE, "LUNA_UPDATER_BLOCK"));
|
CHandle __handle{CreateMutexA(&allAccess, FALSE, "LUNA_UPDATER_BLOCK")};
|
||||||
PyStand ps(L"files\\runtime");
|
PyStand ps(L"files\\runtime");
|
||||||
if (ps.DetectScript() != 0)
|
if (ps.DetectScript() != 0)
|
||||||
{
|
{
|
||||||
|
@ -55,10 +55,10 @@ std::optional<std::vector<byte>> _Speak(std::wstring &Content, const wchar_t *to
|
|||||||
|
|
||||||
ULONG bytesRead; // this will tell the number of bytes that have been read
|
ULONG bytesRead; // this will tell the number of bytes that have been read
|
||||||
std::vector<byte> datas;
|
std::vector<byte> datas;
|
||||||
datas.resize(sSize + 0x3ea);
|
datas.resize(sSize + 46);
|
||||||
auto pBuffer = datas.data(); // buffer to read the data
|
auto pBuffer = datas.data(); // buffer to read the data
|
||||||
// memcpy(pBuffer,&wavHeader,sizeof(WAV_HEADER));
|
// memcpy(pBuffer,&wavHeader,sizeof(WAV_HEADER));
|
||||||
int fsize = sSize + 0x3ea;
|
int fsize = sSize + 46;
|
||||||
int ptr = 0;
|
int ptr = 0;
|
||||||
memcpy(pBuffer, "RIFF", 4);
|
memcpy(pBuffer, "RIFF", 4);
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <mmdeviceapi.h>
|
#include <mmdeviceapi.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
|
#include <atlsync.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -489,51 +489,10 @@ char *TranslateFull(char *otext, int freeText, int NeedAbort(int line, int lines
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wchar_t *logFile = 0;
|
|
||||||
void SetLogFile(wchar_t *file)
|
|
||||||
{
|
|
||||||
logFile = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *TranslateFullLog(wchar_t *otext)
|
|
||||||
{
|
|
||||||
if (logFile && logFile[0])
|
|
||||||
{
|
|
||||||
HANDLE hMutex = CreateMutex(0, 0, L"TRAG Logging Super Mutext +10 from Outer Space");
|
|
||||||
DWORD res;
|
|
||||||
if (hMutex)
|
|
||||||
res = WaitForSingleObject(hMutex, 2000);
|
|
||||||
HANDLE hFile = CreateFile(logFile, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
|
|
||||||
if (hFile != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
DWORD junk;
|
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
||||||
SetFilePointer(hFile, 0, 0, FILE_END);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wchar_t bom = 0xFEFF;
|
|
||||||
WriteFile(hFile, &bom, sizeof(wchar_t), &junk, 0);
|
|
||||||
}
|
|
||||||
WriteFile(hFile, otext, sizeof(wchar_t) * wcslen(otext), &junk, 0);
|
|
||||||
WriteFile(hFile, L"\r\n", sizeof(wchar_t) * 2, &junk, 0);
|
|
||||||
CloseHandle(hFile);
|
|
||||||
}
|
|
||||||
if (hMutex)
|
|
||||||
{
|
|
||||||
// Prolly not needed.
|
|
||||||
if (WAIT_OBJECT_0 == res)
|
|
||||||
ReleaseMutex(hMutex);
|
|
||||||
CloseHandle(hMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TranslateFull(otext);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AtlasConfig atlcfg;
|
struct AtlasConfig atlcfg;
|
||||||
|
|
||||||
void writestring(const wchar_t *text, HANDLE hPipe);
|
void writestring(const wchar_t *text, HANDLE hPipe);
|
||||||
wchar_t *readstring(HANDLE hPipe);
|
wchar_t *readstring(HANDLE hPipe);
|
||||||
HANDLE mutex = NULL;
|
|
||||||
int atlaswmain(int argc, wchar_t *argv[])
|
int atlaswmain(int argc, wchar_t *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -548,33 +507,6 @@ int atlaswmain(int argc, wchar_t *argv[])
|
|||||||
if (!src)
|
if (!src)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!mutex)
|
|
||||||
{
|
|
||||||
mutex = CreateMutex(NULL, FALSE, NULL);
|
|
||||||
if (!mutex)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool waitingForMutex = true;
|
|
||||||
while (waitingForMutex)
|
|
||||||
{
|
|
||||||
switch (WaitForSingleObject(mutex, INFINITE))
|
|
||||||
{
|
|
||||||
case WAIT_OBJECT_0:
|
|
||||||
{
|
|
||||||
waitingForMutex = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WAIT_ABANDONED:
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!AtlasIsLoaded())
|
if (!AtlasIsLoaded())
|
||||||
{
|
{
|
||||||
// atlcfg.flags = ~BREAK_ON_SINGLE_LINE_BREAKS;
|
// atlcfg.flags = ~BREAK_ON_SINGLE_LINE_BREAKS;
|
||||||
@ -583,7 +515,6 @@ int atlaswmain(int argc, wchar_t *argv[])
|
|||||||
InitAtlas(atlcfg, ATLAS_JAP_TO_ENG);
|
InitAtlas(atlcfg, ATLAS_JAP_TO_ENG);
|
||||||
if (!AtlasIsLoaded())
|
if (!AtlasIsLoaded())
|
||||||
{
|
{
|
||||||
ReleaseMutex(mutex);
|
|
||||||
writestring(0, hPipe);
|
writestring(0, hPipe);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -592,7 +523,6 @@ int atlaswmain(int argc, wchar_t *argv[])
|
|||||||
writestring(text, hPipe);
|
writestring(text, hPipe);
|
||||||
free(src);
|
free(src);
|
||||||
free(text);
|
free(text);
|
||||||
ReleaseMutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -39,9 +39,6 @@ char *TranslateFull(char *otext, int freeText = 0, int NeedAbort(int line, int l
|
|||||||
|
|
||||||
int AtlasIsLoaded();
|
int AtlasIsLoaded();
|
||||||
|
|
||||||
// dirty hack
|
|
||||||
void SetLogFile(wchar_t *file);
|
|
||||||
wchar_t *TranslateFullLog(wchar_t *otext);
|
|
||||||
/*
|
/*
|
||||||
wchar_t path[MAX_PATH];
|
wchar_t path[MAX_PATH];
|
||||||
GetCurrentDirectory(MAX_PATH, path);
|
GetCurrentDirectory(MAX_PATH, path);
|
||||||
|
@ -39,7 +39,7 @@ std::wstring stolower(const std::wstring &s1)
|
|||||||
std::vector<DWORD> EnumerateProcesses(const std::wstring &exe)
|
std::vector<DWORD> EnumerateProcesses(const std::wstring &exe)
|
||||||
{
|
{
|
||||||
|
|
||||||
AutoHandle hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
CHandle hSnapshot{CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)};
|
||||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
@ -5,13 +5,13 @@ int updatewmain(int argc, wchar_t *argv[])
|
|||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
return 0;
|
return 0;
|
||||||
SetProcessDPIAware();
|
SetProcessDPIAware();
|
||||||
AutoHandle hMutex = CreateMutex(NULL, FALSE, L"LUNA_UPDATER_SINGLE");
|
CHandle hMutex{CreateMutex(NULL, FALSE, L"LUNA_UPDATER_SINGLE")};
|
||||||
|
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
return 0;
|
return 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
AutoHandle semaphore = CreateMutex(NULL, FALSE, L"LUNA_UPDATER_BLOCK");
|
CHandle semaphore{CreateMutex(NULL, FALSE, L"LUNA_UPDATER_BLOCK")};
|
||||||
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
break;
|
break;
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
|
@ -26,12 +26,10 @@ namespace ebyroid
|
|||||||
|
|
||||||
ApiAdapter *ApiAdapter::Create(const char *dllpath)
|
ApiAdapter *ApiAdapter::Create(const char *dllpath)
|
||||||
{
|
{
|
||||||
printf("dllpath %s\n", dllpath);
|
|
||||||
HINSTANCE handle = LoadLibraryA(dllpath);
|
HINSTANCE handle = LoadLibraryA(dllpath);
|
||||||
if (handle == nullptr)
|
if (handle == nullptr)
|
||||||
{
|
{
|
||||||
char m[128];
|
char m[128];
|
||||||
printf("load error\n");
|
|
||||||
std::snprintf(m,
|
std::snprintf(m,
|
||||||
128,
|
128,
|
||||||
"LoadLibrary failed with code %d (Check out the voiceroid path setting)",
|
"LoadLibrary failed with code %d (Check out the voiceroid path setting)",
|
||||||
@ -52,7 +50,6 @@ namespace ebyroid
|
|||||||
adapter->text_to_speech_ = LoadProc<ApiTextToSpeech>(handle, "_AITalkAPI_TextToSpeech@12");
|
adapter->text_to_speech_ = LoadProc<ApiTextToSpeech>(handle, "_AITalkAPI_TextToSpeech@12");
|
||||||
adapter->close_speech_ = LoadProc<ApiCloseSpeech>(handle, "_AITalkAPI_CloseSpeech@8");
|
adapter->close_speech_ = LoadProc<ApiCloseSpeech>(handle, "_AITalkAPI_CloseSpeech@8");
|
||||||
adapter->get_data_ = LoadProc<ApiGetData>(handle, "_AITalkAPI_GetData@16");
|
adapter->get_data_ = LoadProc<ApiGetData>(handle, "_AITalkAPI_GetData@16");
|
||||||
printf("load dll ok\n");
|
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,28 +34,17 @@ namespace ebyroid
|
|||||||
return ebyroid;
|
return ebyroid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Ebyroid::Hiragana(const unsigned char *inbytes, unsigned char **outbytes, size_t *outsize)
|
int Ebyroid::Hiragana(const char *inbytes, std::vector<char> &output)
|
||||||
{
|
{
|
||||||
Response *const response = new Response(api_adapter_);
|
Response<char> response{api_adapter_};
|
||||||
printf("1\n");
|
|
||||||
TJobParam param;
|
TJobParam param;
|
||||||
param.mode_in_out = IOMODE_PLAIN_TO_AIKANA;
|
param.mode_in_out = IOMODE_PLAIN_TO_AIKANA;
|
||||||
param.user_data = response;
|
param.user_data = &response;
|
||||||
|
|
||||||
char eventname[32];
|
|
||||||
std::sprintf(eventname, "TTKLOCK:%p", response);
|
|
||||||
printf("12\n");
|
|
||||||
HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventname);
|
|
||||||
printf("3\n");
|
|
||||||
int32_t job_id;
|
int32_t job_id;
|
||||||
ResultCode result = api_adapter_->TextToKana(&job_id, ¶m, (const char *)inbytes);
|
ResultCode result = api_adapter_->TextToKana(&job_id, ¶m, inbytes);
|
||||||
printf("4\n");
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete response;
|
|
||||||
printf("%d\n", result);
|
|
||||||
ResetEvent(event);
|
|
||||||
CloseHandle(event);
|
|
||||||
static const char *format = "TextToKana failed with the result code %d\n"
|
static const char *format = "TextToKana failed with the result code %d\n"
|
||||||
"Given inbytes: %s";
|
"Given inbytes: %s";
|
||||||
|
|
||||||
@ -63,53 +52,33 @@ namespace ebyroid
|
|||||||
std::snprintf(m, 0xFFFF, format, result, inbytes);
|
std::snprintf(m, 0xFFFF, format, result, inbytes);
|
||||||
throw std::runtime_error(m);
|
throw std::runtime_error(m);
|
||||||
}
|
}
|
||||||
printf("6\n");
|
WaitForSingleObject(response.event, INFINITE);
|
||||||
WaitForSingleObject(event, INFINITE);
|
|
||||||
ResetEvent(event);
|
|
||||||
CloseHandle(event);
|
|
||||||
printf("8\n");
|
|
||||||
// finalize
|
// finalize
|
||||||
result = api_adapter_->CloseKana(job_id);
|
result = api_adapter_->CloseKana(job_id);
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete response;
|
|
||||||
throw std::runtime_error("wtf");
|
throw std::runtime_error("wtf");
|
||||||
}
|
}
|
||||||
|
|
||||||
// write to output memory
|
// write to output memory
|
||||||
vector<unsigned char> buffer = response->End();
|
output = response.End();
|
||||||
*outsize = buffer.size();
|
|
||||||
*outbytes = (unsigned char *)malloc(buffer.size() + 1);
|
|
||||||
std::copy(buffer.begin(), buffer.end(), *outbytes);
|
|
||||||
*(*outbytes + buffer.size()) = '\0';
|
|
||||||
|
|
||||||
delete response;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Ebyroid::Speech(const unsigned char *inbytes,
|
int Ebyroid::Speech(const char *inbytes, std::vector<int16_t> &output, uint32_t mode)
|
||||||
int16_t **outbytes,
|
|
||||||
size_t *outsize,
|
|
||||||
uint32_t mode)
|
|
||||||
{
|
{
|
||||||
Response *const response = new Response(api_adapter_);
|
Response<int16_t> response{api_adapter_};
|
||||||
|
|
||||||
TJobParam param;
|
TJobParam param;
|
||||||
param.mode_in_out = mode == 0u ? IOMODE_AIKANA_TO_WAVE : (JobInOut)mode;
|
param.mode_in_out = mode == 0u ? IOMODE_AIKANA_TO_WAVE : (JobInOut)mode;
|
||||||
param.user_data = response;
|
param.user_data = &response;
|
||||||
|
|
||||||
char eventname[32];
|
|
||||||
sprintf(eventname, "TTSLOCK:%p", response);
|
|
||||||
HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventname);
|
|
||||||
|
|
||||||
int32_t job_id;
|
int32_t job_id;
|
||||||
ResultCode result = api_adapter_->TextToSpeech(&job_id, ¶m, (const char *)inbytes);
|
ResultCode result = api_adapter_->TextToSpeech(&job_id, ¶m, inbytes);
|
||||||
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete response;
|
|
||||||
ResetEvent(event);
|
|
||||||
CloseHandle(event);
|
|
||||||
static const char *format = "TextToSpeech failed with the result code %d\n"
|
static const char *format = "TextToSpeech failed with the result code %d\n"
|
||||||
"Given inbytes: %s";
|
"Given inbytes: %s";
|
||||||
char m[0xFFFF];
|
char m[0xFFFF];
|
||||||
@ -117,49 +86,21 @@ namespace ebyroid
|
|||||||
throw std::runtime_error(m);
|
throw std::runtime_error(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForSingleObject(event, INFINITE);
|
WaitForSingleObject(response.event, INFINITE);
|
||||||
ResetEvent(event);
|
|
||||||
CloseHandle(event);
|
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
result = api_adapter_->CloseSpeech(job_id);
|
result = api_adapter_->CloseSpeech(job_id);
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete response;
|
|
||||||
throw std::runtime_error("wtf");
|
throw std::runtime_error("wtf");
|
||||||
}
|
}
|
||||||
|
|
||||||
// write to output memory
|
// write to output memory
|
||||||
vector<int16_t> buffer = response->End16();
|
output = response.End();
|
||||||
*outsize = buffer.size() * 2; // sizeof(int16_t) == 2
|
|
||||||
*outbytes = (int16_t *)malloc(buffer.size() * 2 + 1);
|
|
||||||
std::copy(buffer.begin(), buffer.end(), *outbytes);
|
|
||||||
*((char *)*outbytes + (buffer.size() * 2)) = '\0';
|
|
||||||
|
|
||||||
delete response;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::Write(char *bytes, uint32_t size)
|
|
||||||
{
|
|
||||||
buffer_.insert(std::end(buffer_), bytes, bytes + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Response::Write16(int16_t *shorts, uint32_t size)
|
|
||||||
{
|
|
||||||
buffer_16_.insert(std::end(buffer_16_), shorts, shorts + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<unsigned char> Response::End()
|
|
||||||
{
|
|
||||||
return std::move(buffer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<int16_t> Response::End16()
|
|
||||||
{
|
|
||||||
return std::move(buffer_16_);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -167,8 +108,7 @@ namespace ebyroid
|
|||||||
{
|
{
|
||||||
SettingsBuilder builder(base_dir, voice);
|
SettingsBuilder builder(base_dir, voice);
|
||||||
Settings settings = builder.Build();
|
Settings settings = builder.Build();
|
||||||
|
std::unique_ptr<ApiAdapter> adapter{ApiAdapter::Create(dllpath.c_str())};
|
||||||
ApiAdapter *adapter = ApiAdapter::Create(dllpath.c_str());
|
|
||||||
|
|
||||||
TConfig config;
|
TConfig config;
|
||||||
config.hz_voice_db = settings.frequency;
|
config.hz_voice_db = settings.frequency;
|
||||||
@ -184,39 +124,17 @@ namespace ebyroid
|
|||||||
config.code_auth_seed = "PROJECT-VOICeVIO-SFE";
|
config.code_auth_seed = "PROJECT-VOICeVIO-SFE";
|
||||||
result = adapter->Init(&config);
|
result = adapter->Init(&config);
|
||||||
}
|
}
|
||||||
printf("init %d\n", result);
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete adapter;
|
|
||||||
string message = "API initialization failed with code ";
|
string message = "API initialization failed with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
/*pair<bool, string>xx = WithDirecory(settings.base_dir, [adapter, settings]() {
|
|
||||||
ResultCode result = adapter->LangLoad(settings.language_dir);
|
|
||||||
printf("laod lang %d\n", result);
|
|
||||||
if (result != ERR_SUCCESS) {
|
|
||||||
char m[64];
|
|
||||||
std::snprintf(m, 64, "API LangLoad failed (could not load language) with code %d", result);
|
|
||||||
return pair<bool, string>(true, string(m));
|
|
||||||
}
|
|
||||||
return pair<bool, string>(false, string());
|
|
||||||
});*/
|
|
||||||
bool x = SetCurrentDirectoryA(settings.base_dir);
|
|
||||||
SetDllDirectoryA(settings.base_dir);
|
SetDllDirectoryA(settings.base_dir);
|
||||||
printf("%d\n", x);
|
|
||||||
wchar_t buffer[1000] = {0};
|
|
||||||
DWORD sz = 1000;
|
|
||||||
GetCurrentDirectoryW(sz, buffer);
|
|
||||||
wprintf(L"%s\n", buffer);
|
|
||||||
result = adapter->LangLoad(settings.language_dir);
|
result = adapter->LangLoad(settings.language_dir);
|
||||||
printf("%s %s \n", settings.base_dir, settings.language_dir);
|
|
||||||
printf("loadvoice %d\n", result);
|
|
||||||
result = adapter->VoiceLoad(settings.voice_name);
|
result = adapter->VoiceLoad(settings.voice_name);
|
||||||
printf("loadvoice %s %d\n", settings.voice_name, result);
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete adapter;
|
|
||||||
string message = "API Load Voice failed (Could not load voice data) with code ";
|
string message = "API Load Voice failed (Could not load voice data) with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
@ -225,96 +143,73 @@ namespace ebyroid
|
|||||||
result = adapter->GetParam((void *)0, ¶m_size);
|
result = adapter->GetParam((void *)0, ¶m_size);
|
||||||
if (result != ERR_INSUFFICIENT)
|
if (result != ERR_INSUFFICIENT)
|
||||||
{ // NOTE: Code -20 is expected here
|
{ // NOTE: Code -20 is expected here
|
||||||
delete adapter;
|
|
||||||
string message = "API Get Param failed (Could not acquire the size) with code ";
|
string message = "API Get Param failed (Could not acquire the size) with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
|
if (param_size == sizeof(TTtsParam))
|
||||||
printf("param->size %d\n", param_size);
|
|
||||||
if (param_size == 500)
|
|
||||||
{ // voiceroid2
|
{ // voiceroid2
|
||||||
char *param_buffer = new char[param_size];
|
TTtsParam param;
|
||||||
TTtsParam *param = (TTtsParam *)param_buffer;
|
|
||||||
// TTtsParam* param = (TTtsParam*) param_buffer;
|
// TTtsParam* param = (TTtsParam*) param_buffer;
|
||||||
param->size = param_size;
|
param.size = param_size;
|
||||||
result = adapter->GetParam(param, ¶m_size);
|
result = adapter->GetParam(¶m, ¶m_size);
|
||||||
printf("%s %d\n", "GetParam", result);
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete[] param_buffer;
|
|
||||||
delete adapter;
|
|
||||||
string message = "API Get Param failed with code ";
|
string message = "API Get Param failed with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
param->extend_format = BOTH;
|
param.extend_format = BOTH;
|
||||||
param->proc_text_buf = HiraganaCallback;
|
param.proc_text_buf = HiraganaCallback;
|
||||||
param->proc_raw_buf = SpeechCallback;
|
param.proc_raw_buf = SpeechCallback;
|
||||||
param->proc_event_tts = nullptr;
|
param.proc_event_tts = nullptr;
|
||||||
param->len_raw_buf_bytes = kConfigRawbufSize;
|
param.len_raw_buf_bytes = kConfigRawbufSize;
|
||||||
|
|
||||||
param->volume = volume;
|
param.volume = volume;
|
||||||
printf("1\n");
|
param.speaker[0].volume = volume;
|
||||||
param->speaker[0].volume = volume;
|
/*param.speaker[0].pitch = 1.111;
|
||||||
/*param->speaker[0].pitch = 1.111;
|
param.speaker[0].pause_middle = 80;
|
||||||
param->speaker[0].pause_middle = 80;
|
param.speaker[0].pause_sentence = 200;
|
||||||
param->speaker[0].pause_sentence = 200;
|
param.speaker[0].pause_long = 100;
|
||||||
param->speaker[0].pause_long = 100;
|
param.speaker[0].range = 0.893;*/
|
||||||
param->speaker[0].range = 0.893;*/
|
param.speaker[0].speed = speed;
|
||||||
param->speaker[0].speed = speed;
|
result = adapter->SetParam(¶m);
|
||||||
//printf("2 %d %d\n", volume, speed);
|
|
||||||
result = adapter->SetParam(param);
|
|
||||||
printf("3 %d\n", result);
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete[] param_buffer;
|
|
||||||
delete adapter;
|
|
||||||
string message = "API Set Param failed with code ";
|
string message = "API Set Param failed with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
printf("3\n");
|
|
||||||
delete[] param_buffer;
|
|
||||||
}
|
}
|
||||||
else if (param_size == 416)
|
else if (param_size == sizeof(AITalk_TTtsParam))
|
||||||
{ // voiceroid+
|
{ // voiceroid+
|
||||||
char *param_buffer = new char[param_size];
|
AITalk_TTtsParam param;
|
||||||
AITalk_TTtsParam *param = (AITalk_TTtsParam *)param_buffer;
|
|
||||||
// TTtsParam* param = (TTtsParam*) param_buffer;
|
// TTtsParam* param = (TTtsParam*) param_buffer;
|
||||||
param->size = param_size;
|
param.size = param_size;
|
||||||
result = adapter->GetParam(param, ¶m_size);
|
result = adapter->GetParam(¶m, ¶m_size);
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete[] param_buffer;
|
|
||||||
delete adapter;
|
|
||||||
string message = "API Get Param failed with code ";
|
string message = "API Get Param failed with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
printf("numSpeakers %d\n", param->numSpeakers);
|
param.proc_text_buf = HiraganaCallback;
|
||||||
param->proc_text_buf = HiraganaCallback;
|
param.proc_raw_buf = SpeechCallback;
|
||||||
param->proc_raw_buf = SpeechCallback;
|
param.proc_event_tts = nullptr;
|
||||||
param->proc_event_tts = nullptr;
|
param.lenRawBufBytes = kConfigRawbufSize;
|
||||||
param->lenRawBufBytes = kConfigRawbufSize;
|
|
||||||
|
|
||||||
param->volume = volume;
|
param.volume = volume;
|
||||||
result = adapter->SetParam(param);
|
result = adapter->SetParam(¶m);
|
||||||
printf("SetParam ok %d\n", result);
|
|
||||||
if (result != ERR_SUCCESS)
|
if (result != ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
delete[] param_buffer;
|
|
||||||
delete adapter;
|
|
||||||
string message = "API Set Param failed with code ";
|
string message = "API Set Param failed with code ";
|
||||||
message += std::to_string(result);
|
message += std::to_string(result);
|
||||||
printf("%s\n", message.c_str());
|
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
}
|
}
|
||||||
delete[] param_buffer;
|
|
||||||
}
|
}
|
||||||
|
auto _ = adapter.get();
|
||||||
printf("%s \n", "setparam all ok");
|
adapter.release();
|
||||||
return adapter;
|
return _;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline pair<bool, string> WithDirecory(const char *dir, function<pair<bool, string>(void)> yield)
|
inline pair<bool, string> WithDirecory(const char *dir, function<pair<bool, string>(void)> yield)
|
||||||
@ -360,7 +255,7 @@ namespace ebyroid
|
|||||||
}
|
}
|
||||||
int __stdcall HiraganaCallback(EventReasonCode reason_code, int32_t job_id, IntPtr user_data)
|
int __stdcall HiraganaCallback(EventReasonCode reason_code, int32_t job_id, IntPtr user_data)
|
||||||
{
|
{
|
||||||
Response *const response = (Response *)user_data;
|
auto response = (Response<char> *)user_data;
|
||||||
ApiAdapter *api_adapter = response->api_adapter();
|
ApiAdapter *api_adapter = response->api_adapter();
|
||||||
|
|
||||||
if (reason_code != TEXTBUF_FULL && reason_code != TEXTBUF_FLUSH && reason_code != TEXTBUF_CLOSE)
|
if (reason_code != TEXTBUF_FULL && reason_code != TEXTBUF_FLUSH && reason_code != TEXTBUF_CLOSE)
|
||||||
@ -370,7 +265,7 @@ namespace ebyroid
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int kBufferSize = 0x1000;
|
static constexpr int kBufferSize = 0x1000;
|
||||||
char *buffer = new char[kBufferSize];
|
char buffer[kBufferSize];
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
uint32_t size, pos;
|
uint32_t size, pos;
|
||||||
@ -386,14 +281,10 @@ namespace ebyroid
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
if (reason_code == TEXTBUF_CLOSE)
|
if (reason_code == TEXTBUF_CLOSE)
|
||||||
{
|
{
|
||||||
char eventname[32];
|
response->event.Set();
|
||||||
sprintf(eventname, "TTKLOCK:%p", response);
|
|
||||||
HANDLE event = OpenEventA(EVENT_ALL_ACCESS, FALSE, eventname);
|
|
||||||
SetEvent(event);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -403,7 +294,7 @@ namespace ebyroid
|
|||||||
uint64_t tick,
|
uint64_t tick,
|
||||||
IntPtr user_data)
|
IntPtr user_data)
|
||||||
{
|
{
|
||||||
Response *const response = (Response *)user_data;
|
auto response = (Response<int16_t> *)user_data;
|
||||||
ApiAdapter *api_adapter = response->api_adapter();
|
ApiAdapter *api_adapter = response->api_adapter();
|
||||||
|
|
||||||
if (reason_code != RAWBUF_FULL && reason_code != RAWBUF_FLUSH && reason_code != RAWBUF_CLOSE)
|
if (reason_code != RAWBUF_FULL && reason_code != RAWBUF_FLUSH && reason_code != RAWBUF_CLOSE)
|
||||||
@ -413,7 +304,7 @@ namespace ebyroid
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int kBufferSize = 0xFFFF;
|
static constexpr int kBufferSize = 0xFFFF;
|
||||||
int16_t *buffer = new int16_t[kBufferSize];
|
int16_t buffer[kBufferSize];
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
uint32_t size, pos;
|
uint32_t size, pos;
|
||||||
@ -422,20 +313,16 @@ namespace ebyroid
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
response->Write16(buffer, size);
|
response->Write(buffer, size);
|
||||||
if (kBufferSize > size)
|
if (kBufferSize > size)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
if (reason_code == RAWBUF_CLOSE)
|
if (reason_code == RAWBUF_CLOSE)
|
||||||
{
|
{
|
||||||
char eventname[32];
|
response->event.Set();
|
||||||
sprintf(eventname, "TTSLOCK:%p", response);
|
|
||||||
HANDLE event = OpenEventA(EVENT_ALL_ACCESS, FALSE, eventname);
|
|
||||||
SetEvent(event);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef EBYROID_H
|
#ifndef EBYROID_H
|
||||||
#define EBYROID_H
|
#define EBYROID_H
|
||||||
|
|
||||||
|
|
||||||
namespace ebyroid
|
namespace ebyroid
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -24,8 +23,8 @@ namespace ebyroid
|
|||||||
~Ebyroid();
|
~Ebyroid();
|
||||||
|
|
||||||
static Ebyroid *Create(const std::string &base_dir, const std::string &dllpath, const std::string &voice, float volume, float speed);
|
static Ebyroid *Create(const std::string &base_dir, const std::string &dllpath, const std::string &voice, float volume, float speed);
|
||||||
int Hiragana(const unsigned char *inbytes, unsigned char **outbytes, size_t *outsize);
|
int Hiragana(const char *inbytes, std::vector<char> &);
|
||||||
int Speech(const unsigned char *inbytes, int16_t **outbytes, size_t *outsize, uint32_t mode = 0u);
|
int Speech(const char *inbytes, std::vector<int16_t> &, uint32_t mode = 0u);
|
||||||
int Convert(const ConvertParams ¶ms,
|
int Convert(const ConvertParams ¶ms,
|
||||||
const unsigned char *inbytes,
|
const unsigned char *inbytes,
|
||||||
int16_t **outbytes,
|
int16_t **outbytes,
|
||||||
@ -36,20 +35,27 @@ namespace ebyroid
|
|||||||
ApiAdapter *api_adapter_;
|
ApiAdapter *api_adapter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
class Response
|
class Response
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Response(ApiAdapter *adapter) : api_adapter_(adapter) {}
|
Response(ApiAdapter *adapter) : api_adapter_(adapter)
|
||||||
void Write(char *bytes, uint32_t size);
|
{
|
||||||
void Write16(int16_t *shorts, uint32_t size);
|
event.Create(NULL, FALSE, FALSE, NULL);
|
||||||
std::vector<unsigned char> End();
|
}
|
||||||
std::vector<int16_t> End16();
|
void Write(T *bytes, size_t size)
|
||||||
|
{
|
||||||
|
buffer_.insert(std::end(buffer_), bytes, bytes + size);
|
||||||
|
}
|
||||||
|
std::vector<T> End()
|
||||||
|
{
|
||||||
|
return std::move(buffer_);
|
||||||
|
}
|
||||||
ApiAdapter *api_adapter() { return api_adapter_; };
|
ApiAdapter *api_adapter() { return api_adapter_; };
|
||||||
|
CEvent event;
|
||||||
private:
|
private:
|
||||||
ApiAdapter *api_adapter_;
|
ApiAdapter *api_adapter_;
|
||||||
std::vector<unsigned char> buffer_;
|
std::vector<T> buffer_;
|
||||||
std::vector<int16_t> buffer_16_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ebyroid
|
} // namespace ebyroid
|
||||||
|
@ -28,14 +28,11 @@ int voiceroid2wmain(int argc, wchar_t *wargv[])
|
|||||||
SetEvent(CreateEventA(&allAccess, FALSE, FALSE, argv[4]));
|
SetEvent(CreateEventA(&allAccess, FALSE, FALSE, argv[4]));
|
||||||
ConnectNamedPipe(hPipe, NULL);
|
ConnectNamedPipe(hPipe, NULL);
|
||||||
int freq1;
|
int freq1;
|
||||||
unsigned char input_j[4096] = {0};
|
char input_j[4096] = {0};
|
||||||
DWORD _;
|
DWORD _;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ZeroMemory(input_j, sizeof(input_j));
|
ZeroMemory(input_j, sizeof(input_j));
|
||||||
unsigned char *out;
|
|
||||||
size_t output_size;
|
|
||||||
int16_t *out2;
|
|
||||||
|
|
||||||
if (!ReadFile(hPipe, input_j, 4096, &_, NULL))
|
if (!ReadFile(hPipe, input_j, 4096, &_, NULL))
|
||||||
break;
|
break;
|
||||||
@ -51,8 +48,8 @@ int voiceroid2wmain(int argc, wchar_t *wargv[])
|
|||||||
{
|
{
|
||||||
delete ebyroid;
|
delete ebyroid;
|
||||||
}
|
}
|
||||||
ebyroid = Ebyroid::Create((const char *)argv[1], //"C:\\dataH\\Yukari2",
|
ebyroid = Ebyroid::Create(argv[1], //"C:\\dataH\\Yukari2",
|
||||||
(const char *)argv[2],
|
argv[2],
|
||||||
voice.c_str(),
|
voice.c_str(),
|
||||||
2,
|
2,
|
||||||
rate); // 1); //0.1-2,0.5-4
|
rate); // 1); //0.1-2,0.5-4
|
||||||
@ -65,10 +62,12 @@ int voiceroid2wmain(int argc, wchar_t *wargv[])
|
|||||||
freq1 = 44100;
|
freq1 = 44100;
|
||||||
else
|
else
|
||||||
freq1 = 22050;
|
freq1 = 22050;
|
||||||
// int result = ebyroid->Hiragana((const unsigned char*)UnicodeToShift_jis(input), &out, &output_size);
|
std::vector<char> output;
|
||||||
int result = ebyroid->Hiragana((const unsigned char *)input_j, &out, &output_size);
|
int result = ebyroid->Hiragana(input_j, output);
|
||||||
|
output.push_back(0);
|
||||||
result = ebyroid->Speech(out, &out2, &output_size);
|
std::vector<int16_t> binary;
|
||||||
|
result = ebyroid->Speech(output.data(), binary);
|
||||||
|
size_t output_size = binary.size() * 2;
|
||||||
int fsize = output_size + 44;
|
int fsize = output_size + 44;
|
||||||
if (fsize > 1024 * 1024 * 10)
|
if (fsize > 1024 * 1024 * 10)
|
||||||
{
|
{
|
||||||
@ -98,12 +97,9 @@ int voiceroid2wmain(int argc, wchar_t *wargv[])
|
|||||||
ptr += 4;
|
ptr += 4;
|
||||||
memcpy(mapview + ptr, &output_size, 4);
|
memcpy(mapview + ptr, &output_size, 4);
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
memcpy(mapview + ptr, out2, output_size);
|
memcpy(mapview + ptr, binary.data(), output_size);
|
||||||
}
|
}
|
||||||
WriteFile(hPipe, &fsize, 4, &_, NULL);
|
WriteFile(hPipe, &fsize, 4, &_, NULL);
|
||||||
|
|
||||||
free(out);
|
|
||||||
free(out2);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -26,18 +26,20 @@ DECLARE_API void showintab(HWND hwnd, bool show, bool tool)
|
|||||||
|
|
||||||
DECLARE_API bool pid_running(DWORD pid)
|
DECLARE_API bool pid_running(DWORD pid)
|
||||||
{
|
{
|
||||||
DWORD code;
|
CHandle hprocess{OpenProcess(
|
||||||
#ifndef WINXP
|
#ifndef WINXP
|
||||||
GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)), &code);
|
PROCESS_QUERY_LIMITED_INFORMATION,
|
||||||
#else
|
#else
|
||||||
GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)), &code);
|
PROCESS_QUERY_INFORMATION,
|
||||||
#endif
|
#endif
|
||||||
|
FALSE, pid)};
|
||||||
|
if (!hprocess)
|
||||||
|
return false;
|
||||||
|
DWORD code;
|
||||||
|
GetExitCodeProcess(hprocess, &code);
|
||||||
// 句柄必須具有 PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION 訪問許可權。 如需詳細資訊,請參閱 處理安全性和訪問許可權。
|
// 句柄必須具有 PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION 訪問許可權。 如需詳細資訊,請參閱 處理安全性和訪問許可權。
|
||||||
// Windows Server 2003 和 Windows XP: 句柄必須具有 PROCESS_QUERY_INFORMATION 訪問許可權。
|
// Windows Server 2003 和 Windows XP: 句柄必須具有 PROCESS_QUERY_INFORMATION 訪問許可權。
|
||||||
return code == STILL_ACTIVE;
|
return code == STILL_ACTIVE;
|
||||||
// auto process = AutoHandle(OpenProcess(SYNCHRONIZE, FALSE, pid));
|
|
||||||
// DWORD ret = WaitForSingleObject(process, 0);
|
|
||||||
// return ret == WAIT_TIMEOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct __EnumWindowsProc
|
struct __EnumWindowsProc
|
||||||
@ -79,11 +81,13 @@ DECLARE_API bool Is64bit(DWORD pid)
|
|||||||
{
|
{
|
||||||
if (!Is64BitOS())
|
if (!Is64BitOS())
|
||||||
return false;
|
return false;
|
||||||
|
CHandle hprocess{OpenProcess(
|
||||||
#ifndef WINXP
|
#ifndef WINXP
|
||||||
auto hprocess = AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
|
PROCESS_QUERY_LIMITED_INFORMATION,
|
||||||
#else
|
#else
|
||||||
auto hprocess = AutoHandle(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid));
|
PROCESS_QUERY_INFORMATION,
|
||||||
#endif
|
#endif
|
||||||
|
FALSE, pid)};
|
||||||
// 進程的控制碼。 控制碼必須具有PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION存取權限。 如需詳細資訊,請參閱 處理安全性和存取權限。
|
// 進程的控制碼。 控制碼必須具有PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION存取權限。 如需詳細資訊,請參閱 處理安全性和存取權限。
|
||||||
// Windows Server 2003 和 Windows XP: 控制碼必須具有PROCESS_QUERY_INFORMATION存取權限。
|
// Windows Server 2003 和 Windows XP: 控制碼必須具有PROCESS_QUERY_INFORMATION存取權限。
|
||||||
BOOL f64bitProc = false;
|
BOOL f64bitProc = false;
|
||||||
@ -94,7 +98,7 @@ DECLARE_API bool Is64bit(DWORD pid)
|
|||||||
DECLARE_API void getprocesses(void (*cb)(DWORD, const wchar_t *))
|
DECLARE_API void getprocesses(void (*cb)(DWORD, const wchar_t *))
|
||||||
{
|
{
|
||||||
std::unordered_map<std::wstring, std::vector<int>> exe_pid;
|
std::unordered_map<std::wstring, std::vector<int>> exe_pid;
|
||||||
AutoHandle hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
CHandle hSnapshot{CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)};
|
||||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user