После выделения памяти для параметра wchar_t*
и копирования строки в буфер при возврате из функции буфер не может быть прочитан. Согласно отладчику:
machineName 0xcccccccccccccccc <Error reading characters of string.> wchar_t *
учитывая следующий код
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
файл test.cpp ...
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
файл sysCertStore.h ...
#ifdef __cplusplus
extern "C"
{
// only need to export C interface if
// used by C++ source code
BOOL c_GetMachineName(wchar_t* machineName);
};
#endif
файл sysCertStore.cpp ...
BOOL c_GetMachineName(wchar_t* machineName) {
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1];
int i = 0;
LPWSTR infoBuf = new wchar_t[MAX_COMPUTERNAME_LENGTH + 1]; // = {'\0'};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
memset(Name, 0, MAX_COMPUTERNAME_LENGTH + 1);
if (GetComputerNameW(infoBuf, &bufCharCount))
{
for (i = 0; i < MAX_COMPUTERNAME_LENGTH + 1; i++)
{
Name[i] = infoBuf[i];
}
delete[] infoBuf;
INT strln= wcslen(Name)+1;
machineName = (wchar_t*)malloc(strln * sizeof(wchar_t)); // new wchar_t[strln];
wcscpy_s(machineName, strln, Name);
return TRUE;
} else
{
wcscpy_s(Name,7+1, L"Unknown");
return FALSE;
}
return FALSE;
}
Я ожидаю, что тест напечатает имя машины и освободит память выделенной строки/буфера, выделенной в функции c_GetMachineName
.
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
вам нужно либо вернуть machineName
, либо передать его как wchar_t** machineName
и *machineName = malloc(...)
. Все в C передается по значению, создаются копии каждого аргумента. Эти копии исчезают при выходе из функции, в оригинал не вносятся никакие изменения.
или я вижу, что вы тоже отметили C++... в этом случае вы также можете передать по ссылке
@yano, вы не можете передать ссылку в функцию C, потому что в C нет ссылок.
@MarkRansom, возможно, намерение состоит в том, чтобы c_GetMachineName
был только C, но он находится в файле .cpp и вызывает new
и delete[]
.. ? Я до сих пор не знаю, действительно ли компилятор MS различает C и C++.
0xcccccccccccccccc
означает неинициализированную стековую память: https://stackoverflow.com/questions/127386/what-are-the-debug-memory-fill-patterns-in-visual-studio-c-and- окнасделать machineName = (wchar_t*)malloc(strln * sizeof(wchar_t));
эквивалентно действию в функции int foo(int a) { a = 42; }
Параметр machineName
для c_GetMachineName()
передается по значению, поэтому переменная вызывающего объекта копируется, а c_GetMachineName()
вместо этого изменяет копию.
Локальная переменная machineName
, объявленная внутри вашего теста, не инициализирована (и, следовательно, установлена в 0xcccccccccccccccc
в режиме отладки), и c_GetMachineName()
не может изменить ее, чтобы она указывала на действительный адрес. Вот почему тест завершается с ошибкой при попытке чтения с неверного адреса 0xcccccccccccccccc
.
Чтобы сделать то, что вы пытаетесь, c_GetMachineName()
вместо этого необходимо принять свой параметр machineName
по указателю, чтобы он мог изменить переменную вызывающей стороны, чтобы она указывала на память, возвращаемую malloc()
.
Кроме того, ваша переменная infoBuf
избыточна и ее можно исключить. То же самое можно и с использованием wcslen()
, поскольку GetComputerNameW()
сообщает вам, сколько символов оно записывает в буфер.
Вместо этого попробуйте это:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(&machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
BOOL c_GetMachineName(wchar_t** machineName) {
if (!machineName)
return FALSE;
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1] = {};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(Name, &bufCharCount))
return FALSE;
++bufCharCount;
*machineName = (wchar_t*) malloc(bufCharCount * sizeof(wchar_t)); // new wchar_t[bufCharCount];
if (!*machineName)
return FALSE;
wcscpy_s(*machineName, bufCharCount, Name);
return TRUE;
/* or simpler:
*machineName = _wcsdup(Name);
return (*machineName != NULL);
*/
}
В качестве альтернативы вы можете просто return
вместо этого использовать указатель malloc
, например:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName = c_GetMachineName();
EXPECT_NE(machineName, nullptr);
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
wchar_t* c_GetMachineName() {
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1] = {};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(Name, &bufCharCount))
return NULL;
++bufCharCount;
wchar_t *machineName = (wchar_t*) malloc(bufCharCount * sizeof(wchar_t)); // new wchar_t[bufCharCount];
if (!machineName)
return NULL;
wcscpy_s(machineName, bufCharCount, Name);
return machineName;
/* or simpler:
return _wcsdup(Name);
*/
}
Или просто попросите вызывающую сторону выделить память, а c_GetMachineName()
просто заполнит ее, например:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t machineName[256];
EXPECT_TRUE(c_GetMachineName(machineName, 256));
setlocale(LC_ALL, "");
printf("%ls", machineName);
}
BOOL c_GetMachineName(wchar_t* machineName, DWORD maxLength) {
return GetComputerNameW(machineName, &maxLength))
}
СПАСИБО!!! Реми Лебо — отлично работает, отличные заметки/объяснения. Я новичок в вопросах, как мне выбрать это в качестве ответа/отдать должное вам за ответ?
@JohnRainey Что мне делать, если кто-то отвечает на мой вопрос?
после wcscpy_s (имя_машины, strln, имя); MachineName содержит имя машины.