wininet内部实现探索

wininet内部的探索

这里源代码都是reatos,有些是WIN2K的代码。

1:HINTERNET Handles

对外的定义winhttp.h 里面

这个就是我用的到句柄

typedef LPVOID HINTERNET;

typedef HINTERNET * LPHINTERNET;

这里就是一个指针,具体指向什么数据结构就看他的上下文了。(上下文可以看成是哪个函数调用的他)

MSDN说了一句很重要的话

Note that handle values are recycled quickly; therefore, if a handle is closed and a new handle is generated immediately, there is a good chance that the new handle has the same value as the handle just closed.

注意释放 HINTERNET句柄很可能会导致一些意想不到的问题。(后面写一个专门测试例子来验证)

2:InternetOpen 看看他做了什么,毕竟这个所有的根函数

MSDN解析:Initializes an application‘s use of the WinINet functions.

貌似说初始化wininet的函数。

我觉得是在一个进程里面建立起一个数据结构(我觉得这个不是系统的数据结构,而是一个进程的内部的数据结构)。

看一下在这个函数做了什么?

HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
    LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
{
    appinfo_t *lpwai = NULL;

    lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
    if (!lpwai) {
        SetLastError(ERROR_OUTOFMEMORY);
        return NULL;
    }

    lpwai->hdr.htype = WH_HINIT;
    lpwai->hdr.dwFlags = dwFlags;
    lpwai->accessType = dwAccessType;
    lpwai->proxyUsername = NULL;
    lpwai->proxyPassword = NULL;

    lpwai->agent = heap_strdupW(lpszAgent);
    if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
        INTERNET_ConfigureProxy( lpwai );
    else
        lpwai->proxy = heap_strdupW(lpszProxy);
    lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);

    TRACE("returning %p\n", lpwai);

    return lpwai->hdr.hInternet;
//这里在alloc_object做的。
//这里看是返回的索引,但我实际检测的时候,返回数组的地址,而不是索引,其实2种相同。
}

这个函数做了分配对应的INTERNET根的数据结构,同时把参数分配内存保存堆上。

我在vc6 测试InternetOpen.

void TestInternetOpen()

{

HINTERNET hInternetRoot = InternetOpen("fishclient",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);

printf("%u\n",(UINT_PTR)hInternetRoot);

//InternetCloseHandle(hInternetRoot);

}

第一次创建值都是固定,如果你没有释放的话,下次创建的值就偏移Int位置,看上面的函数,貌似return lpwai->hdr.hInternet;

返回的索引,但根据TestInternetOpen是不对的,后来我自己下了win2000的源代码,看了一下返回是内部数据结构的假的地址(类似索引),所以reactos反汇编确实不完全安装微软的源代码走的,而是通过自己理解再重写一遍,可以说提炼微软意思,然后用少量代码写出来(因为一些功能,reactos没有实现)。感谢这些前辈给我留下这么好的东西。

win2k 的InternetOpenA的代码

I

NTERNETAPI
HINTERNET
WINAPI
InternetOpenA(
    IN LPCSTR lpszAgent,
    IN DWORD dwAccessType,
    IN LPCSTR lpszProxy OPTIONAL,
    IN LPCSTR lpszProxyBypass OPTIONAL,
    IN DWORD dwFlags
    )

/*++

Routine Description:

    Opens a root Internet handle from which all HINTERNET objects are derived

Arguments:

    lpszAgent       - name of the application making the request (arbitrary
                      identifying string). Used in "User-Agent" header when
                      communicating with HTTP servers, if the application does
                      not add a User-Agent header of its own

    dwAccessType    - type of access required. Can be

                        INTERNET_OPEN_TYPE_PRECONFIG
                            - Gets the configuration from the registry

                        INTERNET_OPEN_TYPE_DIRECT
                            - Requests are made directly to the nominated server

                        INTERNET_OPEN_TYPE_PROXY
                            - Requests are made via the nominated proxy

                        INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY
                            - Like Pre-Config, but prevents JavaScript, INS
                                and other auto-proxy types from being used.

    lpszProxy       - if INTERNET_OPEN_TYPE_PROXY, a list of proxy servers to
                      use

    lpszProxyBypass - if INTERNET_OPEN_TYPE_PROXY, a list of servers which we
                      will communicate with directly

    dwFlags         - flags to control the operation of this API or potentially
                      all APIs called on the handle generated by this API.
                      Currently supported are:

                        INTERNET_FLAG_ASYNC
                            - if specified then all subsequent API calls made
                              against the handle returned from this API, or
                              handles descended from the handle returned by
                              this API, have the opportunity to complete
                              asynchronously, depending on other factors
                              relevant at the time the API is called

Return Value:

    HINTERNET
        Success - handle of Internet object

        Failure - NULL. For more information, call GetLastError()

--*/

{
    PERF_INIT();

    DEBUG_ENTER_API((DBG_API,
                     Handle,
                     "InternetOpenA",
                     "%q, %s (%d), %q, %q, %#x",
                     lpszAgent,
                     InternetMapOpenType(dwAccessType),
                     dwAccessType,
                     lpszProxy,
                     lpszProxyBypass,
                     dwFlags
                     ));

    DWORD error;
    HINTERNET hInternet = NULL;

    if (!GlobalDataInitialized) {
        error = GlobalDataInitialize();
        if (error != ERROR_SUCCESS) {
            goto quit;
        }
    }

    //
    // we are doing GetUserName here instead of in DLL_PROCESS_ATTACH
    // As every caller of wininet has to do this first, we ensure
    // that the username is initialized when they get to actually doing
    // any real operation
    //

    GetWininetUserName();

    //
    // validate parameters
    //

    if (!
         (
              (dwAccessType == INTERNET_OPEN_TYPE_DIRECT)
           || (dwAccessType == INTERNET_OPEN_TYPE_PROXY)
           || (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
           || (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
           || (
                (dwAccessType == INTERNET_OPEN_TYPE_PROXY)
                &&
                    (
                       !ARGUMENT_PRESENT(lpszProxy)
                    || (*lpszProxy == '\0')

                    )
              )
           || (dwFlags & ~INTERNET_FLAGS_MASK)
         )
       )
    {
        error = ERROR_INVALID_PARAMETER;
        goto quit;
    }

    GlobalHaveInternetOpened = TRUE;

    //
    // Initalize an auto proxy dll if needed,
    //  as long as the caller is allowing us free rein to do this
    //  by calling us with INTERNET_OPEN_TYPE_PRECONFIG.
    //

    //if ( dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG )
    //{
    //    if ( ! InitalizeAutoConfigDllIfNeeded() )
    //  {
    //      error = GetLastError();
    //
    //      INET_ASSERT(error != ERROR_SUCCESS);
    //
    //      goto quit;
    //  }
    //
    //

    INTERNET_HANDLE_OBJECT * lpInternet;

    lpInternet = new INTERNET_HANDLE_OBJECT(lpszAgent,
                                            dwAccessType,
                                            (LPSTR)lpszProxy,
                                            (LPSTR)lpszProxyBypass,
                                            dwFlags
                                            );
    if (lpInternet == NULL) {
        error = ERROR_NOT_ENOUGH_MEMORY;
        goto quit;
    }
    error = lpInternet->GetStatus();
    if (error == ERROR_SUCCESS) {
        hInternet = (HINTERNET)lpInternet;

        //
        // success - don't return the object address, return the pseudo-handle
        // value we generated
        //

        hInternet = ((HANDLE_OBJECT *)hInternet)->GetPseudoHandle();//这里强制转发基类指针调用函数。(微软这个时候已经用的C++来写了)

        //
        // start async support now if required. If we can't start it, we'll get
        // another chance the next time we create an async request
        //

        if (dwFlags & INTERNET_FLAG_ASYNC) {
            InitializeAsyncSupport();
        }
    } else {

        //
        // hack fix to stop InternetIndicateStatus (called from the handle
        // object destructor) blowing up if there is no handle object in the
        // thread info block. We can't call back anyway
        //

        LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();

        if (lpThreadInfo) {

            //
            // BUGBUG - incorrect handle value
            //

            _InternetSetObjectHandle(lpThreadInfo, lpInternet, lpInternet);
        }

        //
        // we failed during initialization. Kill the handle using Dereference()
        // (in order to stop the debug version complaining about the reference
        // count not being 0. Invalidate for same reason)
        //

        lpInternet->Invalidate();
        lpInternet->Dereference();

        INET_ASSERT(hInternet == NULL);

    }

quit:

    if (error != ERROR_SUCCESS) {

        DEBUG_ERROR(API, error);

        SetLastError(error);
    }

    DEBUG_LEAVE_API(hInternet);

    return hInternet;
}

---------------------------------------------------------------------------------------------

//我们看到这个数据结构所以我们一定要知道保存了,不过其实大概也能够猜到一些东西

typedef struct

{

object_header_t hdr;

LPWSTR  agent;

LPWSTR  proxy;

LPWSTR  proxyBypass;

LPWSTR  proxyUsername;

LPWSTR  proxyPassword;

DWORD   accessType;

} appinfo_t;

typedef struct _object_header_t object_header_t;

struct _object_header_t

{

WH_TYPE htype;

const object_vtbl_t *vtbl;

HINTERNET hInternet;

BOOL valid_handle;

DWORD  dwFlags;

DWORD_PTR dwContext;

DWORD  dwError;

ULONG  ErrorMask;

DWORD  dwInternalFlags;

LONG   refs;

INTERNET_STATUS_CALLBACK lpfnStatusCB;

struct list entry;

struct list children;

};

可以看出来这个就是链表所有的数据都保存在这里了。

这个结构会一些inertnet通用函数调用的,进行设置。

因为reactos 的 wininet的数据结构用的c来写,win2k用c++ 写。

但是意思表达一个意思,可能我觉得用c来写更能清晰,感觉的reacos代码非常好,有些技巧有必要自己慢慢的挖掘出来。

看一下指针

typedef struct {

void (*Destroy)(object_header_t*);

void (*CloseConnection)(object_header_t*);

DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL);

DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD);

DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*);

DWORD (*ReadFileExA)(object_header_t*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR);

DWORD (*ReadFileExW)(object_header_t*,INTERNET_BUFFERSW*,DWORD,DWORD_PTR);

DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*);

DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR);

DWORD (*FindNextFileW)(object_header_t*,void*);

} object_vtbl_t;

BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)

{

object_header_t *obj;

TRACE("%p\n", hInternet);

obj = get_handle_object( hInternet );

if (!obj) {

SetLastError(ERROR_INVALID_HANDLE);

return FALSE;

}

invalidate_handle(obj);

WININET_Release(obj);

return TRUE;

}

//关闭就比较明了,到引用为0就是放内部结构

总结:

inertOpen 确实跟MSDN说作用是一个意思

Initializes an application‘s use of the WinINet functions.

其实就是初始化一个重要的数据结构而已,然后插入到链表里面去。

其实HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,

LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)

参数已经说了这一切了;。

保存的客户端的名字,保存接受类型,保存代理。===这些都是关系到后面的请求怎么去请求的问题,比喻代理如果有了,那么socket连接的时候必须连接到代理的服务器去。所有这些信息保存内部数据结构。然后通过 HINTERNET 传递出去,带调用不同的函数。

时间: 2024-10-24 19:53:05

wininet内部实现探索的相关文章

Git内部原理探索

目录 前言 Git分区 .git版本库里的文件/目录是干什么的 Git是如何存储文件信息的 当我们执行git add.git commit时,Git背后做了什么 Git分支的本质是什么 HEAD引用 参考 @ 前言 洞悉技术的本质,可以让我们在层出不穷的框架面前仍能泰然处之.用了那么久的 Git,不懂点内部原理,那可不行!懂点原理可以让我们遇到问题的时候能够更好更快的理清解决问题的思路.博客原文 要真正读懂本文可能需要以下基础: 有 Git 使用经验 对 Git 的三个分区有所了解 熟悉常用的

Android内存泄露案例分析

一款优秀的Android应用,不仅要有完善的功能,也要有良好的体验,而性能是影响体验的一个重要因素.内存泄露是Android开发中常见的性能问题.这篇文章,通过我们曾经遇到的一个真实的案例,来讲述一个内存泄露问题,从发现到分析定位,再到最终解决的全过程. 这里把整个过程分为四个阶段: 第一阶段,现场勘查,分析Bug现象,找出有用线索: 第二阶段,初步推断,根据之前的线索,推断可能导致Bug的原因,并且进一步验证推断是否正确: 第三阶段,探究根源,找出导致Bug的真正原因: 第四阶段,解决方案,研

转:旅游推荐系统的演进

旅游推荐系统的演进 http://tech.meituan.com/travel-recsys.html 背景 度假业务在整个在线旅游市场中占据着非常重要的位置,如何做好做大这块蛋糕是行业内的焦点.与美食或酒店的用户兴趣点明确(比如找某个确定的餐厅或者找某个目的地附近的酒店)不同,旅游场景中的用户兴趣点(比如周末去哪儿好玩)很难确定,而且会随着季节.天气.用户属性等变化而变化.这些特点导致传统的信息检索并不能很好的满足用户需求,我们迫切需要建设旅游推荐系统(本文中度假=旅游). 旅游推荐系统主要

引擎下的PaaS, 第一章: kernel 命名空间

使事情简单化背后是非常繁重的工作.在dotCloud,我们将非常复杂的事务(例如部署和扩展web应用)打包进一个尽可能简单的环境中.但是我们在这样的环境中,如何进行工作呢?从kernel-level的虚拟化到监控,从高吞吐量忘了路由到分布式锁,从EBS处理到每分钟手机数百万的系统数据...如同一些人提到过的,弹性调度一个PaaS 就像是系统工程师的迪斯尼乐园. 本文是第一期文章,关于PaaS的架构和内部进行探索,并对dotCloud做更详细的说明.在第一段中,我们将介绍namespace,dot

DCGAN 论文简单解读

DCGAN的全称是Deep Convolution Generative Adversarial Networks(深度卷积生成对抗网络).是2014年Ian J.Goodfellow 的那篇开创性的GAN论文之后一个新的提出将GAN和卷积网络结合起来,以解决GAN训练不稳定的问题的一篇paper. 关于基本的GAN的原理,可以参考原始paper,或者其他一些有用的文章和代码,比如:GAN mnist 数据生成,深度卷积GAN之图像生成,GAN tutorial等.这里不再赘述. 一. DCGA

探索推荐引擎内部的秘密,第 3 部分: 深入推荐引擎相关算法 - 聚类

聚类分析 什么是聚类分析? 聚类 (Clustering) 就是将数据对象分组成为多个类或者簇 (Cluster),它的目标是:在同一个簇中的对象之间具有较高的相似度,而不同簇中的对象差别较大.所以,在很多应用中,一个簇中的数据对象可以被作为一个整体来对待,从而减少计算量或者提高计算质量. 其实聚类是一个人们日常生活的常见行为,即所谓"物以类聚,人以群分",核心的思想也就是聚类.人们总是不断地改进下意识中的聚类模式来学习如何区分各个事物和人.同时,聚类分析已经广泛的应用在许多应用中,包

探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探

"探索推荐引擎内部的秘密"系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用.同时在理论讲解的基础上,还会结合 Apache Mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法.本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎. 信息发现 如今已经进入了一个数据爆炸的时代,

探索推荐引擎内部的秘密

"探索推荐引擎内部的秘密"系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用.同时在理论讲解的基础上,还会结合 Apache Mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法.本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎. 信息发现 如今已经进入了一个数据爆炸的时代,

深入探索.NET内部了解CLR如何创建运行时对象

前言 SystemDomain, SharedDomain, and DefaultDomain. 对象布局和内存细节. 方法表布局. 方法分派(Method dispatching). 因为公共语言运行时(CLR)即将成为在Windows上创建应用程序的主角级基础架构, 多掌握点关于CLR的深度认识会帮助你构建高效的, 工业级健壮的应用程序. 在这篇文章中, 我们会浏览,调查CLR的内在本质, 包括对象实例布局, 方法表的布局, 方法分派, 基于接口的分派, 和各种各样的数据结构. 我们会使用