python - InternetCrackUrlW 不会填充结构化类中指针后面的字符串值

标签 python ctypes wininet

我正在尝试使用 InternetCrackUrl 解析 url WinINet 库中的函数。

此函数的“返回”值是通过 lpUrlComponents 参数完成的,该参数具有 defined structure .

我现在遇到的问题是我的结构化类仅检索数字字段中的值,DWORDINT,但所有字母数字字段/所有指针, >LPCWSTR 为空(在代码块末尾输出)。

我知道有问题的参数应该是指向变量的指针。我认为这是错误的部分。

我做错了什么?

编辑:我添加了使其在代码块末尾工作所需的几行。这已经在Win8.1和XP上进行了测试。

from ctypes import *
from ctypes.wintypes import *

dll = windll.wininet

url = LPCWSTR("http://user:password@www.host.com:8080/url-path?key=value")
url_length = DWORD(len(url.value))
flags = DWORD()

class URL_COMPONENTS(Structure):
    _fields_ = [
        ("dwStructSize", DWORD),
        ("lpszScheme", LPCWSTR),
        ("dwSchemeLength", DWORD),
        ("nScheme", INT),
        ("lpszHostName", LPCWSTR),
        ("dwHostNameLength", DWORD),
        ("nPort", INT),
        ("lpszUserName", LPCWSTR),
        ("dwUserNameLength", DWORD),
        ("lpszPassword", LPCWSTR),
        ("dwPasswordLength", DWORD),
        ("lpszUrlPath", LPCWSTR),
        ("dwUrlPathLength", DWORD),
        ("lpszExtraInfo", LPCWSTR),
        ("dwExtraInfoLength", DWORD),
    ]

url = LPCWSTR("http://user:password@www.host.com:8080/url-path?key=value")
url_length = DWORD(len(url.value))
flags = DWORD()
url_components = URL_COMPONENTS()

dll.InternetCrackUrlW.restype = c_bool

print "Output of initial question:"
print dll.InternetCrackUrlW(url, url_length, flags, byref(url_components))

for field in url_components._fields_:
     print field[0], getattr(url_components, field[0])

print "\nOutput of working:"

# Give the those lengths a nonzero value. == 0 do nothing, != 0 do something
url_components.dwHostNameLength = DWORD(-1)

dll.InternetCrackUrlW(url, url_length, flags, byref(url_components))

# Now we got the  string cut off at the start of the desired element.
print "lpszHostName:", url_components.lpszHostName

# And the length of the content.
print "dwHostNameLength:", url_components.dwHostNameLength

# Just cut it out and you get the desired result.
print "HostName:", url_components.lpszHostName[:url_components.dwHostNameLength]

Output of initial question output:
True
dwStructSize 60
lpszScheme None
dwSchemeLength 0
nScheme 3
lpszHostName None
dwHostNameLength 0
nPort 8080
lpszUserName None
dwUserNameLength 0
lpszPassword None
dwPasswordLength 0
lpszUrlPath None
dwUrlPathLength 0
lpszExtraInfo None
dwExtraInfoLength 0

Output of working:
lpszHostName: www.host.com:8080/url-path?key=value
dwHostNameLength: 12
HostName: www.host.com

最佳答案

下面是 URL_COMPONENTS 结构的实现,它将所有字符串缓冲区设置为固定大小,默认为 512 个字符。

from ctypes import *
from ctypes.wintypes import *

wininet = WinDLL('wininet', use_last_error=True)

class URL_COMPONENTS(Structure):
    _fields_ = (("dwStructSize", DWORD),
                ("lpszScheme", LPWSTR),
                ("dwSchemeLength", DWORD),
                ("nScheme", INT),
                ("lpszHostName", LPWSTR),
                ("dwHostNameLength", DWORD),
                ("nPort", INT),
                ("lpszUserName", LPWSTR),
                ("dwUserNameLength", DWORD),
                ("lpszPassword", LPWSTR),
                ("dwPasswordLength", DWORD),
                ("lpszUrlPath", LPWSTR),
                ("dwUrlPathLength", DWORD),
                ("lpszExtraInfo", LPWSTR),
                ("dwExtraInfoLength", DWORD))
    def __init__(self, bufsize=512):
        self.dwStructSize = sizeof(self)
        fields = iter(self._fields_)
        for name, dtype in fields:
            if dtype == LPWSTR:
                buf = (c_wchar * bufsize)()
                setattr(self, name, cast(buf, LPWSTR))
                name, dtype = next(fields)
                setattr(self, name, bufsize)
if __name__ == '__main__':
    url = LPCWSTR("http://user:password@www.host.com:8080/url-path?key=value")
    url_length = len(url.value)
    flags = 0
    url_components = URL_COMPONENTS()
    if not wininet.InternetCrackUrlW(url, url_length, flags,
                                     byref(url_components)):
        raise WinError(get_last_error())
    for name, dtype in url_components._fields_:
        print '%s: %s' % (name, getattr(url_components, name))

输出:

dwStructSize: 104
lpszScheme: http
dwSchemeLength: 4
nScheme: 3
lpszHostName: www.host.com
dwHostNameLength: 12
nPort: 8080
lpszUserName: user
dwUserNameLength: 4
lpszPassword: password
dwPasswordLength: 8
lpszUrlPath: /url-path
dwUrlPathLength: 9
lpszExtraInfo: ?key=value
dwExtraInfoLength: 10

关于python - InternetCrackUrlW 不会填充结构化类中指针后面的字符串值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32971962/

相关文章:

python - 将图像从 float32 转换为 uint8 时,蒙版对象消失

python - django.core.exceptions.FieldError : Unknown field(s) (username) specified for Employee 错误

c++ - 通过 python ctypes 使用时,opencv 调用共享库段错误

c++ - 任何人都知道为什么这个 POST with WinHttp 失败了

python - 为什么深度学习 Keras 上的准确率总是 0.00%,损失很高

python - 复选框形式的 Django 权限

Python调用C的全局变量

python - 如何在 python ctypes 中包装包含 C++ 对象的 C 结构

c++ - 添加进度条到wininet http上传C++

c++ - URLDownloadToFile 总是返回 S_OK