Работа с командной строкой в masm32

Тема в разделе "WASM.BEGINNERS", создана пользователем assch, 4 июн 2017.

  1. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    Чтобы узнать какие прописаны значения в командной строке
    нужно воспользоватся тандемом функций

    Код (ASM):
    1. call GetCommandLineW
    2. push offset pTemp
    3. push eax
    4. call CommandLineToArgvW
    После отработки в переменной - pTemp
    будет прописано количество параметров
    а на выходе в регистре - eax
    будет указатель на созданный список параметров
    который является массивом строк в формате - UNICODE

    В некоторых случаях мягко говоря это не совсем удобно
    Раньше я не сталкивался с командной строкой по причине ненадобности
    и вот теперь когда мне понадобилось обработать командную строку
    я мягко говоря был крайне удивлён что не существует функции
    для обработки параметров командной строки в формате - ASCII

    По этой причине я написал пользовательскую функцию - CommandLine$
    и завернул её в макропроцедуру
    и если кому интересно можно ознакомится с этой реализацией
    Макрос имеет незатейлевое название с префиксом - @CommandLine

    Код (ASM):
    1. @CommandLine MACRO p1:= <32>
    2. local adr
    3. .data?
    4. adr byte p1 dup(?)
    5. .code
    6. push offset adr
    7. call CommandLine$
    8. ENDM
    У макроса только один параметр и в нём по умолчанию прописано - 32
    то есть если макрос объявить без параметра то в сегменте - .data?
    пропишется буфер размером 32 байта под четырёх-байтные данные
    если мысленно применить байтное смещение в буфере
    то это будет выглядеть так:

    [0-3] числовое значение (количество параметров)
    [4-7] адрес первого параметра (как правило имя или путь экзешника)
    [8-11] адрес второго параметра
    [12-15] адрес третьего параметра

    ну и так далее по интуитивно понятной логике
    в 32 байтном буфере по умолчанию
    уместится 7 адресов параметров с нулевым байтом в конце
    плюс первоначальный параметр (число этих параметров)

    Если вам потребуется больше или меньше параметров
    то размер буфера нужно увеличивать или уменьшать кратно четырём байтам
    но тогда макрос придётся прописывать с параметром
    если например нужно больше то так - @CommandLine 40
    в этом случае в буфере можно поместить адреса 9 параметров
    а если например нужно меньше то так - @CommandLine 12
    в этом случае в буфере можно поместить адреса только 2 параметров
    но я думаю 32 байтный буфер по умолчанию
    где макрос можно прописывать просто без параметра - @CommandLine
    это выше крыши хотя конечно кому как

    Пользовательская функция:

    Код (ASM):
    1. CommandLine$ proc uses esi edi pBuf:dword
    2. ;----------------------------------------
    3. f GetCommandLine
    4. xchg esi,eax
    5. mov edi,pBuf
    6. push edi
    7. xor ecx,ecx
    8. xor edx,edx
    9. @@:
    10. mov al,byte ptr [esi]
    11. ;------------------------
    12. .if al == 0
    13. jmp @f
    14. .endif
    15. ;------------------------
    16. .if al == 20h
    17. mov byte ptr [esi],0
    18. xor ecx,ecx
    19. ;------------------------
    20. .else
    21. ;----------------
    22. .if ecx == 0
    23. inc edx
    24. inc ecx
    25. add edi,4
    26. mov dword ptr [edi],esi
    27. .endif
    28. ;----------------
    29. .endif
    30. ;------------------------
    31. inc esi
    32. jmp @b
    33. @@:
    34. pop eax
    35. mov dword ptr [eax],edx
    36. ;----------------------------------------
    37. ret
    38. CommandLine$ endp
    На выходе в регистре - eax
    будет адрес созданного буфера
    Проверить работоспособность можно этой конструкцией

    Код (ASM):
    1. @CommandLine
    2.  
    3. mov ecx,dword ptr [eax]
    4. .while ecx
    5. add eax,4
    6. mov edx,dword ptr [eax]
    7. ;---------------
    8. push eax
    9. push ecx
    10. invoke MessageBoxA,0,edx,0,32
    11. pop ecx
    12. pop eax
    13. ;---------------
    14. dec ecx
    15. .endw
    Проверять лучше бат-файлом
    создать бат-файл и положить его рядом с вашим экзешником
    в бат-файле прописать например вот так:

    Код (ASM):
    1. testing.exe   Parametr_1   Parametr_2    Parametr_3
    имя экзешника я применил - testing
    у вас оно может быть любое другое
     
    yashechka и Mikl___ нравится это.
  2. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    В функции - CommandLine$
    первой строчкой прописано - f GetCommandLine
    нужно вместо этого прописать - call GetCommandLine
    сам я вместо макроса - invoke пользуюсь своим макросом - f
    по этому забыл подправить чтобы вам было понятно
    Ещё раз прошу прощения
     
  3. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    assch,
    Если уж пишешь код с намеком на библиотечность, то лучше сразу что-нибудь типа getopt запилить. Полезней же, чем просто макросами функционал апи дублировать.
     
  4. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    rmn,
    я просто предложил определённую схему для работы с командной строкой
    но с большим бы интересом посмотрел ваше видение подобной реализации
    как говориться век живи век учись
     
    Mikl___ нравится это.
  5. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    В пользовательской функции я не учёл применения в параметрах апострофов
    а так как функция пробелы интерпретирует как разделители параметров
    то при применении апострофов это не приемлемо

    Для этого поставил фильтр который будет работать тривиально в лоб
    при захвате одного из апострофов (" - 22h) или (' - 27h)
    фильтр дождётся пока открывающий апостроф не закроется
    при работе фильтра пробелы будут игнорироватся
    например если в бат-файле прописать

    Код (ASM):
    1. testing.exe   Parametr_1   "C:\Program Files\Windows Media Player\wmplayer.exe"    Parametr_3
    функция разложит командную строку на четыре параметра

    1 - testing.exe
    2 - Parametr_1
    3 - C:\Program Files\Windows Media Player\wmplayer.exe
    4 - Parametr_3

    В логике функции - CommandLineToArgvW
    не много более расширенная интерпретация работы с двойным апострофом
    да да именно с двойным потому что одиночный апостроф она игнорирует

    в чистом виде как это делает - CommandLineToArgvW
    в моей пользовательской функции сделать это не возможно
    потому что это совершенно два разных подхода
    библиотечная функция - CommandLineToArgvW
    помимо буфера командной строки
    динамически выделяет свой буфер под прописанные параметры
    и этот буфер програмист должен потом по правилам хорошего тона закрыть
    а моя функция работает только с буфером командной строки
    в котором вместо разделяемых пробелов прописывает нули
    попутно заполняя сегментный буфер
    соответствующими адресами взятыми из буфера командной строки

    Я думаю простого фильтра для апострофов который работает в лоб
    для большинства случаев будет вполне премлемо
    кстати говоря этот фильтр прекрасно работает с любым из апострофов
    а вот функция - CommandLineToArgvW
    почему то не хочет работать с одиночным апострофом
    корректно обрабатывая только двойной апостроф

    Исправленная пользовательская функция с фильтром для апострофов

    Код (ASM):
    1. CommandLine$ proc uses esi edi pBuf:dword
    2. ;----------------------------------------
    3. call GetCommandLine
    4. xchg esi,eax
    5. mov edi,pBuf
    6. push edi
    7. xor ecx,ecx
    8. xor edx,edx
    9. @@:
    10. mov al,byte ptr [esi]
    11. ;------------------------
    12. .if al == 0
    13. jmp @f
    14. .endif
    15. ;------------------------
    16. .if al == 22h || al == 27h
    17. mov cl,al
    18. mov byte ptr [esi],0
    19. inc esi
    20. add edi,4
    21. mov dword ptr [edi],esi
    22. inc edx
    23. loc_1:
    24. mov al,byte ptr [esi]
    25. ;------------
    26. .if al == 0
    27. jmp @f
    28. .endif
    29. ;------------
    30. .if al == cl
    31. mov byte ptr [esi],0
    32. xor ecx,ecx
    33. inc esi
    34. jmp @b
    35. .endif
    36. ;------------
    37. inc esi
    38. jmp loc_1
    39. .endif
    40. ;------------------------
    41. .if al == 20h
    42. mov byte ptr [esi],0
    43. xor ecx,ecx
    44. ;------------------------
    45. .else
    46. ;----------------
    47. .if ecx == 0
    48. inc edx
    49. inc ecx
    50. add edi,4
    51. mov dword ptr [edi],esi
    52. .endif
    53. ;----------------
    54. .endif
    55. ;------------------------
    56. inc esi
    57. jmp @b
    58. @@:
    59. pop eax
    60. mov dword ptr [eax],edx
    61. ;----------------------------------------
    62. ret
    63. CommandLine$ endp
    Можно конечно сделать обработку командной строки
    используя функцию - CommandLineToArgvW
    и потом своим алгоритмом или функцией - WideCharToMultiByte
    добиться желаемого результата но для этого как минимум
    понадобится подключить библиотеку - Shell32.dll
    и дополнительный динамический или сегментный буфер

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

    Я наверное не ошибусь если предположу что у любого программиста
    таких (пользовательских инструментов) вагон и маленькая тележка