views:

543

answers:

2

I'm trying to use a feature of the Microsoft WinHttp library that has been exposed by the developers of Win32com. Unfortunately most of the library does not seem to be documented and there are no example of the correct way to use the win32inet features via the win32com library.

This is what I have so far:

import win32inet
hinternet = win32inet.InternetOpen("foo 1.0", 0, "", "", 0)
# Does not work!!!
proxy = win32inet.WinHttpGetProxyForUrl( hinternet, u"http://www.foo.com", 0  )

As you can see, all I am trying to do is use the win32inet feature to find out which proxy is the appropriate one to use for a given URL, int his case foo.com.

Can you help me correct the syntax of the last line? MSN has some good documentation for the function being wrapped but the args do not seem to map the to those of the python library perfectly.

The fixed version of this script should:

  • Be able to look up which proxy to use for any given URL.

  • It should always do exactly what Internet Explorer would do (i.e. use the same proxy)

  • It should be valid on any valid Windows XP set-up. That means it should work with an explicitly configured proxy and also no proxy at all.

  • It only needs to work on Windows XP 32bit with Python 2.4.4. It can use any official released version of win32com.

I'm using Python2.4.4 with Win32Com on Windows XP.

UPDATE 0:

OR... can you give me an alternative implementation in cTypes? As long as I can make it work I'm happy!

+1  A: 

Unless there is a strong reason for using win32inet (which is messy in this area due to limitations of SWIG), I recommend that you use ctypes instead.

Vinay Sajip
Why is that? Is the win32inet module untrustworthy?
Salim Fadhley
Well, if it had worked, I presume you wouldn't have posted this question ;-). You still haven't answered `ars`'s question (about what error you are getting), so I'm not really sure what problem you're running into. I get a getargs error which points to non-standard argument passing, which is a consequence of the limitations I mentioned.
Vinay Sajip
Yes, that is the error. The arguments are wrong - I'm just not sure what the right ones are!
Salim Fadhley
+3  A: 

Here is the code which creates HINTERNET session and uses that to get proxy details, using ctypes to directly access winhttp DLL. It works without any error but I have no proxy set on my machine, you may have to tweak few constants to get it right. Go thru the msdn links in code, from where I have seen the API.

import ctypes
import ctypes.wintypes

winHttp = ctypes.windll.LoadLibrary("Winhttp.dll")

# http://msdn.microsoft.com/en-us/library/aa384098(VS.85).aspx
# first get a handle to HTTP session
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY=0
WINHTTP_NO_PROXY_NAME=WINHTTP_NO_PROXY_BYPASS=0
WINHTTP_FLAG_ASYNC=0x10000000
HINTERNET = winHttp.WinHttpOpen("PyWin32", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC)
print HINTERNET

# now get proxy using HTTP session
# http://msdn.microsoft.com/en-us/library/aa384097(VS.85).aspx
"""
BOOL WinHttpGetProxyForUrl(
  __in   HINTERNET hSession,
  __in   LPCWSTR lpcwszUrl,
  __in   WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,
  __out  WINHTTP_PROXY_INFO *pProxyInfo
);
"""
# create C structure for WINHTTP_AUTOPROXY_OPTIONS
#http://msdn.microsoft.com/en-us/library/aa384123(VS.85).aspx
"""
typedef struct {
  DWORD   dwFlags;
  DWORD   dwAutoDetectFlags;
  LPCWSTR lpszAutoConfigUrl;
  LPVOID  lpvReserved;
  DWORD   dwReserved;
  BOOL    fAutoLogonIfChallenged;
} WINHTTP_AUTOPROXY_OPTIONS;
"""
class WINHTTP_AUTOPROXY_OPTIONS(ctypes.Structure):
    _fields_ = [("dwFlags", ctypes.wintypes.DWORD),
                ("dwAutoDetectFlags", ctypes.wintypes.DWORD),
                ("lpszAutoConfigUrl", ctypes.wintypes.LPCWSTR),
                ("lpvReserved", ctypes.c_void_p ),
                ("dwReserved", ctypes.wintypes.DWORD),
                ("fAutoLogonIfChallenged",ctypes.wintypes.BOOL),]

WINHTTP_AUTOPROXY_AUTO_DETECT = 0x00000001;
WINHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001;
WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002;
options = WINHTTP_AUTOPROXY_OPTIONS()
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP|WINHTTP_AUTO_DETECT_TYPE_DNS_A
options.lpszAutoConfigUrl = 0
options.fAutoLogonIfChallenged = False

# create C structure for WINHTTP_AUTOPROXY_OPTIONS
# http://msdn.microsoft.com/en-us/library/aa383912(VS.85).aspx
"""
struct WINHTTP_PROXY_INFO {
  DWORD  dwAccessType;
  LPWSTR lpszProxy;
  LPWSTR lpszProxyBypass;
};
"""
class WINHTTP_PROXY_INFO(ctypes.Structure):
    _fields_ = [("dwAccessType", ctypes.wintypes.DWORD),
                ("lpszProxy", ctypes.wintypes.LPCWSTR),
                ("lpszProxyBypass", ctypes.wintypes.LPCWSTR),]

info = WINHTTP_PROXY_INFO()

ret = winHttp.WinHttpGetProxyForUrl(HINTERNET, "http://www.google.com", ctypes.pointer(options), ctypes.pointer(info) )
print "proxy success?",ret
if not ret:
    # some error lets see what is that?
    import win32api
    import win32con
    errorCode = win32api.GetLastError()
    print "win32 Error:",errorCode
    s = ""
    print win32api.FormatMessage(errorCode)

print info.dwAccessType, info.lpszProxy, info.lpszProxyBypass
Anurag Uniyal
Okay, that's an amazing help... and now that I knopw about ctypes.wintypes I can in theory make any struct I like. it's amazing how helpful it is just to have one recipe to start off with.
Salim Fadhley