И снова проблема со строками (юникод).
Как известно в c# объект System.String содержит unicode строку. При передаче параметров строк в c++-cli, мне необходимо перекодировать данную строку в мульти-байтовую кодировку, без потери данных. Я просто не понимаю как сделать это правильно дабы открыть в libvlc файл который содержит unicode символы как в пути, так и в названии файла?
При вызове Marshal::StringToHGlobalAnsi(file_location); все символы не поддерживающиеся char* передаются как вопросы.
При этом libvlc отдает ошибку как unknown error, а в консоли видно что он пытается открыть файл как c:/path/to/???.mp3
void vlc_media::open_file(String ^ file_location) {
release_media();
const char* vlc_error;
IntPtr tmpPtr = Marshal::StringToHGlobalAnsi(file_location);
char* file_loc = reinterpret_cast<char*>(tmpPtr.ToPointer());
libvlc_media_t* tmpmptr = libvlc_media_new_path(&m_instance_, file_loc);
if(!tmpmptr)
{
vlc_error = libvlc_errmsg();
Marshal::FreeHGlobal(tmpPtr);
throw gcnew Exception(gcnew String(vlc_error));
}
m_media_ = IntPtr(tmpmptr);
Marshal::FreeHGlobal(tmpPtr);
}
Я надеюсь, что VLC умеет принимать широкие строки. (Это скорее всего так, поскольку файловая система у Windows юникодная.) Вам понядобятся заголовки для маршаллирования.
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace msclr::interop;
using namespace System;
В этом случае ваш код будет выглядеть так:
String^ managed = L"привет мир";
std::wstring utf16 = marshal_as<std::wstring>(managed);
Если вам нужно utf-8, то тоже несложно:
String^ managed = L"привет мир";
array<Byte>^ managedBytesUtf8 = Text::Encoding::UTF8->GetBytes(managed);
pin_ptr<Byte> nativeBytesUtf8 = &managedBytesUtf8[0];
std::string utf8((char*)nativeBytesUtf8, managedBytesUtf8->Length);
Прибегнул к такому решению, работает на ура:
#pragma once
#include <Windows.h>
using namespace System;
namespace yami {
namespace vlc {
ref class vlc_string {
private:
char* m_value;
HRESULT __fastcall UnicodeToAnsi(LPCOLESTR pszW, LPSTR* ppszA);
public:
vlc_string(String^ string);
~vlc_string();
static char* operator &(vlc_string^ vlc_str);
};
}
}
#include "stdafx.h"
#include "vlc_string.h"
namespace yami {
namespace vlc {
HRESULT vlc_string::UnicodeToAnsi(LPCOLESTR pszW, LPSTR * ppszA) {
ULONG cbAnsi, cCharacters;
DWORD dwError;
if (pszW == NULL)
{
*ppszA = NULL;
return NOERROR;
}
cCharacters = wcslen(pszW) + 1;
cbAnsi = cCharacters * 2;
*ppszA = reinterpret_cast<char*>(malloc(cbAnsi));
if (NULL == *ppszA)
return E_OUTOFMEMORY;
if (0 == WideCharToMultiByte(CP_UTF8, 0, pszW, cCharacters, *ppszA,
cbAnsi, NULL, NULL))
{
dwError = GetLastError();
free(*ppszA);
*ppszA = NULL;
return HRESULT_FROM_WIN32(dwError);
}
return NOERROR;
}
vlc_string::vlc_string(String^ string) : m_value(nullptr) {
IntPtr tmpPtr = System::Runtime::InteropServices::Marshal::StringToHGlobalUni(string);
wchar_t* buffer = reinterpret_cast<wchar_t*>(tmpPtr.ToPointer());
char* tmp;
HRESULT result = UnicodeToAnsi(buffer, &tmp);
if(FAILED(result))
{
throw gcnew System::Runtime::InteropServices::COMException("Failed to convert String to vlc_string");
}
m_value = new char[strlen(tmp)];
strcpy(m_value, tmp);
free(tmp); // чуть не забыл освободить.
System::Runtime::InteropServices::Marshal::FreeHGlobal(tmpPtr);
}
char* vlc_string::operator&(vlc_string ^ value) {
// используем reinterpret_cast т.к. в классе лежит interop_ptr, а не нативный указатель
return reinterpret_cast<char*>(value->m_value);
}
vlc_string::~vlc_string() {
if(m_value)
free(m_value);
}
}
}
Использование:
void vlc_media::open_file(String ^ file_location) {
release_media();
const char* vlc_error;
vlc_string^ path = gcnew vlc_string(file_location);
libvlc_media_t* tmpmptr = libvlc_media_new_path(&m_instance_, &path);
if (!tmpmptr)
{
vlc_error = libvlc_errmsg();
delete path;
throw gcnew Exception(gcnew String(vlc_error));
}
m_media_ = IntPtr(tmpmptr);
delete path;
}
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники