Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Assembler FAQ > Загрузка Интернет страницы, через прокси-сервер, используя, библиотеку wininet.


Автор: Катька 03.11.07, 12:41
 
Загрузка Интернет страницы, через прокси-сервер, используя, библиотеку wininet.

Если пользоваться библиотекой winsock Интернет-страницу загрузить можно, но сделать это гораздо, сложнее ;), поэтому, я покажу - способ загрузки страницы по средствам библиотеки wininet. Плюс этот функционал будет работать, через прокси-сервер используя функцию UrlMkSetSessionOption из библиотеки urlmon.

Функции WinInet API

Разберём все функции по порядку и рассмотрим только те параметры, которые нам будут необходимы.

InternetOpen

Эта функция инициализирует WinInet и возвращает дескриптор, который необходим для вызова других функций WinInet. В случае неудачи возвращается NULL. Более подробную информацию об ошибке можно получить, вызвав функцию GetLastError.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    HINTERNET WINAPI InternetOpen(
        LPCTSTR lpszAgent,
        DWORD dwAccessType,
        LPCTSTR lpszProxyName,
        LPCTSTR lpszProxyBypass,
        DWORD dwFlags
    );

Параметры:
ПараметрОписание
lpszAgentЗадаёт имя приложения, которое используется как агент в HTTP протоколе. Сервер может определять агента с помощью переменной сервера HTTP_USER_AGENT. Если ваша программа собирается выдавать себя за MS Internet Explorer, передайте в этот параметр строчку "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914) "
dwAccessTypeЗадаёт необходимый тип доступа (прямой или через прокси). Мы будем использовать значение INTERNET_OPEN_TYPE_PRECONFIG, которое устанавливает тип доступа в соответствии с установками в реестре.


InternetConnect

Эта функция открывает FTP, HTTP или Gopher сессию для заданного сайта.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    HINTERNET InternetConnect(
        HINTERNET hInternet,
        LPCTSTR lpszServerName,
        INTERNET_PORT nServerPort,
        LPCTSTR lpszUsername,
        LPCTSTR lpszPassword,
        DWORD dwService,
        DWORD dwFlags,
        DWORD_PTR dwContext
    );

Параметры:
ПараметрОписание
hInternetДескриптор, полученный вызовом предыдущей функции.
lpszServerNameЗадаёт имя сервера. Это может быть обычное имя, например www.rsdn.ru, или адрес IP.
nServerPortНомер TCP/IP порта к которому мы собираемся подсоединиться. Мы будем использовать значене INTERNET_DEFAULT_HTTP_PORT для обычных соединений, либо INTERNET_DEFAULT_HTTPS_PORT для SSL соединений.
dwServiceТип сервиса - FTP, HTTP или Gopher. Мы будем использовать INTERNET_SERVICE_HTTP.


InternetOpenUrl

Функция принимает полный URL файла и возвращает указатель на него.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function InternetOpenUrl(hInet: HINTERNET;
                            lpszUrl: PChar;
                            lpszHeaders: PChar;
                            dwHeadersLength: DWORD;
                            dwFlags: DWORD;
                            dwContext: DWORD): HINTERNET; stdcall;

Параметры:
ПараметрОписание
HInetуказатель, полученный после вызова InternetOpen.
LpszUrURL , до которого нужно получить доступ. Обязательно должен начинаться с указания протокола, по которому будет происходить соединение. Поддерживаются следующие протоколы - ftp:, gopher:, http:, https:.
LpszHeaders содержит заголовок HTTP запроса.
DwHeadersLengthдлина заголовка. Если заголовок nil, то можно установить значение –1, и длина будет вычислена автоматически.
DwFlagsфлаг, задающий дополнительные параметры перед выполнением функции. Вот некоторые его значения: INTERNET_ FLAG_EXISTING_CONNECT, INTERNET_FLAG_HYPERLINK, INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP, INTERNET_FLAG_NO_AUTO_REDIRECT, INTERNET_FLAG_NO_CACH E_WRITE, INTERNET_FLAG_NO_COOKIES.
Возвращается значение TRUE, если соединение успешно, или FALSE - в противном случае.

InternetReadFile

Функция позволяет считывать данные, используя указатель, полученный в результате вызова InternetOpenUrl. Так же, как и все остальные функции, возвращает TRUE или FALSE. После завершения работы функции нужно освободить указатель Hfile, вызвав InternetCloseHandle(hUrlFile) .

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function InternetReadFile(hFile: HINTERNET;
                             lpBuffer: Pointer;
                             dwNumberOfBytesToRead: DWORD;
                             var lpdwNumberOfBytesRead: DWORD): BOOL; stdcall;

Параметры:
ПараметрОписание
HFileуказатель на файл, полученный после вызова функции InternetOpenUrl
LpBufferуказатель на буфер, куда будут заноситься данные.
DwNumberOfBytesToReadчисло байт, которое нужно причитать
lpdwNumberOfBytesReadсодержит количество прочитанных байтов. Устанавливается в 0 перед проверкой ошибок.

Вот, в принципе, и все об самых основных функциях, которые я пользовала в данной статье они находятся в библе wininet . ;) Структура INTERNET_PROXY_INFO для использования в функции UrlMkSetSessionOption загрузки страницы через проксю, включает в себя следующие параметры:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    typedef struct {
       DWORD dwAccessType;
       LPCTSTR lpszProxy;
       LPCTSTR lpszProxyBypass;
    }
где dwAccessType – тип прокси для открытия страницы; lpszProxy – собственно сам адрес и порт(прокси-адрес); lpszProxyBypass – использование прокси -сервера имеющего пароль на загрузку страниц через него в данном случае нам это не требуется ;)

Функция:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure UrlMkSetSessionOption (dwOption : Integer;
         var pBuffer : Pointer;
         dwBufferLength : Integer;
         dwReserved : Integer);
         stdcall; external 'URLMON' name 'UrlMkSetSessionOption'
где dwOption - опции прокси; pBuffer – сама структура INTERNET_PROXY_INFO; dwBufferLength – размер структуры, ну и конечно флаги направления…

Ну и наконец сам код, который загружает код страницы в поле :)

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ; pwi.asm
    .386
    .model flat,stdcall
    option casemap:none
     
    include \masm32\include\windows.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\wininet.inc
    include \masm32\include\urlmon.inc
     
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\urlmon.lib
    includelib \masm32\lib\wininet.lib
     
        _T macro p1, p2 ;макрос обработки строк
          local l
            ifb <p2>; Строка без имени
                .data
                    l   db p1, 0
                .code
                exitm   <addr l>
            else    ; Строка с именем
                .data
                    p1  db p2, 0
                .code
                exitm   <addr p1>
            endif
        endm
     
        IDC_INPUTDATA   equ 1000 ;окно приёма данных
        IDC_GETHOST     equ 1001 ;edit для хоста
        IDC_PROXI       equ 1002 ;edit для прокси
        IDC_LOAD        equ 1003 ;кнопка загрузить
        IDC_EXIT        equ 1004 ;выход
     
    ;=================
    ; Local prototypes
    ;=================
        WndProc     PROTO :DWORD,:DWORD,:DWORD,:DWORD
     
    .data
     ;прокси - адрес и порт  "218.7.13.186:80" < - пригодится ;)
      hInstance     dd 0
      AgetUser      db '}{}{}{',0;ЮзерАгент - название программы, которое будет отображатся на сервере
    ;дескрипторы wininet - функций
      hInternet     dd 0
      hOpenUrl      dd 0
      hConnect      dd 0
     
      ProxyHP       db 20 dup (?);буфер для прокси адреса
      
     .data?
      ByteWRite     dd ?;сколько байт записано
      StrokaIz      db 1024 dup (?) ;буфер для хоста
      iBuffer       dw 24000 dup (?);для получения данных
      busize        = $-iBuffer;размер буфера
      PiProxy       INTERNET_PROXY_INFO <>;структура для Proxy соединения
     
    .code
        start:
     
    ; #########################################################################
        invoke  GetModuleHandle, NULL
        mov     hInstance, eax
        invoke  DialogBoxParam,hInstance,_T("MAINDIALOG"),0,ADDR WndProc,0
        invoke  ExitProcess,eax
     
    ; #########################################################################
     
    WndProc proc hWin   :DWORD,
                 uMsg   :DWORD,
                 wParam :DWORD,
                 lParam :DWORD
     
        .if uMsg == WM_INITDIALOG
            invoke  SendMessage,hWin,WM_SETTEXT,0, _T("HtmlProxyGet")
     
        .elseif uMsg==WM_COMMAND
            mov     eax, wParam
            mov     edx, eax
            shr     edx, 16
            .if edx == BN_CLICKED
                .if ax == IDC_LOAD;берём адрес и порт прокси - сервера из Edit-control
                    invoke  GetDlgItemText,hWin,IDC_PROXI,addr ProxyHP,-1
                    ;опции прокси сервера
                    mov     PiProxy.dwAccessType, INTERNET_OPEN_TYPE_PROXY
                    ;адрес и порт
                    mov     PiProxy.lpszProxy,offset ProxyHP
                    ;функция создания Proxy сессии   опции прокси   параметры структуры   размер структуры
                    invoke  UrlMkSetSessionOption,INTERNET_OPTION_PROXY,addr PiProxy, SizeOf(INTERNET_PROXY_INFO),0
                    ;хост из Edit- control
                    invoke  GetDlgItemText,hWin,IDC_GETHOST,addr StrokaIz,-1
                    ;инициализация WinInet и возвращает дескриптора, который
                    ;необходим для вызова других функций WinInet
                    invoke  InternetOpen,addr AgetUser,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0
                    mov      hInternet,eax
                    ;открывает  HTTP  сессию для заданного сайта
                    invoke  InternetConnect, [hInternet],\;Дескриптор, полученный вызовом предыдущей функции.
                                            addr StrokaIz,\;хост
                                            INTERNET_DEFAULT_HTTP_PORT,\; для обычных соединений
                                            NULL,NULL,\
                                            INTERNET_SERVICE_HTTP,\;Тип сервиса
                                            0,\
                                            1
                    mov     [hConnect],eax
                    ;принимает полный URL файла и возвращает указатель на него.
                    invoke  InternetOpenUrl,[hInternet],\;указатель, полученный после вызова InternetOpen.
                      addr StrokaIz,\
                    0, 0,\
                    INTERNET_FLAG_RELOAD,\;флаг, задающий дополнительные параметры перед выполнением функции
                    0
                    mov     [hOpenUrl],eax
                    ;позволяет считывать данные, используя указатель,
                    ; полученный в результате вызова InternetOpenUrl.
                    ;Так же, как и все остальные функции, возвращает TRUE или FALSE
                    invoke  InternetReadFile, [hOpenUrl],\; указатель на файл, полученный после вызова функции InternetOpenUrl
                     addr (iBuffer),\;указатель на буфер, куда будут заноситься данные
                     busize ,\;число байт, которое нужно причитать
                      addr ByteWRite;содержит количество прочитанных байтов. Устанавливается в 0 перед проверкой ошибок.
                    ;выводим html - код
                    invoke  SetDlgItemText,hWin,IDC_INPUTDATA,  addr iBuffer
                    ;  закрытие дескрипторов вызванных wininet - функциями
                    invoke  InternetCloseHandle,hOpenUrl
                    invoke  InternetCloseHandle,hConnect
                    invoke  InternetCloseHandle,hInternet
                .elseif ax == IDC_EXIT
                    invoke  SendMessage, hWin, WM_CLOSE, 0, 0
                .endif
            .endif
     
        .elseif uMsg == WM_CLOSE
            invoke  EndDialog,hWin,0
     
        .else
            mov     eax, FALSE
            ret
        .endif
            mov     eax, TRUE
            ret
     
    WndProc endp
     
    ; ########################################################################
     
    end start

Диалог:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // wi.rc
    #define DS_MODALFRAME   0x80L
     
    #define WS_POPUP        0x80000000L
    #define WS_CHILD        0x40000000L
    #define WS_VISIBLE      0x10000000L
    #define WS_CAPTION      0x00C00000L
    #define WS_BORDER       0x00800000L
    #define WS_SYSMENU      0x00080000L
    #define WS_GROUP        0x00020000L
    #define WS_TABSTOP      0x00010000L
     
    #define ES_LEFT         0x00000000L
    #define ES_MULTILINE    0x00000004L
    #define ES_AUTOVSCROLL  0x00000040L
    #define ES_AUTOHSCROLL  0x00000080L
     
    #define IDC_INPUTDATA   1000
    #define IDC_GETHOST     1001
    #define IDC_PROXI       1002
    #define IDC_LOAD        1003
    #define IDC_EXIT        1004
     
    MAINDIALOG DIALOG 10, 15, 282, 199
    STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "MAINDIALOG"
    FONT 8, "MS Sans Serif"
    BEGIN
            CONTROL "", IDC_INPUTDATA, "EDIT", ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 8, 17, 264, 92
            CTEXT "Код страницы", -1, 8, 4, 264, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
            CTEXT "Нужный хост", -1, 8, 117, 264, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
            EDITTEXT IDC_GETHOST, 8, 128, 264, 12, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
            CTEXT "Прокси", -1, 8, 148, 264, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
            EDITTEXT IDC_PROXI, 8, 160, 264, 12, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
            DEFPUSHBUTTON "Загрузить", IDC_LOAD, 8, 180, 48, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
            PUSHBUTTON "Выход", IDC_EXIT, 224, 180, 48, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
    END

Компилируется:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    E:\masm32\bin\rc wi.rc
    E:\masm32\bin\ml /c /coff /nologo pwi.asm
    E:\masm32\bin\Link /SUBSYSTEM:WINDOWS pwi.obj wi.res
    Pause

Вот и всего то. ;) Конечно, нужно не забывать про обработку ошибок, здесь – это специально не сделано, чтобы нагляднее показать работу wininet функций. Для загрузки огромных сайтов нужно увеличить размер буфера. Также не забываем про указание префикса http протокола - «http://». Ну и конечно, всё зависит от прокси-сервера; приведённый в коде адрес 218.7.13.186:80 , самый быстродейственный на данный момент.

Удачи в компиляции. :rolleyes:

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)