Дааааа лопухнулся я, уже замкнуло... писал то я в HKCU, а читал с HKLM )
На второй вопрос все верно, посмотрел, но ожидал увидеть несколько другое...
теперь у меня еще вопрос, объсните мне разницу между
push eax
pop hWin
И
mov hWin, eax
посути дела, они ведь делают одно и тоже, только первый закладывает в стек, а потом извлекает уже под другим именем правильно понимаю? а во втором случае в hWin копируется значение из eax? Или может есть какая то более существенная разница между этим?
Теперь у меня вторая часть вопроса.
Все нормально, значение устанавливаю и получаю, а что касается сравнения строки то тут MASM, а точнее RadASM ругается, вот что я делаю:
.if Value==SsValYes
;SHOW IN TRAY
invoke MessageBox,hWin, addr SsSubKey, addr STsKey,MB_OK
.endif
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
.if Value==SsValYes
;Auto Load With Windows
.endif
Мне кажется вся проблема вот в чем, правильно я понимаю и как от это перебороть?:
...
SsValYes db 'Yes',0
...
Value db 255 dup(0)
...
3. Что можете посоветовать для обучения, может есть какая книженция хорошая, как в электронном виде так и в печатном издании?
Многие начинают изучение ассемблера с DOS, но я не могу понять зачем мне знать все прерывания доса, которые в винде не используется, или я ошибаюсь?
4. ну вот вроде бы и все
Дааааа лопухнулся я, уже замкнуло... писал то я в HKCU, а читал с HKLM )
На второй вопрос все верно, посмотрел, но ожидал увидеть несколько другое...
теперь у меня еще вопрос, объсните мне разницу между
push eax
pop hWin
И
mov hWin, eax
посути дела, они ведь делают одно и тоже, только первый закладывает в стек, а потом извлекает уже под другим именем правильно понимаю? а во втором случае в hWin копируется значение из eax? Или может есть какая то более существенная разница между этим?
Теперь у меня вторая часть вопроса.
Все нормально, значение устанавливаю и получаю, а что касается сравнения строки то тут MASM, а точнее RadASM ругается, вот что я делаю:
.if Value==SsValYes
;SHOW IN TRAY
invoke MessageBox,hWin, addr SsSubKey, addr STsKey,MB_OK
.endif
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
.if Value==SsValYes
;Auto Load With Windows
.endif
Мне кажется вся проблема вот в чем, правильно я понимаю и как от это перебороть?:
...
SsValYes db 'Yes',0
...
Value db 255 dup(0)
...
3. Что можете посоветовать для обучения, может есть какая книженция хорошая, как в электронном виде так и в печатном издании?
Многие начинают изучение ассемблера с DOS, но я не могу понять зачем мне знать все прерывания доса, которые в винде не используется, или я ошибаюсь?
4. ну вот вроде бы и все
Дааааа лопухнулся я, уже замкнуло... писал то я в HKCU, а читал с HKLM )
На второй вопрос все верно, посмотрел, но ожидал увидеть несколько другое...
теперь у меня еще вопрос, объсните мне разницу между
push eax
pop hWin
И
mov hWin, eax
посути дела, они ведь делают одно и тоже, только первый закладывает в стек, а потом извлекает уже под другим именем правильно понимаю? а во втором случае в hWin копируется значение из eax? Или может есть какая то более существенная разница между этим?
Теперь у меня вторая часть вопроса.
Все нормально, значение устанавливаю и получаю, а что касается сравнения строки то тут MASM, а точнее RadASM ругается, вот что я делаю:
.if Value==SsValYes
;SHOW IN TRAY
invoke MessageBox,hWin, addr SsSubKey, addr STsKey,MB_OK
.endif
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
.if Value==SsValYes
;Auto Load With Windows
.endif
Мне кажется вся проблема вот в чем, правильно я понимаю и как от это перебороть?:
...
SsValYes db 'Yes',0
...
Value db 255 dup(0)
...
3. Что можете посоветовать для обучения, может есть какая книженция хорошая, как в электронном виде так и в печатном издании?
Многие начинают изучение ассемблера с DOS, но я не могу понять зачем мне знать все прерывания доса, которые в винде не используется, или я ошибаюсь?
4. ну вот вроде бы и все
Ну, для начала, забудь, как сравниваются строки в VB. Строк, как таковых, не существует. Это всё, как писал некто, "от лукавого". Переменные бывают: BYTE, WORD, DWORD, QWORD, TWORD, по-моему, так называются. Проц не работает со строками. Только с числами.
Когда ты хочешь получить доступ к строке, ты должен получить ЧИСЛО - адрес ячейки в памяти, где начинается массив чисел, являющихся кодами символов. Чтобы сравнить две строки, ты должен побайтно сравнивать два числа - записанное по адресу первой строки и по адресу второй строки, например так:
str1 db "stroka1",0
str2 db "stroka2",0
invoke lstrcmp, addr str1, addr str2
ф-ция lstrcmp сравнивает строки, начинающиеся по адресам str1 и str2. Результат возвращает в еах. Если еах отрицательное число- str1 меньше чем str2, если положительное - str1 больше чем str2, если ноль - одинаковые.
Ф-ций по работе со строками достаточно много. Описание можно найти в masm32lib - help'e или в msdn.
Можешь сам составить какие-нибудь ф-ции. Например lstrcmp меня не очень устраивала в плане работы с русским алфавитом, да и скорости хотелось поболее, поэтому написал свою. Для примера тебе вот она:
CmpStrICyr proc uses esi edi Str1:DWORD, Str2:DWORD
mov esi,Str1
mov edi,Str2
@Loop1:
mov al,byte ptr[esi]
mov cl,byte ptr[edi]
.if al >= 'А'
.if al <='Я'
add al,32
.endif
jmp @F
.elseif al >= 'A'
.if al <= 'Z'
add al,32
.endif
.endif
@@:
.if cl >= 'А'
.if cl <= 'Я'
add cl,32
.endif
jmp @F
.elseif cl >= 'A'
.if cl <= 'Z'
add cl,32
.endif
.endif
@@:
test al,cl
jz @Ret
@@:
cmp al,cl
jg short @Max
jl short @Min
inc esi
inc edi
jmp short @Loop1
xor eax,eax
jmp short @Ret
@Max: mov eax,1
jmp short @Ret
@Min: mov eax,-1
@Ret:
ret
CmpStrICyr endp
Входные параметры - адреса сравниваемых строк. На выходе в eax - как у lstrcmp : <0 ,0 или >0
и такие вещи : .if Value==SsValYes делать нельзя. Ты пытаешься на VB-шный манер сравнить две строки, даже не строки, а два адреса в памяти, а это даже не содержимое этих адресов.
К тому же такой инструкции у процессора нет, потому RadAsm и ругается: нельзя сравнивать два непосредственных операнда. Загрузи один из них в регистр и сравнивай второй уже с регистром. Хотя результат будет неверным, но ругаться не будет
А сравнить их можно так:
invoke lstrcmpi, addr Value, addr SsValYes
и ф-ция побайтно будет считывать значения ячеек памяти по адресам Value и SsValYes, и сравнивать их между собой. Если они равны, то будут проверяться содержимое следующих ячеек: Value +1 SsValYes+1 и т.д. пока не закончится одна из строк, либо пока не будут найдены несовпадающие ячейки.
lstrcmpi отличается от lstrcmp тем, что сравнивает независимо от регистра букв.
Можно использовать мою ф-цию:
invoke CmpStrICyr, addr Value, addr SsValYes
А вообще почаще заглядывай в masm'овские хэлпы (Их там несколько: по масму, по masm32lib и т.д.) Там куча всяких ф-ций, в т.ч. и по строкам (masm32lib)
И вот тебе ссылка, там достаточно много инфы для начинающих, причем многое на русском языке:
http://asm.shadrinsk.net/
что касается
push eax
pop hWin
можно сделать и mov hWin,eax.
Но такой фокус не пройдёт, если у тебя пересылка межде двумя ячейками памяти: тут нужно делать push Val1
pop Val2
либо
mov eax, Val1
mov Val2, eax
И ещё: в комплекте с masm'ом куча всяких примеров. Поковыряй их. В Яндексе можешь поискать книгу Юрова по асму. Там правда ошибок хватает, но и полезное можно найти.
Насчет строк понял всю фишку...
по поводу функции, то вот что я нашел в справочнике, но что то не совсем соображается как оно все работает:
CMPS/CMPSB/CMPSW/CMPSD
(CoMPare String Byte/Word/Double word operands)
Сравнение строк байтов/слов/двойных слов
.data
obl1 db 'Строка для сравнения'
obl1 db 'Строка для сравнения'
a_obl1 dd obl1
a_obl2 dd obl2
.code
...
cld
mov cx,20
lds si,a_obl1
les di,a_obl2
repe cmpsb
jnz m1
...
...
m1:
...
В этом примере строка сравнивается побайтно, я так понимаю..., a_obl1 dd obl1 - этой строкой не совсем понятно, что мы делаем.
>mov eax, Val1
>mov Val2, eax
всеровно не могу понять, почему нельзя сделать mov Val2, Val1 - и зачем задействовать регистр eax?
Твою функцию я обязательно добавлю в свою библиотеку кодов
Юрова книга у меня есть, первые несколько глав я осилил, но потом пошли какие то страшные примеры в которых ничего не понять, вообщем как мне показлось она оказлась для меня сложной, наверное мне надо читать ее уже на втором этапе...
Сейчас пойду смотреть ссылку...
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
invoke lstrcmp, addr Value, addr SsValYes
.if eax==0
invoke MessageBox,hWin, addr a2, addr STsKey,MB_OK;Auto Load With Windows
.endif
Все работае нормально, строки сравниваются, но есть одна непонятка...
Если в реестре на двух значения стоит 'No', тогда не отображется MessageBox;
если в реестре на первом значении стоит 'No', а на втором 'Yes', то все как положено выводиться сообщение из второго куска;
если в реестре на дух значениях стоит 'Yes', то показываются два сообщения;
--------НО---------
стоит мне поставить на первом значении 'Yes', а на втором поставить 'No', то отображаются всеровно два сообщения, почему так не могу понять...
получается, что этот кусок дает ложный результат:
invoke lstrcmp, addr Value, addr SsValYes
.if eax==0
invoke MessageBox,hWin, addr a2, addr STsKey,MB_OK;Auto Load With Windows
.endif
Прямо загдака какая-то...
a_obl1 dd obl1 - это пример, как в переменную a_obl1 занести адрес obl1. obl1-это адрес в памяти первого байта строки, а a_obl1-это переменная, в которой содержится этот адрес.
почему нельзя сделать mov Val2, Val1
Потому, что нет у процессора такой инструкции - переслать значение между двумя ячейками памяти. Не бывает. Можно пересылать между двумя регистрами, между регистром и памятью, между памятью и регистром, но не между двумя ячейками памяти. Не заложено такое в процессоре. Поэтому либо через регистр либо через стек.
Ещё скачай туториалы IcZelion с wasm'a. Они с переводом, достаточно доступно. Часть примеров из IcZelion поставляется вместе с masm'ом. Когда инсталлируешь его, они складываются в папку masm32\icztutes. Там же (на сайте) есть несколько статей на самом начинающем уровне. Будет полезно.
Что касается двух MessageBox'ов - чуть позже, сейчас надо бежать по делам
И ещё раз: отрешись от VB-привычек. У тебя есть только ячейки памяти, скомпонованые по 8, 16,32 штуки, и есть регистры процессора. Всё что делаешь - это работа я ячейками и их содержимым.
По поводу вышесказанного СПАСИБО, здраво объяснил, тебе бы книги писать(для таких как я)!
Теперь я смело могу понимать почему нельзя пересылать значения между памятью и память, потому что нету такой команды, но это можно сделать посредством закладывания в стек и извелчения, можно сделать через регистры(это я сам собой горжусь, потому как начинаю понимать )
Но, вопрос про MessageBox'ы я решить не смог, поэтому не снимается
Стараюсь отвыкать, но отвыкается не сразу, но думаю со временем должно придти, с васма я скачал кучу всего, включая Iczelion, версию сайта в оффлайне, форум сайта за какоето число и еще кучу всего
по поводу Iczeliona - то тема классная, вот только там не описывается про сам ассемблер, а больший уклон идет под программирование форточек...
Используй окно Output Window RadAsm'a, чтобы посмотреть, где и что у тебя происходит. Это наподобие Debug.Print в VB (окошко находится внизу IDE). В свой код вставь такие вещи:
lea eax, Value ; в еах - адрес строки Value
PritStringByAddr eax ; вывод в Output Window содержимого строки
PrintDec eax ; печатает содержимое еах
т.е. сделай так:
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
lea eax, Value
PritStringByAddr eax
lea eax, SsValYes
PritStringByAddr eax
invoke lstrcmp, addr Value, addr SsValYes
.if eax==0
invoke MessageBox,hWin, addr a2, addr STsKey,MB_OK;Auto Load With Windows
.endif
Чтобы работали эти ф-ции вывода в OutPut Window, не забудь об инклюдах:
include C:\masm32\RadASM\Masm\inc\debug.inc
includelib C:\masm32\RadASM\Masm\lib\debug.lib
1. Посмотри, что у тебя будет в Value перед первым и перед вторым сравнением. Если будет в обоих случаях "Yes", то перед вторым вызовом попробуй обнулить Value, возможно, что если Value не пустая перед вызовом Reg
2. В RegGetValProc после первого вызова RegQueryValueEx сразу же вставь еще раз её вызов, точно такой же, т.е. так:
первым вызовом заполнится lType и lngDataLen, а вторым с уже заполненными lType и lngDataLen будет считываться само значение. Так правильней.
3. Когда ты вызвал из своего кода RegGetValProc, по возвращению из неё проверяй, что в еах. Я не от нечего делать возвращаемые ею значения определил как код успешности или неуспешности чтения ключа . Если ноль - значит была ошибка чтения ключа. В этом случае возможно, что в Value осталось предыдущее значение т.е. "Yes", поэтому и второе сравнение показывает, что считано "Yes". Т.е. примерно так:
Ну и плюс впечатай куски которые выводят в OutPut Window информацию
А вообще, чтобы наверняка ответить на вопрос, надо иметь код, т.к. кроме того, что ты написал, много чего используется в вызовах функций, и возможно, там что-то неправильно.
Пробовал сделать два параметра, и один Yes, другой - No. Считывал сначала который Yes, затем который No. Всё нормально, один MessageBox (c Yes).
Вот ещё один вариант ф-ции чтения из реестра. Входные и выходные параметры те же, что и в первый раз писал. Попробуй с этим, хотя у меня оба варианта корректно читают независимо от того, какие значения имеют считываемые параметры, и независимо от того в каком порядке Yes и No.
;#########################################################################
RegGetValue proc hKey:DWORD,sSubKey:DWORD,sValueName:DWORD,sValue:DWORD
LOCAL lngDataLen:DWORD
local hHandleKey:DWORD
local lType :DWORD
;открываем ключ, если успешно, в еах будет 0, в hHandleKey - хэндл открытого ключа
invoke RegOpenKeyEx,hKey,sSubKey,NULL,KEY_READ,addr hHandleKey
cmp eax,ERROR_SUCCESS ; проверка на успешность открытия
jne Exit_Error ; если ключ не открыт (ошибка) - выходим с eax==0
; запрашиваем длину значения параметра sValueName - lngDataLen, и его тип(строк, дворд и т.д.) - lType
invoke RegQueryValueEx,hHandleKey,sValueName,NULL,addr lType,sValue,addr lngDataLen
cmp lType, REG_SZ ; проверка на тип значения параметра
jne Exit_Error ; если не строковое значение - выходим с eax==0
cmp lngDataLen,0 ; проверка на длину значения параметра
je Exit_Error ; если ноль - выходим с eax==0
; запрашиваем само значение параметра sValueName, теперь получаем само значение в sValue
invoke RegQueryValueEx,hHandleKey,sValueName,NULL,addr lType,sValue,addr lngDataLen
cmp eax,ERROR_SUCCESS
jne Exit_Error
;закрываем ключ
invoke RegCloseKey,hHandleKey
;если мы добрались досюда, значит всё было считано нормально, само значение записано по адресу sValue
mov eax,1 ;отмечаем, что всё нормально(если из ф-ции мы возвращаем 1 - всё нормально)
jmp Exit_Success ; выходим
Exit_Error:
;если мы оказались здесь, то была ошибка, закрываем ключ
invoke RegCloseKey,hHandleKey
; обнуляем еах (если из ф-ции мы возвращаем ноль - была ошибка)
xor eax,eax
Exit_Success:
ret
RegGetValue endp
Чтобы легче разобраться, с комментариями написал.
И ещё: в пакете RadAsm'a есть примеры использования PrintDec, PrintHex, PrintStringByAddr и т.д. И кроме того, есть возможность ставить брекпоинты на строках кода и смотреть состояния регистров и флагов процессора в точках останова.
все разобрасля вроде как,
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr STsKey, addr Value
invoke lstrcmp, addr Value, addr SsValYes
.if eax==0
invoke MessageBox,hWin, addr a1, addr STsKey,MB_OK;SHOW IN TRAY
.endif
invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
;invoke RegGetValProc,HKEY_CURRENT_USER, addr SsSubKey, addr AWsKey, addr Value
;lea eax, Value
;PrintStringByAddr eax
invoke lstrcmp, addr Value, addr SsValYes
;PrintDec eax
.if eax==0
invoke MessageBox,hWin, addr a2, addr STsKey,MB_OK;Auto Load With Windows
.endif
В Value, так и продолжало находиться Yes, после чего шло сравнение и понятное дело они были равны, ну и выполнялся второй MessageBox, странно я бы не вжизь не догадался сделать второй раз вызов
invoke RegQueryValueEx,hHandleKey,sValueName,NULL,addr lType,sValue,addr lngDataLen
Ну теперь вроде вопрос пока нет, но это не надолго ))
RegQueryValueEx чтобы вернула нормальный результат, должна иметь на входе тип считываемого значения и его длину. При первом вызове у нас нет этих данных, неизвестна длина и тип. И ф-ция заполняет сама эти два входных параметра и второй вызов уже нормально проходит.
Можно сделать и один вызов так:
invoke RegQueryValueEx,hHandleKey,sValueName,NULL,REG_SZ,sValue,3
Но такой вариант прокатит только если заранее известно, что параметр строковый и длина значения - 3 байта(вместе с terminated null). Для "No" - подойдёт, для "Yes" - нет, т.к. Yes не влезает со своим нулём в 3 байта. В этом случае в eax вернётся ошибка ERROR_MORE_DATA, а состояние буфера по адресу sValue будет неопределённым.
Всё это описано в msdn, читай )