powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как мне написать API-ф-цию чтоб возвращала строку.
53 сообщений из 53, показаны все 3 страниц
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315299
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Внутри C++ кода есть.
Код: plaintext
1.
char*	UserName = NULL;



В какой-то момент ей присваивается реальная строка:
Код: plaintext
1.
UserName = NewUserName; //char* NewUserName  



Эту строку UserName надо отфутболить через API в VB6 приложение

Пытаюсь так например:
Код: plaintext
1.
2.
3.
4.
5.
int __stdcall CPP_Get_Registration_Information(char * MyUserName)
{ 
  MyUserName = UserName;
  return 0;
}


Вот как это правильно сделать?

Доставать пытаюсь так:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
Private Declare Function CPP_Get_Registration_Information Lib "MyTestDll.dll" _
 (ByVal NewUserName As String) As Long
Private Sub CommandGetRegistrationInformation_Click()
  Dim NewUserName As String
  NewUserName = String$(255, 0)
  CPP_Get_Registration_Information NewUserName
  MsgBox NewUserName
End Sub


Не получается строку прочитать, пусто!

По хорошему на стороне VB конструкция должна быть примерно такая:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
Declare Function CPP_Get_Registration_Information Lib "MyTestDll.dll" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Function GetRegName() As String
Dim RegName As String
    ' Receive a Registration Info from API's CPP_Get_Registration_Information  function
     RegName = String$(255, 0)
     GetRegName = Left(RegName, CPP_Get_Registration_Information(RegName, InStr(RegName, Chr(0)) - 1))
End Function



Но я не понимаю как зарядить эту конструкцию на стороне C++.
C аналогичными ф-циями где надо вернуть несколько чисел (а не строку) я разобрался.
Например:

C++
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
int		TrialDaysTotal		= -1,
		TrialDaysLeft		= -1;
...
	TrialDaysTotal = Total;
	TrialDaysLeft  = Left;
...
extern "C" {
int __stdcall CPP_Get_Trial_Days(int * Total, int * Left)
{ 
  * Total = TrialDaysTotal;
  * Left = TrialDaysLeft;
  return 0;
}



VB6
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Private Declare Function CPP_Get_Trial_Days Lib "MyTestDll.dll" _
 (ByRef Total As Long, ByRef Left As Long) As Long

Private Sub CommandGetTrialDays_Click()
  Dim Total As Long
  Dim Left As Long
  
  CPP_Get_Trial_Days Total, Left
  
  MsgBox "Total=" & Total & " Left=" & Left
End Sub


С int/Long все работает.

Помогите мне char * из C++ вытащить.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315304
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Все оказалось немного проще:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
//C++
extern "C" {

char * __stdcall CPP_Get_Registration_Information()
{ 
  return UserName;
}
...



Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
'VB6
Private Declare Function CPP_Get_Registration_Information Lib "MyTestDll.dll"  () As Long

Private Sub CommandGetRegistrationInformation_Click()
  MsgBox PtrToString(CPP_Get_Registration_Information)
End Sub

Function PtrToString(Ptr As Long) As String
    Dim Data As Byte
    Dim str As String
    Dim i As Long
    str = ""
    If Ptr <> 0 Then
        For i = 0 To 10000 '255
            CopyMemory Data, ByVal Ptr + i, 1
            If Data = 0 Then Exit For 'конец строки \0
            str = str & Chr(Data)
        Next i
    End If
    PtrToString = str
End Function


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

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

Я рад что у меня хоть как то получилось.

А чем char * плох?
Asprotect в своих API использует именно char *, его я и возвращаю через мою API.
А VB6 по любому получит Long - указатель (Ptr) на начало строки.
А конец строки - нулевой символ.

Проблема возникла из того, что в VB6 нельзя напрямую вызвать нормальные API AsProtect.
Вот здесь чуть подробнее:
Вопрос по API ф-циям AsProtect если кто сталкивался или умеет использовать "сложные" API.

Зато dll-ки с API писать научился.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315398
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77А чем char * плох?
кто память освобождать будет?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315427
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил,

а ты ссылку смотрел постом выше, где более менее полный код приведен?
Конструкция

Код: plaintext
1.
2.
3.
4.
5.
6.
char*	UserName			= NULL;

void __declspec(dllexport) __stdcall GetRegistrationInformation(char* NewUserName){

	UserName = NewUserName;
}



навязана из документации AsProtect.
(верхняя "API" не моя и она сработает автоматом, моя (вызываемая по требованию из VB6) только нижняя)

А AsProtect фиг знает чего там делает и чего освобождает.
Или считаешь, что я должен что-то освобождать со стороны VB, я же только отдаю ссылку на память, а значение там и так лежит с момента как сработает dll (LoadLibrary?)
И полагаю что то что там создается при выгрузке dll (проги) очищается.

Или предлагаешь коверкать типы? Оно стоит? Я и так C++ коды в час по чайной ложке рожаю.
В любом случае UserName запрашивается один раз при старте программы и памяти много не занимает (даже если согласиться что она таки теряется). А почему так уверен что теряется?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315553
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Внутри C++ кода есть.
Код: plaintext
1.
char*	UserName = NULL;


Возможно это будет интересно: в разных C++ компиляторах NULL может иметь разное значение, а не 0, как это можно было бы ожидать, что может привести к неожиданному результату для конструкций вида
Код: plaintext
1.
if(!UserName){...}. 


Поэтому лучше присваивать либо 0, либо nullptr (для C++11).
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315557
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumВозможно это будет интересно: в разных C++ компиляторах NULL может иметь разное значение, а не 0, как это можно было бы ожидать, что может привести к неожиданному результату для конструкций вида
Код: plaintext
1.
if(!UserName){...}

Какие могут быть неожиданности, если оператор отрицания для указателей возвращает отрицание сравнения с NULL?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315570
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77а ты ссылку смотрел постом выше, где более менее полный код приведен?
есть прямой путь
Код: plaintext
1.
2.
3.
4.
5.
extern "C"  BSTR  __declspec(dllexport) __stdcall fnString()
{
	char* retVal = "Самодур";
	return ::SysAllocStringByteLen(retVal,strlen(retVal));	
}
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315574
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovКакие могут быть неожиданности, если оператор отрицания для указателей возвращает отрицание сравнения с NULL?[/quote]
А что тут непонятного? Если символическая константа NULL равна 0, то результат проверки будет 1. В противном случае результат проверки будет 0. Т.о. в зависимости от реализации компилятора результат приведённой мною выше проверки может оказаться различным.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315579
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumА что тут непонятного? Если символическая константа NULL равна 0, то результат проверки будет 1. В противном случае результат проверки будет 0. Т.о. в зависимости от реализации компилятора результат приведённой мною выше проверки может оказаться различным.Ещё раз !указатель == !(указатель == NULL)
Поэтому (если вдруг), найдётся компилятор, где NULL !== 0 - всё будет работать корректно.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315597
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovЕщё раз
Код: plaintext
1.
!указатель ==  !(указатель == NULL)


Поэтому (если вдруг), найдётся компилятор, где NULL !== 0 - всё будет работать корректно.
Исходный код:
Код: plaintext
1.
char*	UserName = NULL;


Если записывать в такой форме:
Код: plaintext
1.
if(!(UserName == NULL)){...}


то несомненно, это всегда будет работать правильно, вне зависимости от реализации компилятора.

Но если записать в таком виде:
Код: plaintext
1.
if(!UserName){...}


то возникнет ситуация, о которой я писал выше, поскольку если в реализации конкретного компилятора символическая константа NULL окажется не равной 0, то указанное вами равенство
Код: plaintext
1.
!указатель ==  !(указатель == NULL)


окажется неверным, т.к.
Код: plaintext
1.
!указатель

вернёт 0, в то время как
Код: plaintext
1.
!(указатель == NULL)

вернёт 1.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315603
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositumвернёт 1.Рассматривайте части моего "равенства" как уравнение и всё встанет на свои места.

P.S. А вы можете привести пример компилятора, где NULL !== 0?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315629
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovРассматривайте части моего "равенства" как уравнение и всё встанет на свои места.
Не вижу, каким образом?
Basil A. SidorovP.S. А вы можете привести пример компилятора, где NULL !== 0?
Я пользуюсь только MS Visual Studio и GNU g++.
А что, обязательно нужно ждать, чтобы споткнуться об это? То, что упоминалось мною выше взято не с потолка, а было вычитано из книжек, где и было дано предупреждение о том, что не стоит слепо полагаться на то, что в C++ всегда NULL == 0, т.к. это не регламентировано в стандарте, но отдано на откуп разработчиков компиляторов.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315642
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вспомнил один из сточников, где читал подобного рода информацию: Стивен Прата, "Язык программирования C++ (C++11). Лекции и упражнения", 6-е издание. Глава 12, стр. 610, примечание "Нулевой указатель в C++11".
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315645
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumТо, что упоминалось мною выше взято не с потолка, а было вычитано из книжекА в этих книжках не пояснялась семантика оператора "boolean not" применительно к указателям?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315651
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovCompositumТо, что упоминалось мною выше взято не с потолка, а было вычитано из книжекА в этих книжках не пояснялась семантика оператора "boolean not" применительно к указателям?
Насколько мне известно, оператор "!" превращает 0 в 1, а любое число, отличное от 0 превращает в 0. Поправьте меня, если я не прав. Я что, где-то выше противоречил этому?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315683
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Вы слишком все упрощаете.

Оператор ! (а также if() и т.п.) создает булевый контекст для своего аргумента.
В булевом контекте, число 0 неявно приводится к false, остальные числа к true.
Для указателя другое правило: NULL приводится к false, остальные указатели к true.

Таким образом, какое бы не было физическое значение у нулевых указателей, конструкция !ptr всегда работает корректно.

Теперь про обратную сторону.

Compositum
Код: plaintext
1.
!(указатель == NULL)


вернёт 1.
Это опять упрощение.
Оператор ! не возвращает 0 или 1.
Он возвращает bool, т.е. false или true.
А в числовом контексте (например при присвоении в int), эти значения неявно переводятся в их соответствующие числовые представления, 0 или 1 (насколько я помню стандартом не определено что true это именно 1, но могу ошибаться, т.к. нет времени искать).
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315698
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskyнасколько я помню стандартом не определено что true это именно 1
быстрый гуглинг показал, что при преобразовании из bool в int по стандарту обязательно приводятся к 0 или 1.
Но это не отменяет все остальное что я говорил.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315724
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyДля указателя другое правило: NULL приводится к false, остальные указатели к true.
Спасибо, учту на будущее. Я думал, что и указатели приводятся к bool на основе числового значения адреса, на который они указывают.
Anatoly Moskovskyнасколько я помню стандартом не определено что true это именно 1, но могу ошибаться, т.к. нет времени искать
любое число, отличное от 0 трактуется как true (из книжек).
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315727
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumЯ думал, что и указатели приводятся к bool на основе числового значения адресаА ведь вам намекали. Долго.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315731
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovА ведь вам намекали. Долго.
Мне лучше писать прямо, без намёков, поскольку надлежащего опыта программирования в C++ у меня нет. :)
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38315746
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumAnatoly Moskovskyнасколько я помню стандартом не определено что true это именно 1, но могу ошибаться, т.к. нет времени искать
любое число, отличное от 0 трактуется как true (из книжек).
CompositumМне лучше писать прямо, без намёков
Пишу вам прямо, без намёков - я там в процитированном пишу про перевод из bool в числа. А вы написали про обратное преобразование.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317775
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий77а ты ссылку смотрел постом выше, где более менее полный код приведен?
есть прямой путь
Код: plaintext
1.
2.
3.
4.
5.
extern "C"  BSTR  __declspec(dllexport) __stdcall fnString()
{
	char* retVal = "Самодур";
	return ::SysAllocStringByteLen(retVal,strlen(retVal));	
}



Хорошо, давай вообще без самодурства.
Есть пример несамодурной API:
GetWindowText function
Код: plaintext
1.
2.
3.
4.
5.
int WINAPI GetWindowText(
  _In_   HWND hWnd,
  _Out_  LPTSTR lpString,
  _In_   int nMaxCount
);


Код для использования GetWindowText из VB6 простой и понятный:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Private Declare Function GetWindowText Lib "user32" Alias _
 "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, _
 ByVal nMaxCount As Long) As Long
...
  Dim buf As String * 256
  Dim Title As String
  Dim length As Long

  ' Get the window's title.
  length = GetWindowText(app_hwnd, buf, Len(buf))
  Title = Left$(buf, length)


Заметь, без использования моей САМОДУРНОЙ PtrToString на стороне VB6. при помощи которой я вытаскиваю String из памяти зная только Ptr.

И я пытаюсь создать свою API по образу и подобию GetWindowText (чтоб возвращала длину и заполняла буфер строчкой).
Делаю так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
char*	UserName			= NULL;
....
  UserName = NewUserName; //короче в char* точно есть строка "1-0-0" из 5 символов не считая \0
...

extern "C" {

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  lpString = (LPTSTR)UserName;
  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.
13.
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))
  MsgBox length
  RegInfo = Left$(buf, length)
  MsgBox RegInfo
End Sub



MsgBox length -честно возвращает число "5"
А вот
MsgBox RegInfo
ни фига не возвращает (буфер как был пуст, так и остался).

Что я не так написал в dll что у меня буфер строчкой не заполняется?
Как реализовать _Out_ LPTSTR lpString
Я в C-шном коде выделил места подвоха.
Ток вот как правильно я не знаю.
Поможете?
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38317814
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77И я пытаюсь создать свою API по образу и подобию GetWindowText (чтоб возвращала длину и заполняла буфер строчкой).
Делаю так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
char*	UserName			= NULL;
....
  UserName = NewUserName; //короче в char* точно есть строка "1-0-0" из 5 символов не считая \0
...

extern "C" {

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  lpString = (LPTSTR)UserName  Не верно. Нельзя это делать. ;
  if (lenth < nMaxCount) {
    lpString[lenth] = 0;
    return lenth;
  }
  else {
    lpString[nMaxCount - 1] = 0;
    return nMaxCount - 1;
  }
}



Что я не так написал в dll что у меня буфер строчкой не заполняется?
Как реализовать _Out_ LPTSTR lpString
Я в C-шном коде выделил места подвоха.
Ток вот как правильно я не знаю.
Поможете?
Ты не заполняешь буфер, а переопределяешь его.
Строки в С это массивы. Их надо копировать специальными функциями, простому знаку равенства они не подвластны.
Код: plaintext
1.
2.
3.
4.
int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString, int nMaxCount)
{ 
  int lenth = (int) strlen(UserName);
  strncpy(lpString, UserName, nMaxCount);
...
Рейтинг: 0 / 0
Как мне написать 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
Как мне написать API-ф-цию чтоб возвращала строку.
    #38319798
ZVI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилтебе рассказать, что такое переполнение буфера или сам нагуглишь?
Спасибо, не нужно :)
За небрежность C кода извиняюсь. И malloc и free для string здесь, конечно же, были бы уместны.
И не нужно рассказывать про то, что Strncpy сама не допускает переполнения, а VB, в отличие от C, сам за собой подчищает память, кроме объектных переменных, конечно (не наш случай).
А со стороны VB, если посмотрите, разумные для примера меры приняты.

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

1) NULL
Вы так горячо спорили про этот самый NULL.
Но ни один из вас даже намеком не обмолвился что нельзя делать
strlen (NULL)
и именно эта строчка и дает crash

Проверяйте,
Код: plaintext
1.
2.
3.
  char * test = NULL;
  int i = (int) strlen(test);  
  printf("i= %d\n", i);


этого например достаточно чтоб вылететь в мир иной

Надо хотя бы ЭТО проверять.
Код: plaintext
1.
2.
3.
  int lenth = 0;
  if (UserName != NULL)
    lenth =(int) strlen(UserName);



2) lenth > nMaxCount- 1
Что касается strncpy _s то что бы там не было в документациях, при конструкции
Код: plaintext
1.
errno_t rc = strncpy_s(lpString, nMaxCount, UserName, length);


она извините ругается МАТОМ а не ошибкой в errno_t rc как видимо следует из документации.

А вот вариант
Код: plaintext
1.
strncpy(lpString, UserName, length);


очень даже проходной с этой точки зрения.
Компилятор чего-то там бурчит, но ведь компилирует, и программа дух не испускает.
Честно говоря к чертям этот nMaxCount, толку от него никакого, да и он нуль-терминаторов честно говоря тоже, length то известна, мусор по-любому отсекается на уровне приложения.

Посему вот так в самый раз:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
С++
int __stdcall char_Get_Registration_Information(char* chrString)
{ 
  int lenth = 0;
  if (UserName != NULL)
    lenth =(int) strlen(UserName);
  strncpy(chrString, UserName, lenth);
  return lenth;
}

int __stdcall LPTSTR_Get_Registration_Information(LPTSTR lpString)
{ 
  int lenth = 0;
  if (UserName != NULL)
    lenth =(int) strlen(UserName);
  strncpy(lpString, UserName, lenth);
  return lenth;
}



Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
VB6
Private Declare Function char_Get_Registration_Information Lib "LicenseDll.dll" _
 (ByVal chrString As String) As Long
Private Declare Function LPTSTR_Get_Registration_Information Lib "LicenseDll.dll" _
 (ByVal lpString As String) As Long

Private Sub CommandGetReg_Click() 'LPTSTR
  
  Dim buf As String
  Dim length As Long
  Dim RegInfo As String
    
  buf = Space(256)
  length = LPTSTR_Get_Registration_Information(buf)
  MsgBox length
  If length > 255 Then
    buf = Space(length + 1)
    length = LPTSTR_Get_Registration_Information(buf)
  End If
  RegInfo = Left$(buf, length)
  MsgBox RegInfo
  Text1.Text = RegInfo
End Sub

Private Sub CommandGetRegChar_Click()
  
  Dim buf As String
  Dim length As Long
  Dim RegInfo As String
    
  buf = Space(256)
  length = char_Get_Registration_Information(buf)
  MsgBox length
  If length > 255 Then
    buf = Space(length + 1)
    length = char_Get_Registration_Information(buf)
  End If
  RegInfo = Left$(buf, length)
  MsgBox RegInfo
  Text1.Text = RegInfo
End Sub



ИзопропилДмитрий77,

в случае возврата BSTR нет никакой нужды в передаче длины строки и прочих танцев с бубном с буфером

Да, спасибо. Я оценил наконец.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
BSTR  __stdcall fnString()
{
  int lenth = 0;
  if (UserName != NULL)
    lenth =(int) strlen(UserName);
  return ::SysAllocStringByteLen(UserName,lenth);	
}



Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
Private Declare Function fnString Lib "LicenseDll.dll" () As String

Private Sub CommandFnString_Click()
  Dim vb_Str As String
  vb_Str = fnString
  MsgBox vb_Str
  MsgBox Len(vb_Str)
  Text1.Text = vb_Str
End Sub



Черт, никогда ранее не видел чтобы API ф-ция в VB6 ВОЗВРАЩАЛА As String
Круто.

ZVI, спасибо за поддержку.

Как мне все это надоело.
Оставлю наверно свой вариант из второго поста. Вполне себе рабочий вариант такой и уже вставлен в проект.
...
Рейтинг: 0 / 0
Как мне написать API-ф-цию чтоб возвращала строку.
    #38323227
WED67
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Дмитрий77,

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


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