IDE рушится при работе с GetMem

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
VBTerminator
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 415
Зарегистрирован: 19.11.2008 (Ср) 20:10

IDE рушится при работе с GetMem

Сообщение VBTerminator » 29.07.2011 (Пт) 19:26

Работая с API-функцией GetMem, я обнаружил одну неприятную особенность: если она работает с переменной, находящейся вне области видимости вызывающего её места, то IDE рушится. Поясню на примере:
Код: Выделить всё
Option Explicit

Public Declare Function GetMem4 Lib "msvbvm60" _
    (ByVal pSrc As Long, ByVal pDst As Long) As Long


Sub MAIN()
   
    Dim myvar As Long
    myvar = 1234
   
    CopyMyVar VarPtr(myvar)
   
End Sub

Public Sub CopyMyVar(ByVal VarAddr As Long)
   
    Dim copy As Long
    GetMem4 VarAddr, copy    'Здесь и происходит обрушение
   
    MsgBox copy
   
End Sub


Вопрос: как обойти эту проблему, особенно если процедура CopyMyVar() будет располагаться во внешней DLL-библиотеке как API-функция?

Debugger
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1667
Зарегистрирован: 17.06.2006 (Сб) 15:11

Re: IDE рушится при работе с GetMem

Сообщение Debugger » 29.07.2011 (Пт) 21:07

VBTerminator писал(а):Public Sub CopyMyVar(ByVal VarAddr As Long)

Dim copy As Long
GetMem4 VarAddr, copy 'Здесь и происходит обрушение

MsgBox copy

End Sub

VarAddr, исходя из названия - адрес переменной. Значит, первый аргумент - адрес.
copy, судя по всему - просто переменная, куда ты хочешь скопировать. Значит, со вторым аргументом беда: ты хочешь скопировать что-то из адреса VarAddr в ноль (copy = 0). Отсюда вылет.
Вроде бы так.

Alec
Бывалый
Бывалый
 
Сообщения: 275
Зарегистрирован: 31.08.2008 (Вс) 0:15
Откуда: Ростов-на-Дону

Re: IDE рушится при работе с GetMem

Сообщение Alec » 29.07.2011 (Пт) 22:19

Debugger писал(а):VarAddr, исходя из названия - адрес переменной. Значит, первый аргумент - адрес.

http://bbs.vbstreets.ru/viewtopic.php?f=68&t=36758
Иногда лучше вовремя остановиться...
И начать заново!

Debugger
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1667
Зарегистрирован: 17.06.2006 (Сб) 15:11

Re: IDE рушится при работе с GetMem

Сообщение Debugger » 29.07.2011 (Пт) 23:52

Ссылка никак не связана с цитатой. Разве я отговариваю от использования GetMem?

Либо
Код: Выделить всё
GetMem4 VarAddr, VarPtr(copy)

- передаются 2 указателя, всё хорошо

Либо
Код: Выделить всё
Public Declare Function GetMem4 Lib "msvbvm60" (ByVal pSrc As Long, ByRef pDst As Long) As Long
. . .
GetMem4 VarAddr, copy

При этом мы указываем, что pDst всегда будет ссылкой. Не очень красиво мешать смысл аргументов таким способом (как это сделал автор).

Либо
Код: Выделить всё
Public Declare Function GetMem4 Lib "msvbvm60" _
    (ByRef pSrc As Long, ByRef pDst As Long) As Long
. . .
GetMem4 ByVal VarAddr, copy

Указываем, что мы передаём ссылки, но передаём адрес как ByVal.

Первый и последний варианты предпочтительней.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: IDE рушится при работе с GetMem

Сообщение Хакер » 30.07.2011 (Сб) 2:42

Debugger во втором посте всё правильно сказал. Вообще, объявляйте всегда As Any, будет возможность при вызове указать ByVal или ByRef вы хотите.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Alec
Бывалый
Бывалый
 
Сообщения: 275
Зарегистрирован: 31.08.2008 (Вс) 0:15
Откуда: Ростов-на-Дону

Re: IDE рушится при работе с GetMem

Сообщение Alec » 30.07.2011 (Сб) 15:56

Debugger писал(а):Ссылка никак не связана с цитатой. Разве я отговариваю от использования GetMem?

Что ты, конечно нет. Просто я не знаю как сделать ссылку на определенный абзац другого топика. Имелось ввиду:
Хакер на viewtopic.php?f=68&t=36758 писал(а):(Обе функции принимают src и dst -- адреса откуда копировать и куда копировать. CopyMemory принимает ещё и length -- сколько копировать).
Что делает GetMem4:
В eax записывается src.
В ecx записывается dst
В eax записываются 4 байта по адресу, хранящемуся в eax.
В память, по адресу, хранящемуся в ecx, записывается значение (те самые 4 байта), которые хранятся в eax.
Иногда лучше вовремя остановиться...
И начать заново!

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: IDE рушится при работе с GetMem

Сообщение Filyus » 31.07.2011 (Вс) 9:50

Используйте Type Library, тогда вызовы будут быстрее и удобнее.
Примеры объявлений (создаём в Visual C++ или в блокноте файл mem4.id):
Код: Выделить всё
[
  uuid(30A98234-7CB6-44c8-94CA-D166BAE71234),
  version(1.0),
  helpstring("Using GetMem4")
]
library GetMem4
{   importlib("stdole2.tlb");

   [
      dllname("msvbvm60"),
      helpstring("GetMem4 Functions")
   ]
   module msvbvm60 {

       [entry("GetMem4"), propget,helpstring("Returns or sets the value referenced by the source parameter cast to a DWord Long.")]
      HRESULT __stdcall AsLong(
         [in]          void *            Ptr,
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"), propput,]
      HRESULT __stdcall AsLong(
         [in]            void *            Ptr,
         [in]            long               NewValue
      );

      [entry("GetMem4"),helpstring("Returns the argument cast to a DWord structure.")]
      HRESULT __stdcall AsDWord([in] void * Ptr, [out, retval] DWord * lpRetVal);
      
       [entry("GetMem4"), propget,helpstring("Sets or returns the 32-bit Long integer value at the specified memory address.")]
      HRESULT __stdcall Mem(
         [in]          long               Address,
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"), propput,]
      HRESULT __stdcall Mem(
         [in]            long               Address,
         [in]            long               NewValue
      );

       [entry("GetMem4"), propget,helpstring("Returns or sets the value of the source string's BSTR pointer. This property allows read/write access to the same value that is returned by Visual Basic's (hidden) StrPtr function.")]
      HRESULT __stdcall StringPtr(
         [in]          BSTR *            Source,
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"), propput,]
      HRESULT __stdcall StringPtr(
         [in]          BSTR *            Source,
         [in]            long            NewValue
      );

       [entry("GetMem4"), propget,helpstring("Returns or sets the value of an array's SAFEARRAY descriptor pointer. This property allows read/write access to the value referenced by the pointer returned by ArrPtr. Use StrSAPtr for string arrays to prevent the implicit ANSI/Unicode conversion.")]
      HRESULT __stdcall SAPtr(
         [in]          SAFEARRAY(void) *   Array,
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"), propput,]
      HRESULT __stdcall SAPtr(
         [in]          SAFEARRAY(void) *   Array,
         [in]          long               NewValue
      );

       [entry("GetMem4"), propget,helpstring("Returns or sets the value of the SAFEARRAY descriptor pointer of a string array. This property allows read/write access to the value referenced by the pointer returned by StrArrPtr.")]
      HRESULT __stdcall StrSAPtr(
         [in]          SAFEARRAY(BSTR) *   Array,
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"), propput,]
      HRESULT __stdcall StrSAPtr(
         [in]          SAFEARRAY(BSTR) *   Array,
         [in]          long               NewValue
      );
      
       [entry("GetMem4"),propget,helpstring("Expects a ByRef object argument and returns or sets the value of the object pointer. This property allows read/write access to the same value that is returned by ObjPtr.")]
      HRESULT __stdcall ObjectPtr(
         [in]          void *             Object,      // IUnknown **
         [out, retval]   long *            lpRetVal
      );
       [entry("PutMem4"),propput,]
      HRESULT __stdcall ObjectPtr(
         [in]          void *             Object,      // IUnknown **
         [in]          long               NewValue
      );
      
       [entry("GetMem4"),propget,helpstring("Returns or sets the value of the source object's VTable interface pointer. This property allows read/write access to the value referenced by the pointer returned by both ObjPtr and ObjectPtr. Should not be used on objects equal to Nothing.")]
      HRESULT __stdcall VTablePtr(
         [in]          IUnknown *         Object,
         [out, retval]   long *            Value
      );
       [entry("PutMem4"),propput,]
      HRESULT __stdcall VTablePtr(
         [in]          IUnknown *         Object,
         [in]          long               NewValue
      );

       [entry("GetMem4"),helpstring("Assigns a 32-bit dword value from the source to the destination parameter's memory location.")]
      HRESULT __stdcall AssignDWord(
         [in]      long               Source,
         [in, out]   void *               Destination
      );

   };

};

Для компиляции введите в командоной строке или пропишите в .BAT-файле:
Код: Выделить всё
cd C:\Program Files\Microsoft Visual Studio\VC98\Bin\
MIDL.exe mem4.idl

Добавьте полученный TLB-файл в VB (меню Project -> References -> Browse..) *
Доступные методы можно посмотреть по F2.

* Перед использованием Type Library, импортирующей msvbvm60.dll, установите Visual Studio Service Pack 6.

Ваш пример с использованием Type Library:
Код: Выделить всё
Option Explicit

Sub Main()
  Dim myvar As Long
  myvar = 1234
  CopyMyVar VarPtr(myvar)
End Sub

Public Sub CopyMyVar(ByVal VarAddr As Long)
  MsgBox Mem(VarAddr)  'показывает 1234
End Sub

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: IDE рушится при работе с GetMem

Сообщение Хакер » 31.07.2011 (Вс) 11:28

Filyus писал(а):Используйте Type Library, тогда вызовы будут быстрее и удобнее.

viewtopic.php?f=68&t=42926
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

VBTerminator
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 415
Зарегистрирован: 19.11.2008 (Ср) 20:10

Re: IDE рушится при работе с GetMem

Сообщение VBTerminator » 31.07.2011 (Вс) 17:23

Всем большое спасибо!

Я думал, что это проблема областей видимости, а оказалось - банальная опечатка!


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

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

Сейчас этот форум просматривают: AhrefsBot, Yandex-бот и гости: 31

    TopList  
cron