powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как мне написать API-ф-цию чтоб возвращала строку.
25 сообщений из 53, страница 2 из 3
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317827
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl
Код: plaintext
1.
2.
3.
4.
int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  strncpy(lpString, UserName, nMaxCount);



1>.\LicenseDll.cpp(73) : error C2664: 'strncpy' : cannot convert parameter 1 from 'LPTSTR' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317828
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77 Как реализовать _Out_ LPTSTR lpString
без фокусов получать BSTR* а передавать byref as string
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317849
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77White Owl
Код: plaintext
1.
2.
3.
4.
int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  strncpy(lpString, UserName, nMaxCount);



1>.\LicenseDll.cpp(73) : error C2664: 'strncpy' : cannot convert parameter 1 from 'LPTSTR' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style castДай угадаю, у тебя включен UNICODE режим и ты компилируешь в С++?
Выключи первое в настройках проекта. И переименуй свой исходник в .c для выключения второго.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317873
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
бейсик конвертит свои юникодные строки в ANSI и обратно при вызове функций из dll

чтоб избавиться от геморроя можно вернуть из dll единственный объект (IDispatch) и далее просто вызывать его методы и обращаться к свойствам
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317961
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl,

1) Юникод я отключил в Property Pages -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Снял галку Inherit from parent or project defaults где что-то про это говорилось
Надеюсь это касается только тек. проекта и не "испортит" компилятор?
В принципе мне Юникод не нужен и в VB6 я например борюсь со случайными его "проявлениями". Это когда
len(String) вдруг начинает выдавать невменяемое значение после какого-нибудь strconv(,vbUnicode).
2) Файл в .c переименовывать не стал
3) Заменил
Код: plaintext
1.
strncpy(lpString, UserName, nMaxCount);


на
Код: plaintext
1.
strncpy_s(lpString, nMaxCount, UserName, nMaxCount);


(как присоветовал компилятор, читать Warning! допустимо, но не особо приятно)
Ничего не попутал, два раза воткнув именно nMaxCount (а не lenth напр.)?

Короче,
к коду ниже претезии есть? Память чиста? Совесть чиста?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
extern "C" {

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
	strncpy_s(lpString, nMaxCount, UserName, nMaxCount);

  if (lenth < nMaxCount) {
    lpString[lenth] = 0;
    return lenth;
  }
  else {
    lpString[nMaxCount - 1] = 0;
    return nMaxCount - 1;
  }
}


Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Private Declare Function LPTSTR_Get_Registration_Information Lib "LicenseDll.dll" _
 (ByVal lpString As String, ByVal nMaxCount As Long) As Long

Private Sub CommandGetReg_Click()
  Dim buf As String * 256
  Dim RegInfo As String
  Dim length As Long
  
  length = LPTSTR_Get_Registration_Information(buf, Len(buf))
  RegInfo = Left$(buf, length)
  MsgBox RegInfo
End Sub



Все работает. И плюс свел ф-цию к стандартному приему используемому в VB6.
У меня и первый вариант с char * работал, но Вам не понравилось.
Я бы забил, но мне хотелось привести к "стандарту".
Мой PtrToString это не тривиально и не стандарт, и я ее написал в прошлом году исключительно потому,
что с Opal с его ветвящимися структурами из ссылок на const char * по другому из VB6 работать не получилось.

Просто у вас в C++ тут очень интересно.
Какая то дурацкая строчка с NULL вызывает бурные дискуссии на неделю вперед.
Мало того что 5 строчек кода высасываются из пальца 2 дня,
так тебе еще неделю объясняют про 10 других способов.
Вот нафига мне этот IDispatch?
Работать с IЧтонибудь из VB6 ой как нелегко, если только не через tlb-обертку.
Не, я делал Windows Audio API (это которые New), но в VB6 с этим повеситься можно, но пришлось это сделать т.к. Вистовские миксеры со старыми multimedia API глючат.

В данном случае никакой необходимости IИздеватьсяНадСобой нету.

Просто ответьте. Последний вариант безупречен? Если В НЕМ что не так то что?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317971
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А по поводу
Код: plaintext
1.
char*	UserName = NULL;


на который все так дружно набросились,

Ну если dll не "защищена", то NULL там так и останется, соотв. вызов API элементарно вызовет crash.
Я думаю вариант
Код: plaintext
1.
char*	UserName = "";


лучше подойдет для инициализации, не так ли?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317981
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77White Owl,

1) Юникод я отключил в Property Pages -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Снял галку Inherit from parent or project defaults где что-то про это говорилось
Надеюсь это касается только тек. проекта и не "испортит" компилятор?
В принципе мне Юникод не нужен и в VB6 я например борюсь со случайными его "проявлениями". Это когда
len(String) вдруг начинает выдавать невменяемое значение после какого-нибудь strconv(,vbUnicode).
Нет, это не испортит компилятор.
Просто ты используешь LPSTR в своем проекте. Это собственный микрософтовский "тип" данных который является синонимом либо char*, либо unsigned short *. В первом случае ты будешь работать с обычной ASCIIz строкой, во втором с двухбайтовыми строками. И надо будет вместо strncpy использовать функцию wstrncpy. Первый случай это без UNICODE флага, второй случай с ним.

Дмитрий772) Файл в .c переименовывать не сталТы в любом случае вынужден писать верхний уровень на С. Потому что VB не способен импортировать С++ классы и методы классов.
Поэтому у тебя весь исходник и обернут в extern "C" блок.
Если у тебя имя исходного файла some.cpp, то extern "C"{} обязателен. Если some.c, то не обязателен.
На мой взгляд, если тебе нет нужды использовать классы и/или чьи-то С++ библиотеки, то проще писать сразу на С.

Дмитрий773) Заменил
Код: plaintext
1.
strncpy(lpString, UserName, nMaxCount);


на
Код: plaintext
1.
strncpy_s(lpString, nMaxCount, UserName, nMaxCount);


(как присоветовал компилятор, читать Warning! допустимо, но не особо приятно)
Ничего не попутал, два раза воткнув именно nMaxCount (а не lenth напр.)?

Вообще-то попутал. nMaxCount относится к lpString, но не имеет никакого отношения к UserName.



Дмитрий77Короче,
к коду ниже претезии есть? Память чиста? Совесть чиста? Есть претензии. Если ты используешь strncpy_s, то и обработку ошибок делай соответствующую.

Вот так получше будет:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#include <string.h>

extern "C" {

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  errno_t rc = strncpy_s(lpString, nMaxCount, UserName, length);

  if (rc == 0) {
     return length;
  } else {
    return 0;
  }
}

} // for extern "C"
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317989
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlВообще-то попутал. nMaxCount относится к lpString, но не имеет никакого отношения к UserName.ну и что? он же обрезает результирующую строку, если length <= nMaxCount, а больше в неё не попадёт по определению.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317990
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egorych, хотя твой вариант красивее, согласен. замучали меня под вечер абстракциями своими в программировании, прости
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317998
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77А по поводу
Код: plaintext
1.
char*	UserName = NULL;


на который все так дружно набросились,

Ну если dll не "защищена", то NULL там так и останется, соотв. вызов API элементарно вызовет crash.
Я думаю вариант
Код: plaintext
1.
char*	UserName = "";


лучше подойдет для инициализации, не так ли?Нет, так не будет лучше ни в коем случае.

Пойми одну простую вещь: В С и С++ нету строк. Вообще нету. Никаких. По определению.
Любая запись типа кавычки-буковки-кавычки это на самом деле объявление константного массива который будет содержать указанные буковки и конечный ноль. Каждый массив лежит где-то в памяти. А чтобы программа знала где это самое "где-то" находится существуют "указатели".
В Бейсике указатели тоже существуют, но они "спрятаны под капотом". Единственный случай когда ты сталкиваешься с указателями в VB это когда объявляешь параметр функции ByRef. А в С и С++ указатели используются намного шире и любая работа со строками в С это на самом деле манипулирование указателем на массив символов.


Объявляя char* name ты объявляешь не массив, а четыре байтика в памяти (для 32х битного приложения). В эти четыре байтика ты можешь записать реальный адрес в памяти где будет лежать настоящий массив.
Например запись:
char* UserName = "";
Объявляет массив размером в один байт (только один конечный нолик) и кладет этот массив в специальный сегмент памяти называемый сdata. Потом выделяет в сегменте памяти data четыре байтика (обзывает эти четыре байтика UserName) и записывает в них адрес одно-байтового массива.
Если ты теперь в коде функции сделаешь:
UserName="John";
то на самом деле, ты объявил в сегменте cdata массив из пяти байт и проинициализировал его четырьмя буквами и одним нулем, причем это произошло еще до старта программы. А во время выполнения функции ты перенаправляешь указатель UserName на этот пятибайтовый массив. При этом однобайтовый массив ты теряешь. Окончательно и бесповоротно. До того начального массива ты уже никогда-никогда не доберешься.


Запись типа
char* UserName = NULL;
намного лучше. В данном случае ты создаешь указатель (те самые именованные четыре байтика), но вместо адреса реального массива ты пишешь туда "стандартное" значение. Потом его можно использовать для проверки задан UserName или нет.
Например тебе надо вызывать функцию несколько раз, но проинициализировать только однажды:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
char *UserName = NULL;

char *user1 = "John";
char *user2 = "Peter";
char *user3 = "Bill";

void init() {
   if (UserName == NULL) {
      UserName = user1;
   }
}
void setUser(int ID) {
  switch(ID) {
    case 1: UserName = user1; break;
    case 2: UserName = user2; break;
    case 3: UserName = user3; break;
    default: UserName = user1; 
  }
}

Теперь сколько бы раз ты ни вызывал init() операция присвоения UserName выполнится только однажды. Это не очень показательный пример, но если UserName читается не из другой переменной а например из базы данных, или из сети, или спрашивается у юзера, то подобный трюк с начальным NULL может здорово облегчить жизнь.
Если же просто объявить
char *UserName;
То ты создашь в памяти переменную в которой будет какое-то случайное значение. И этот пример работать уже не будет.
Ты можешь заметить что использованный в примере NULL можно запросто заменить на какой-нибудь UNDEFINED. И будешь прав. Но в этом случае ты сам должен будешь создать UNDEFINED, в то время как NULL обычно уже существует и все про него знают и показанные трюки считаются нормой жизни.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38318009
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Вот нафига мне этот IDispatch?
Работать с IЧтонибудь из VB6 ой как нелегко, если только не через tlb-обертку.
не путайте IDispatch и IЧтонибудь

IDispatch - это бейсиковый Object с поздним связыванием, никакого tlb не требуется
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38318036
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl,

Код: plaintext
1.
errno_t rc = strncpy_s(lpString, nMaxCount, UserName, length);


Я не понимаю какую ты ошибку пытаешься отловить в errno_t rc,
1) если будет
length > nMaxCount-1
то будет crash без всякой ловли.
2) А любое значение между lenth и nMaxCount-1 к crash не приводит и дает корректный результат
3) Если считаешь что все-таки правильно инициализировать
Код: plaintext
1.
char*	UserName = NULL;


Сложно спорить с такими доводами, и не буду.
Но если при вызове API там будет NULL то будет crash.

Посему думаю чем отлавливать ошибки (до отлова которых дело не дойдет) проще руководствуясь здравым смыслом писать код чтоб их не было.

Я переделал вот так и жду замечаний:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
char*	UserName = NULL;
...
UserName = NewUserName; //НЕ ГАРАНТИРОВАНО
...

extern "C" {

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  if (UserName != NULL) {
    int lenth = (int) strlen(UserName);
    strncpy_s(lpString, nMaxCount, UserName, nMaxCount-1);
    if (lenth < nMaxCount) {
      lpString[lenth] = 0;
    } else {
      lpString[nMaxCount - 1] = 0;
    }
    return lenth;
  }
  else 
    return 0;
}



Можно конечно заменить на
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
    if (lenth < nMaxCount) {
     strncpy_s(lpString, nMaxCount, UserName, lenth);
     lpString[lenth] = 0;
   } else {
     strncpy_s(lpString, nMaxCount, UserName, nMaxCount-1);
     lpString[nMaxCount - 1] = 0;
   }


но особого смысла в этом не вижу.

Благодаря возврату "честной" длины я могу чуть модифицировать VB6 код и получать полную необрезанную строку максимум в 2 итерации:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Private Sub CommandGetReg_Click()
  
  Dim buf As String
  Dim length As Long
  Dim RegInfo As String
    
  buf = Space(256)
  length = LPTSTR_Get_Registration_Information(buf, Len(buf))
  MsgBox length
  If length > 255 Then
    buf = Space(length + 1)
    length = LPTSTR_Get_Registration_Information(buf, Len(buf))
  End If
  RegInfo = Left$(buf, length)
  Text1.Text = RegInfo
End Sub


Ну, или довольствоваться обрезанной пользуясь предыдущим кодом
Код: vbnet
1.
2.
debug.print Left$("Пример",100)
Пример


Т.е. левая часть длиной 540 от заполненного буфера [255]+\0 выдаст безошибочно строку длиной 255
(т.е. vb-шный код не ошибется).

С Вами не соскучишься.
Чувствую, если писать все на C++ то и программу не напишешь, и денег не заработаешь (такими то темпами).
Но зато умным человеком станешь.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38318066
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Благодаря возврату "честной" длины я могу чуть модифицировать VB6 код и получать полную необрезанную строку максимум в 2 итерации
в традициях WINAPI при передаче NULL в качестве адреса буфера возвращается (через результат или выходной параметр) необходимый размер
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319073
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилв традициях WINAPI при передаче NULL в качестве адреса буфера возвращается (через результат или выходной параметр) необходимый размер
Не всегда. Извращаются как хотят. Например GetPrivateProfileString
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
DWORD WINAPI GetPrivateProfileString(
  _In_   LPCTSTR lpAppName,
  _In_   LPCTSTR lpKeyName,
  _In_   LPCTSTR lpDefault,
  _Out_  LPTSTR lpReturnedString,
  _In_   DWORD nSize,
  _In_   LPCTSTR lpFileName
);


Return value
The return value is the number of characters copied to the buffer, not including the terminating null character.

If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one.

If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two.
Поэтому здесь мой вариант VB6 кода с 2-мя итерациями уже не пройдет. Пользуюсь вот таким кодом:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias _
 "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, _
 ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, _
 ByVal lpFileName As String) As Long

Private Function ReadIni(Section As String, Key As String, Default As String, FileName As String) As String

  Dim RetVal As String, v As Long
  Dim retLen As Long
    
  Do
    retLen = retLen + 260 ' arbitrary - can be set higher/lower if desired
    RetVal = Space(retLen)
    v = GetPrivateProfileString(Section, Key, Default, RetVal, retLen, FileName)
  Loop Until v < retLen - 1
    
  ReadIni = Left$(RetVal, v)
  
End Function



На практике обычно задается большой буфер (в предположении что места хватит) и никаких проверок не производится. Для моей ф-ции которую здесь мусолим такого варианта вполне достаточно. Но я несколько раз накалывался с этим, в частности с ini-файлом, поэтому (с учетом на будущее) все таки хочу написать подобную штуку "с запасом прочности".

Кстати я в своем крайнем варианте еще не проверял что будет если nMaxCount=0
т.е.
Код: plaintext
1.
strncpy_s(lpString, 0, UserName, -1);


Скрашит небось.
А с другой стороны если знаешь API изнутри, или есть нормальное описание в msdn или где-то там которое внимательно читаешь, то никогда не будешь вызывать API с недозволенными параметрами.
А вариант безусловного применения
Код: plaintext
1.
errno_t rc = strncpy_s(lpString, nMaxCount, UserName, length);


как раз может скрашить
1) если UserName=NULL
2) если length > nMaxCount - 1
и этот краш определяется значением UserName, т.е. вызывающая сторона не виновата что какой-то идиот засунул в Username строку в 10000 символов например. И вот это уже не есть гуд.
Я неправ?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319630
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77White Owl,

Код: plaintext
1.
errno_t rc = strncpy_s(lpString, nMaxCount, UserName, length);


Я не понимаю какую ты ошибку пытаешься отловить в errno_t rc,
http://msdn.microsoft.com/en-us/library/5dae5d43(v=vs.80).aspx
Читай внимательно описание функции.
Все что ты делаешь сравнивая length и nMaxCount - не нужно. Это все уже встроено внуть strncpy_s. Читай документацию.

Дмитрий771) если будет
length > nMaxCount-1
то будет crash без всякой ловли.не будет. Читай документацию.

Дмитрий772) А любое значение между lenth и nMaxCount-1 к crash не приводит и дает корректный результатНет. Читай документацию.

Дмитрий773) Если считаешь что все-таки правильно инициализировать
Код: plaintext
1.
char*	UserName = NULL;


Сложно спорить с такими доводами, и не буду.
Но если при вызове API там будет NULL то будет crash.Нет, не будет. Читай документацию.

Дмитрий77Посему думаю чем отлавливать ошибки (до отлова которых дело не дойдет) проще руководствуясь здравым смыслом писать код чтоб их не было.Да, конечно, лучше писать чтобы их не было. И я тебе уже показал как должен выглядеть код использующий функцию strncpy_s().

Дмитрий77Я переделал вот так и жду замечаний:Плохо. Все плохо. У тебя 90% кода - бессмысленная работа. А обработки ошибок нет вообще.


Дмитрий77С Вами не соскучишься.
Чувствую, если писать все на C++ то и программу не напишешь, и денег не заработаешь (такими то темпами).
Но зато умным человеком станешь.А если ты наконец решишься прочитать любой учебник по С (я советую K&R) и поймешь работу с указателями, а потом не будешь лениться читать документацию на используемые функции то все будет легко и замечательно. А до тех пор будешь писать фигню.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319639
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlДмитрий771) если будет
length > nMaxCount-1
то будет crash без всякой ловли.не будет. Читай документацию.

Дмитрий772) А любое значение между lenth и nMaxCount-1 к crash не приводит и дает корректный результатНет. Читай документацию.

Дмитрий773) Если считаешь что все-таки правильно инициализировать
Код: plaintext
1.
char*	UserName = NULL;


Сложно спорить с такими доводами, и не буду.
Но если при вызове API там будет NULL то будет crash.Нет, не будет. Читай документацию.

Вот ты говоришь не будет (Should NOT согласно документации). А я говорю что крашит (ИЗЪ ЕСМЬ что вижу то и докладываю).
Почему тогда у меня твой код (с обработкой ошибок) генерит crash при вызове в указанных случаях?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319644
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Почему тогда у меня твой код (с обработкой ошибок) генерит crash при вызове в указанных случаях?
Так мы ж не видим код, который вы запускаете.
Может у вас там проблема в других местах.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319658
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77White Owlпропущено...
не будет. Читай документацию.

пропущено...
Нет. Читай документацию.

пропущено...
Нет, не будет. Читай документацию.

Вот ты говоришь не будет (Should NOT согласно документации). А я говорю что крашит (ИЗЪ ЕСМЬ что вижу то и докладываю).
Почему тогда у меня твой код (с обработкой ошибок) генерит crash при вызове в указанных случаях?
Если согласно документации should not, а в реальность is - значит одно из двух: либо документация врет, либо ты делаешь неправильно.
Проверяется это очень просто: Отложи в сторону свой существующий супер-проект.
Сделай новый примитивный проект в котором попытайся повторить проблему. Если проблему повторить на микро-проекте удастся - опубликуй его здесь.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319668
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlСделай новый примитивный проект в котором попытайся повторить проблему.
Так это и есть микропроект.
На стороне C одна функция (ну пусть 2-3 аналогичных, но дергаю то одну)
На стороне VB6 декларация ф-ции + код одной кнопки.
Anatoly MoskovskyТак мы ж не видим код, который вы запускаете.
Значит плохо смотрите, если не видите:
14513598
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Private Declare Function LPTSTR_Get_Registration_Information Lib "LicenseDll.dll" _
 (ByVal lpString As String, ByVal nMaxCount As Long) As Long

Private Sub CommandGetReg_Click()
  Dim buf As String * 256
  Dim RegInfo As String
  Dim length As Long
  
  length = LPTSTR_Get_Registration_Information(buf, Len(buf))
  RegInfo = Left$(buf, length)
  MsgBox RegInfo
End Sub


Для получения crash с кодом предложенным White Owl выполнить этот код вполне достаточно для указанных двух случаев:
1) NULL
2) lenth > nMaxCount- 1
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319682
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А в "свой существующий супер-проект" я пока что вставил код из второго поста:
14502889
который у меня сомнений в надежности не вызывает.
И кстати, как люди говорят, 14518605 ,
ZVIПравильно было сделано в начале, во 2-м сообщении, с возвратом 2-байтного указателя на начало строки.
...А память там освобождать и не нужно было, потому что исходная С-ная строка не модифицируется, а создается копия строки в VB, и возвращаемый указатель там используется только для копирования С-шной строки в другую VB-строку.

Единственное, почему я так прицепился к последнему варианту, потому что он "стандартизирован" и не предполагает побайтное рытье памяти на стороне VB6, что очень нестандартно хотя и работает железно.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319725
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

почему не вернуть без фокусов BSTR или VARIANT?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319736
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий77,

почему не вернуть без фокусов BSTR или VARIANT?

Да ради бога.
Ты предлагал:
Код: plaintext
1.
2.
3.
4.
5.
extern "C"  BSTR  __declspec(dllexport) __stdcall fnString()
{
	char* retVal = "Самодур";
	return ::SysAllocStringByteLen(retVal,strlen(retVal));	
}


По сути это ничем не отличается от возврата char *. Кроме пристрастий и сомнительных споров про память (лично я окончательно судить не берусь, но человек - цитата чуть выше -говорит что все там с памятью нормально)

А так напишешь?
Код: plaintext
1.
2.
int __stdcall BSTR_Get_Registration_Information(BSTR bsString, int nMaxCount)
...???



Или даже так?
Код: plaintext
1.
2.
int __stdcall char_Get_Registration_Information(char * charSttring, int nMaxCount)
...???



Ну, ты понимаешь к чему я клоню. К стандартизированному методу вызова. Чтоб скопировать результат в буфер длиной nMaxCount и вернуть lenth.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319745
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

в случае возврата BSTR нет никакой нужды в передаче длины строки и прочих танцев с бубном с буфером
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319750
ZVI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем -привет! Давненько я не брал в руки C-шашек!


Обычно механизм возврата строки из С в VB такой:
Код С-dll
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#include <string.h >

// Функции для "внешнего" вызова 
extern "C"
{
	int __stdcall Key_test(char *txt);
}


// Тестовая функция, возвращающая текстовую строку
int __stdcall Key_test(char *txt)
{
	char *string = "UserName #1";
	int i = strlen(string);
	strncpy(txt, string, i);
	return(i);
}



Код VB:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Private Declare Function Key_test Lib "Test.dll" (ByVal ptr As String) As Long

Private Sub Form_Load()
  Dim i As Long, s As String
  s = App.Path
  ChDrive s
  ChDir s
  s = String(255, 0)
  i = Key_test(s)
  s = Left(s, i)
  MsgBox s & vbLf & i
  Unload Me
End Sub



Приложил cpp, dll и VB проектик
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319763
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ZVIОбычно механизм возврата строки из С в VB такой:

тебе рассказать, что такое переполнение буфера или сам нагуглишь?
...
Рейтинг: 0 / 0
25 сообщений из 53, страница 2 из 3
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как мне написать API-ф-цию чтоб возвращала строку.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]