Возвращаемое значение типа String

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Возвращаемое значение типа String

Сообщение hCORe » 21.04.2005 (Чт) 20:19

Вот функция, экспортируемая из DLL на Delphi:
Код: Выделить всё
function dumb(i: byte):PAnsiChar; stdcall;
begin
// Ich liebe Perfokarten!!!
  dumb:=PAnsiChar(chr(i));
end;


Как правильно объявить ее в VB?
Пробовал вот так:
Код: Выделить всё
Public Declare Function dumb Lib "perfokarten.dll" _
(i As Byte) As String

но при вызове VB, естественно, вылетает - передается ему совсем не то, что нужно. Может быть, еще и в функции что-то изменить?

Я много вариантов перепробовал, но все они нерабочие - либо "вылетают" с ошибками, либо выдают чушь на выходе. Кто что посоветует?
Моду создают модоки, а распространяют модозвоны.

Faust
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 649
Зарегистрирован: 29.12.2003 (Пн) 13:38
Откуда: лаборатория

Сообщение Faust » 21.04.2005 (Чт) 20:30

А почему бы не возвращать такой родной и long'овый указатель на первый символ строки?
Листинги не горят!

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 21.04.2005 (Чт) 20:44

Эта идея была мной уже опробована. Но - как потом преобразовать указатель на первый символ в строку? А то у меня с этим туго :cry:
Моду создают модоки, а распространяют модозвоны.

Sur
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 91
Зарегистрирован: 14.07.2003 (Пн) 20:54
Откуда: C2H5OH

Сообщение Sur » 21.04.2005 (Чт) 20:55

hCORe

Код: Выделить всё
Public Declare Function lstrlenA Lib "kernel32" (ByVal Ptr As Any) As Long
Public Declare Function lstrcpyA Lib "kernel32" (ByVal RetVal As String, ByVal Ptr As Long) As Long

Public Function GetString(ByVal lpszA As Long) As String
    GetString = String$(lstrlenA(ByVal lpszA), 0)
    Call lstrcpyA(ByVal GetString, ByVal lpszA)
End Function

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 22.04.2005 (Пт) 11:08

Гы гы гы :)
Нарушено Золотое Правило работы с указателями :)

Никогда не возвращать из процедуры указатель на локальную переменную!
Память для возвращаемой строки отводить исключительно через new.

Код: Выделить всё
function dumb(i: byte):PAnsiChar; stdcall;
begin
// Ich liebe Perfokarten!!!
  new(result);
  result^:=chr(i);
end;


Код: Выделить всё
Option Explicit

Private Declare Function dumb Lib "C:\Program Files\Borland\Delphi7\Projects\Project1.dll" (ByVal i As Byte) As String

Private Sub Form_Load()
  MsgBox dumb(65)
End Sub



Правда, я не знаю, будет ли в этом случае утечка памяти :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 13:44

Понял. Спасибо :)

Появилось несколько вопросов:
result^ вызывает дереференс результата функции? И "result" - это универсальная штука для возвращения результата?
Моду создают модоки, а распространяют модозвоны.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 23.04.2005 (Сб) 14:06

Ага.
Её удобнее использовать, потому что менять имя функции потом проще :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:05

Странно... Тут возникла еще одна проблема:
Код: Выделить всё
Len(dumb(65)) = 14

Из этих 14 символов только один - нужный. Причем, если вызывать функцию dumb из цикла:
Код: Выделить всё
For i = 0 To 1024
    p = dumb(65)
    Debug.Print i
Next i

то (при выключенном режиме "Optimize" в настройках компилятора Delphi) IDE вылетает при i=718 с ошибкой Access Violation (0xc000005) в модуле kernel32.dll. Скомпилированный exe-шник вылетает тоже. Вас ист дас и как с этим бороться?
Моду создают модоки, а распространяют модозвоны.

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:10

Хммм... Нашел причину сам :)

Вызов dispose(result) приводит к нормальным результатам (прога не вылетает):
Код: Выделить всё
function dumb(i: byte):PAnsiChar; stdcall;
begin
// Ich liebe Perfokarten!
// Ich trage mein liebes Computer jeden Tag!
  new(result);
  result^:=chr(i);
  dispose(result);
end;


А вот длина строки в 14 символов осталась. Это, конечно, не фатально, но... :?
Моду создают модоки, а распространяют модозвоны.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 23.04.2005 (Сб) 15:22

Вообще-то нет :)
После Dispose память освобождается, и у меня, к примеру, с Dispose вылетает сразу. Может, просто 0 в конец дописать? :)
А почему надо именно так? Может, по старинке, передавая в библу указатель на буфер? :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:40

Не знаю, почему именно так :)
Сделал как Sub:
Код: Выделить всё
procedure dumb(i: byte; var s:PAnsiChar); stdcall;
begin
  new(s);
  s^:=chr(i);
end;

Декларация:
Код: Выделить всё
Public Declare Sub dumb Lib "Concept.dll" _
(ByVal i As Byte, s As String)

Вызов:
Код: Выделить всё
For i = 0 To 25500
    fn2033 5, p
    Debug.Print i
Next i

Ошибка в kernel32.dll!
Добавляю dispose(s) перед end; - и ошибки как не бывало! :twisted:

Решил добавлять символ завершающего нуля:
Код: Выделить всё
procedure dumb(i: byte; var s:PAnsiString); stdcall;
begin
  new(s);
  s^:=(chr(i) + #0);
//  dispose(s);
end;


Длина строки - по-прежнему 14. Прогоняю цикл - ошибка в kernel32.dll. Снимаю комментарий с dispose(s) - все работает "на ура". В чем дело? :cry:
Моду создают модоки, а распространяют модозвоны.

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:43

Другая декларация к тому же Sub'у (вариант #1 с dispose из пред. поста):
Код: Выделить всё
Public Declare Sub fn2033 Lib "Concept.dll" _
(ByVal i As Byte, ByVal s As Long)

А этот код:
Код: Выделить всё
fn2033 65, VarPtr(s)
MsgBox s

выдает длину в 7 символов!
Моду создают модоки, а распространяют модозвоны.

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:46

Высказываю предположение: в WinXP по-другому ведется работа с памятью в динамических библиотеках, чем в Win98. :x
Моду создают модоки, а распространяют модозвоны.

hCORe
VB - Экстремал
VB - Экстремал
Аватара пользователя
 
Сообщения: 2332
Зарегистрирован: 22.02.2003 (Сб) 15:21
Откуда: parent directory

Сообщение hCORe » 23.04.2005 (Сб) 15:53

Ан нет! Скомпилировал я, значит, файл, перенес его на Win98SE на виртуальном PC... И все работает! :)
Моду создают модоки, а распространяют модозвоны.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот и гости: 19

    TopList