Fixing memory violations

This commit is contained in:
Caelan Sayler
2024-10-20 00:06:38 +01:00
committed by Caelan
parent 49c2cc265e
commit b2e58e6142
7 changed files with 76 additions and 49 deletions

View File

@@ -25,7 +25,7 @@ HINSTANCE hInst;
const WCHAR szTitle[] = L"Velopack C++ Sample App";
const WCHAR szWindowClass[] = L"VeloCppWinSample";
std::optional<UpdateManager> managerOpt = std::nullopt;
std::unique_ptr<UpdateManager> manager;
std::optional<UpdateInfo> updInfo = std::nullopt;
bool downloaded = false;
@@ -38,22 +38,36 @@ INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
std::wstring Utf8ToWString(std::string const& str);
std::string WStringToUtf8(std::wstring const& wstr);
void handle_vpkc_log(const char* pszLevel, const char* pszMessage)
{
std::cout << pszLevel << ": " << pszMessage << std::endl;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// Redirect StdOut to console window
AllocConsole();
FILE* fp;
_wfreopen_s(&fp, L"CONOUT$", L"w", stdout);
_wfreopen_s(&fp, L"CONOUT$", L"w", stderr);
_wfreopen_s(&fp, L"CONIN$", L"r", stdin);
// Initialize Velopack log capture
std::cout << "Velopack C++ Sample App" << std::endl;
UNREFERENCED_PARAMETER(hPrevInstance);
vpkc_set_log(handle_vpkc_log);
// This should run as early as possible in the main method.
// Velopack may exit / restart the app at this point.
// See VelopackApp class for more options/configuration.
VelopackApp::Build().Run();
VelopackApp::Build()
.Run();
try {
// If the app is not installed, creating an UpdateManager will throw an exception.
managerOpt = UpdateManager(UPDATE_URL);
manager = std::make_unique<UpdateManager>(UPDATE_URL);
}
catch (std::exception& e) {
std::wstring what = Utf8ToWString(e.what());
@@ -136,14 +150,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
{
if (LOWORD(wParam) == BN_CLICKED) {
if (!managerOpt.has_value()) {
break; // this should not happen because we construct UpdateManager in wWinMain
}
auto manager = managerOpt.value();
if ((HWND)lParam == hCheckButton) {
try {
updInfo = manager.CheckForUpdates();
updInfo = manager->CheckForUpdates();
if (updInfo.has_value()) {
std::string version = updInfo.value().TargetFullRelease.Version;
std::wstring message = L"Update available: " + Utf8ToWString(version);
@@ -161,7 +170,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
else if ((HWND)lParam == hDownloadButton) {
if (updInfo.has_value()) {
try {
manager.DownloadUpdates(updInfo.value());
manager->DownloadUpdates(updInfo.value());
downloaded = true;
MessageBoxCentered(hWnd, L"Download completed successfully.", szTitle, MB_OK);
}
@@ -179,7 +188,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
MessageBoxCentered(hWnd, L"Download an update first.", szTitle, MB_OK);
}
else {
manager.WaitExitThenApplyUpdate(updInfo.value());
manager->WaitExitThenApplyUpdate(updInfo.value());
exit(0);
}
}
@@ -192,10 +201,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
HDC hdc = BeginPaint(hWnd, &ps);
RECT r{ 0, 5, ps.rcPaint.right, ps.rcPaint.bottom };
std::string currentVersion = "Not Installed";
if (managerOpt.has_value()) {
currentVersion = managerOpt.value().GetCurrentVersion();
}
std::string currentVersion = manager->GetCurrentVersion();
auto ver = Utf8ToWString(currentVersion);
std::wstring text = L"Welcome to v" + ver + L" of the\nVelopack C++ Sample App.";
DrawText(hdc, text.c_str(), -1, &r, DT_BOTTOM | DT_CENTER);

View File

@@ -5,6 +5,12 @@ VisualStudioVersion = 17.8.34525.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VeloCppWinSample", "VeloCppWinSample.vcxproj", "{F9BB1F11-3827-4745-B11B-77FA5DBE1195}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{25F8ED9F-9255-4CEC-AE44-7F2EAA392C18}"
ProjectSection(SolutionItems) = preProject
build.bat = build.bat
readme.md = readme.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64

View File

@@ -13,9 +13,8 @@ if "%~1"=="" (
)
echo.
echo Building Velopack Rust
cd %~dp0..\..\..\for-rust
cargo build --features cli -r
echo Building Velopack C Lib with Cargo
cargo build -p velopack_libc
cd %~dp0
@@ -43,8 +42,6 @@ cd %~dp0
echo #define UPDATE_URL "REPLACE_ME" > constants.h
copy %~dp0..\..\..\for-rust\target\release\vfusion.exe x64\Debug
echo.
echo Building Velopack Release v%~1
vpk pack -u VeloCppWinSample -o releases -p x64\Debug -v %*
vpk pack -u VelopackCppWin32Sample -o releases -p x64\Debug -v %* -e VeloCppWinSample.exe

View File

@@ -1,5 +1,5 @@
# VeloCppWinSample
_Prerequisites: Rust/Cargo, Dotnet, Msbuild_
# VelopackCppWin32Sample
_Prerequisites: Rust/Cargo, Msbuild_
This app is purely a proof of concept at this time, `velopack.hpp` currently only works on windows and needs testing / fixes for other operating systems, and probably also needs fixing for unicode/strings. This sample is made up of a simple Win32 desktop app, generated via a Visual Studio template, and it includes `velopack.hpp` and [`subprocess.h`](https://github.com/sheredom/subprocess.h).

View File

@@ -48,7 +48,7 @@
extern "C" {
#endif
typedef void* vpkc_update_manager_t;
typedef void vpkc_update_manager_t;
typedef void (*vpkc_progress_callback_t)(size_t progress);
typedef void (*vpkc_log_callback_t)(const char* pszLevel, const char* pszMessage);
typedef void (*vpkc_hook_callback_t)(const char* pszAppVersion);
@@ -93,7 +93,7 @@ typedef struct {
// !! AUTO-GENERATED-END C_TYPES
// Update Manager
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, vpkc_update_options_t* pOptions, vpkc_locator_config_t* pLocator, vpkc_update_manager_t* pManager);
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, vpkc_update_options_t* pOptions, vpkc_locator_config_t* pLocator, vpkc_update_manager_t** pManager);
VPKC_EXPORT size_t VPKC_CALL vpkc_get_current_version(vpkc_update_manager_t* pManager, char* pszVersion, size_t cVersion);
VPKC_EXPORT size_t VPKC_CALL vpkc_get_app_id(vpkc_update_manager_t* pManager, char* pszId, size_t cId);
VPKC_EXPORT bool VPKC_CALL vpkc_is_portable(vpkc_update_manager_t* pManager);
@@ -330,7 +330,7 @@ public:
class UpdateManager {
private:
vpkc_update_manager_t m_pManager;
vpkc_update_manager_t* m_pManager = 0;
public:
UpdateManager(const std::string& urlOrPath, const UpdateOptions* options = nullptr, const VelopackLocatorConfig* locator = nullptr) {
vpkc_update_options_t* pOptions = nullptr;
@@ -345,31 +345,31 @@ public:
pLocator = &vpkc_locator;
}
if (0 != vpkc_new_update_manager(urlOrPath.c_str(), pOptions, pLocator, &m_pManager)) {
if (!vpkc_new_update_manager(urlOrPath.c_str(), pOptions, pLocator, &m_pManager)) {
throw_last_error();
}
};
~UpdateManager() {
vpkc_free_update_manager(&m_pManager);
vpkc_free_update_manager(m_pManager);
};
bool IsPortable() noexcept {
return vpkc_is_portable(&m_pManager);
return vpkc_is_portable(m_pManager);
};
std::string GetCurrentVersion() noexcept {
size_t neededSize = vpkc_get_current_version(&m_pManager, nullptr, 0);
size_t neededSize = vpkc_get_current_version(m_pManager, nullptr, 0);
std::string strVersion(neededSize, '\0');
vpkc_get_current_version(&m_pManager, &strVersion[0], neededSize);
vpkc_get_current_version(m_pManager, &strVersion[0], neededSize);
return strVersion;
};
std::string GetAppId() noexcept {
size_t neededSize = vpkc_get_app_id(&m_pManager, nullptr, 0);
size_t neededSize = vpkc_get_app_id(m_pManager, nullptr, 0);
std::string strId(neededSize, '\0');
vpkc_get_app_id(&m_pManager, &strId[0], neededSize);
vpkc_get_app_id(m_pManager, &strId[0], neededSize);
return strId;
};
std::optional<VelopackAsset> UpdatePendingRestart() noexcept {
vpkc_asset_t asset;
if (vpkc_update_pending_restart(&m_pManager, &asset)) {
if (vpkc_update_pending_restart(m_pManager, &asset)) {
VelopackAsset cpp_asset = to_cpp(asset);
vpkc_free_asset(&asset);
return cpp_asset;
@@ -378,7 +378,7 @@ public:
};
std::optional<UpdateInfo> CheckForUpdates() {
vpkc_update_info_t update;
vpkc_update_check_t result = vpkc_check_for_updates(&m_pManager, &update);
vpkc_update_check_t result = vpkc_check_for_updates(m_pManager, &update);
switch (result) {
case vpkc_update_check_t::UPDATE_ERROR:
throw_last_error();
@@ -394,7 +394,7 @@ public:
};
void DownloadUpdates(const UpdateInfo& update, vpkc_progress_callback_t progress = nullptr) {
vpkc_update_info_t vpkc_update = to_c(update);
if (!vpkc_download_updates(&m_pManager, &vpkc_update, progress)) {
if (!vpkc_download_updates(m_pManager, &vpkc_update, progress)) {
throw_last_error();
}
};
@@ -406,7 +406,7 @@ public:
}
vpkc_asset_t vpkc_asset = to_c(asset);
bool result = vpkc_wait_exit_then_apply_update(&m_pManager, &vpkc_asset, silent, restart, pRestartArgs, restartArgs.size());
bool result = vpkc_wait_exit_then_apply_update(m_pManager, &vpkc_asset, silent, restart, pRestartArgs, restartArgs.size());
// Free all the memory
for (size_t i = 0; i < restartArgs.size(); i++) {

View File

@@ -235,15 +235,20 @@ static inline void clear_last_error() {
}
// Update Manager
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, vpkc_update_options_t* pOptions, vpkc_locator_config_t* pLocator, vpkc_update_manager_t* pManager) {
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, vpkc_update_options_t* pOptions, vpkc_locator_config_t* pLocator, vpkc_update_manager_t** pManager) {
clear_last_error();
try {
if (pManager == nullptr) {
set_last_error("pManager cannot be null");
return false;
}
VelopackLocatorConfigDtoOption locator = to_bridge_opt(pLocator);
UpdateOptionsDtoOption options = to_bridge_opt(pOptions);
::rust::Box<::UpdateManagerOpaque> manager = bridge_new_update_manager(pszUrlOrString, options, locator);
UpdateManagerOpaque* pOpaque = manager.into_raw();
*pManager = pOpaque;
*pManager = reinterpret_cast<vpkc_update_manager_t*>(pOpaque);
return true;
} catch (const std::exception& e) {
set_last_error(e.what());
@@ -251,22 +256,22 @@ VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, v
}
}
VPKC_EXPORT size_t VPKC_CALL vpkc_get_current_version(vpkc_update_manager_t* pManager, char* pszVersion, size_t cVersion) {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
std::string version = (std::string)bridge_get_current_version(*pOpaque);
return return_c_string(version, pszVersion, cVersion);
}
VPKC_EXPORT size_t VPKC_CALL vpkc_get_app_id(vpkc_update_manager_t* pManager, char* pszId, size_t cId) {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
std::string id = (std::string)bridge_get_app_id(*pOpaque);
return return_c_string(id, pszId, cId);
}
VPKC_EXPORT bool VPKC_CALL vpkc_is_portable(vpkc_update_manager_t* pManager) {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
return bridge_is_portable(*pOpaque);
}
VPKC_EXPORT bool VPKC_CALL vpkc_update_pending_restart(vpkc_update_manager_t* pManager, vpkc_asset_t* pAsset) {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
VelopackAssetDtoOption asset = bridge_update_pending_restart(*pOpaque);
if (asset.has_data) {
allocate_velopackasset(asset.data, pAsset);
@@ -277,7 +282,7 @@ VPKC_EXPORT bool VPKC_CALL vpkc_update_pending_restart(vpkc_update_manager_t* pM
VPKC_EXPORT vpkc_update_check_t VPKC_CALL vpkc_check_for_updates(vpkc_update_manager_t* pManager, vpkc_update_info_t* pUpdate) {
clear_last_error();
try {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
UpdateInfoDtoOption update = bridge_check_for_updates(*pOpaque);
if (update.has_data) {
allocate_updateinfo(update.data, pUpdate);
@@ -298,7 +303,7 @@ VPKC_EXPORT bool VPKC_CALL vpkc_download_updates(vpkc_update_manager_t* pManager
return false;
}
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
UpdateInfoDto update = to_bridge(pUpdate);
DownloadCallbackManager download{};
@@ -319,7 +324,7 @@ VPKC_EXPORT bool VPKC_CALL vpkc_wait_exit_then_apply_update(vpkc_update_manager_
return false;
}
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
VelopackAssetDto asset = to_bridge(pAsset);
::rust::Vec<::rust::String> restartArgs{};
@@ -384,7 +389,7 @@ VPKC_EXPORT void VPKC_CALL vpkc_set_log(vpkc_log_callback_t cbLog) {
bridge_set_logger_callback(&logMgr);
}
VPKC_EXPORT void VPKC_CALL vpkc_free_update_manager(vpkc_update_manager_t* pManager) {
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(*pManager);
UpdateManagerOpaque* pOpaque = reinterpret_cast<UpdateManagerOpaque*>(pManager);
auto box = ::rust::Box<::UpdateManagerOpaque>::from_raw(pOpaque);
// this will free when the box goes out of scope
}

View File

@@ -144,6 +144,19 @@ struct UpdateManagerOpaque {
obj: UpdateManager,
}
impl UpdateManagerOpaque {
fn new(obj: UpdateManager) -> Self {
log::debug!("UpdateManagerOpaque allocated");
UpdateManagerOpaque { obj }
}
}
impl Drop for UpdateManagerOpaque {
fn drop(&mut self) {
log::debug!("UpdateManagerOpaque dropped");
}
}
fn bridge_new_update_manager(
url_or_path: &String,
options: &ffi::UpdateOptionsDtoOption,
@@ -153,7 +166,7 @@ fn bridge_new_update_manager(
let options = updateoptions_to_core_option(options);
let locator = velopacklocatorconfig_to_core_option(locator);
let update_manager = UpdateManager::new(source, options, locator)?;
Ok(Box::new(UpdateManagerOpaque { obj: update_manager }))
Ok(Box::new(UpdateManagerOpaque::new(update_manager)))
}
fn bridge_get_current_version(manager: &UpdateManagerOpaque) -> String {