У меня проблема с использованием значений из возвращенной структуры GetAdaptersInfo. Он возвращает структуру IP_ADAPTER_INFO (https://docs.microsoft.com/de-de/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info), из которой я беру некоторые значения в пользовательскую структуру.
Минимальный воспроизводимый пример:
#include <winsock2.h>
#include <iphlpapi.h>
#include <vector>
#pragma comment(lib, "IPHLPAPI.lib")
struct Adapter_Info {
DWORD ComboIndex;
char* AdapterName;
WCHAR* AdapterFriendlyName;
char* Description;
DWORD Index;
char AdapterAddress;
char* Type;
char* CurrentIpAddress;
IP_ADDR_STRING IpAddressList;
char* GatewayList;
bool DhcpServerStatus;
char* DhcpServerStatusChar;
char* DhcpServer;
};
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
int main(std::vector<Adapter_Info>* p_retrieved_adapters, int* p_number_of_adapters)
{
//creating returning vector and number_of_adapters
std::vector<Adapter_Info> retrieved_adapters;
int number_of_adapters = 0;
/* Declare and initialize variables */
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO*)MALLOC(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return 1;
}
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO*)MALLOC(ulOutBufLen);
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return 1;
}
}
//call GetAdaptersInfo for counting number of adapters
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
//count number of adapters
while (pAdapter) {
number_of_adapters++;
pAdapter = pAdapter->Next;
}
}
else {
printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);
}
//call GetAdaptersInfo again and retrieving the information for every adapter
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
//retrieve info for every adapter
while (pAdapter) {
Adapter_Info temp_adapter_info;
temp_adapter_info.ComboIndex = pAdapter->ComboIndex;
temp_adapter_info.AdapterName = pAdapter->AdapterName;
//for testing purposes
printf("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
printf("\tAdapter Name: \t%s\n", temp_adapter_info.AdapterName);
temp_adapter_info.Description = pAdapter->Description;
//for testing purposes
printf("\tAdapter Desc: \t%s\n", pAdapter->Description);
printf("\tAdapter Desc: \t%s\n", temp_adapter_info.Description);
temp_adapter_info.Index = pAdapter->Index;
retrieved_adapters.push_back(temp_adapter_info);
pAdapter = pAdapter->Next;
}
}
else {
printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);
}
*p_retrieved_adapters = retrieved_adapters;
*p_number_of_adapters = number_of_adapters;
//free memory
if (pAdapterInfo)
FREE(pAdapterInfo);
if (pAddresses) {
FREE(pAddresses);
}
return 0;
}
Использование main () в Form1.h:
std::vector<Adapter_Info> retrieved_adapters;
std::vector<Adapter_Info>* p_retrieved_adapters = &retrieved_adapters;;
int number_of_adapters;
int* p_number_of_adapters = &number_of_adapters;
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
main(p_retrieved_adapters, p_number_of_adapters);
for (int xr = 0; xr < number_of_adapters; xr++) {
printf("\tAdapter Name: \t%s\n", retrieved_adapters[xr].AdapterName);
printf("\tAdapter Desc: \t%s\n", retrieved_adapters[xr].Description);
}
String^ str0_0 = WcharToSysString(retrieved_adapters[0].AdapterFriendlyName);
String^ str0_2 = CharToSysString(retrieved_adapters[0].Description);
}
Чтобы отобразить эти значения в метках с winforms, мне нужно преобразовать их в System :: String ^. Для этих целей я создал несколько функций преобразования.
//wchar_t* to char
char* WcharToChar(wchar_t* wcharStr)
{
// Create a string of wide characters, display it, and then
// use this string to create other types of strings.
wchar_t* orig = wcharStr;
std::wcout << orig << _T(" (wchar_t *)") << std::endl;
// Convert the wchar_t string to a char* string. Record
// the length of the original string and add 1 to it to
// account for the terminating null character.
size_t origsize = wcslen(orig) + 1;
size_t convertedChars = 0;
// Use a multibyte string to append the type of string
// to the new string before displaying the result.
char strConcat[] = " (char *)";
size_t strConcatsize = (strlen(strConcat) + 1) * 2;
// Allocate two bytes in the multibyte output string for every wide
// character in the input string (including a wide character
// null). Because a multibyte character can be one or two bytes,
// you should allot two bytes for each character. Having extra
// space for the new string is not an error, but having
// insufficient space is a potential security problem.
const size_t newsize = origsize * 2;
// The new string will contain a converted copy of the original
// string plus the type of string appended to it.
char* nstring = new char[newsize + strConcatsize];
// Put a copy of the converted string into nstring
wcstombs_s(&convertedChars, nstring, newsize, orig, _TRUNCATE);
// append the type of string to the new string.
//_mbscat_s((unsigned char*)nstring, newsize + strConcatsize, (unsigned char*)strConcat);
// Display the result.
std::cout << nstring << std::endl;
return nstring;
}
//wchar_t* to std::string
std::string WcharToStdStr(const wchar_t* s, char dfault, const std::locale& loc)
{
std::ostringstream stm;
while (*s != L'\0') { //EV. HIER FEHLER
stm << std::use_facet< std::ctype<wchar_t> >(loc).narrow(*s++, dfault);
}
return stm.str();
}
//char* to std::string
std::string CharToStdStr(char* charStr)
{
std::string stdStr(charStr);
return stdStr;
}
//std::string to System::String^
System::String^ StdStrToSysString(std::string stdStr)
{
System::String^ sysStr = gcnew System::String(stdStr.c_str());
return sysStr;
}
//wchar_t* to System::String^
System::String^ WcharToSysString(const wchar_t* wcharStr)
{
System::String^ sysStr = gcnew System::String(WcharToStdStr(wcharStr).c_str());
return sysStr;
}
//char* to System::String^
System::String^ CharToSysString(char* charStr)
{
System::String^ sysStr = gcnew System::String(CharToStdStr(charStr).c_str());
return sysStr;
}
Иногда эти функции вообще не работают. В некоторых случаях они не работают с первой попытки, а затем начинают работать после еще одного вызова функции GetAdaptersInfo.
У меня проблемы только с AdapterFriendlyName
и Description
из моей пользовательской структуры.
Буду признателен за любую подсказку (особенно, если есть лучший способ управлять этими значениями, отображать их с помощью Winforms, не преобразовывая их).