InternetCrackUrlW 不填充结构化指针后面的字符串值 class
InternetCrackUrlW does not fill the values of strings behind pointers in structured class
我正在尝试使用 WinINet 库中的 InternetCrackUrl 函数解析 url。
此函数的 "return" 值是通过具有 defined structure.
的 lpUrlComponents 参数完成的
我现在遇到的问题是我的结构化 class 仅检索数字字段 DWORD
和 INT
中的值,但所有字母数字字段/所有指针 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
根据 remarks
:
The required components are indicated by members of the URL_COMPONENTS
structure. Each component has a pointer to the value and has a member that stores the length of the stored value. If both the value and the length for a component are equal to zero, that component is not returned.
因此在调用 InternetCrackUrl
之前为您感兴趣的所有项目设置长度组件。
当函数returns时,指针将设置为有效组件,但它们指向您自己的字符串!同时使用指针和从结构中检索它们的长度。
下面是 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
我正在尝试使用 WinINet 库中的 InternetCrackUrl 函数解析 url。
此函数的 "return" 值是通过具有 defined structure.
的 lpUrlComponents 参数完成的我现在遇到的问题是我的结构化 class 仅检索数字字段 DWORD
和 INT
中的值,但所有字母数字字段/所有指针 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
根据 remarks
:
The required components are indicated by members of the
URL_COMPONENTS
structure. Each component has a pointer to the value and has a member that stores the length of the stored value. If both the value and the length for a component are equal to zero, that component is not returned.
因此在调用 InternetCrackUrl
之前为您感兴趣的所有项目设置长度组件。
当函数returns时,指针将设置为有效组件,但它们指向您自己的字符串!同时使用指针和从结构中检索它们的长度。
下面是 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