Push(Ret) всегда нужно делать (ну почти всегда) - мы же функцию вызываем, а у нее (у функций) всегда один сценарий:
0. Pop`аем число - количество параметров в стеке
1. Pop`аем параметры
2. что-то делаем
3. пушим результат
т.е. на выходе функции всегда в стеке есть значение, которое она туда поместила.
Вот смотри.
Последовательность:
Code: Select all
plugin.Call("D2F36B62-A470-418D-83A3-ED7A3710E5B5","45453CAC-499D-4B37-82B8-0A77F7BD087C") 5
компилится в
Code: Select all
00000000: MCODE_OP_PUSHSTR
00000001: "D2F36B62-A470-418D-83A3-ED7A3710E5B5"
00000014: MCODE_OP_PUSHSTR
00000015: "45453CAC-499D-4B37-82B8-0A77F7BD087C"
00000028: MCODE_OP_PUSHINT
00000029: 2
0000002B: MCODE_F_PLUGIN_CALL
0000002C: MCODE_OP_SAVE
0000002D: %
0000002E: MCODE_OP_KEYS
0000002F: Key: '5'
00000030: MCODE_OP_ENDKEYS
В 0x2c MCODE_OP_SAVE Pop`нет из стека то, что должен был пропушить MCODE_F_PLUGIN_CALL.
Если мы не сделаем Push(Ret) - стек улетит в трубу.
По поводу "ну почти всегда" (это касается только функций, семейства plugin.call и callplugin)
Здесь нужно пушить до вызова плагина, иначе наш Push... снова сорвет стек (последовательность то продолжается - в примере 0x2c)
Почему я убрал PushState?
Plugin.Call это замена F11, так? Я так думаю, что здесь нужно ввести ограничение - чтобы плагин не кидались макросами в середине исполнения... иначе получаем еще тот гимор (хотя, могу быть не прав). В принципе они могут запулить макрос, но в этом случае он станет в конец очереди.
We are the Borg. You will be assimilated.
So Say We All!