WinHTTP and canonicalize parameter string

We just moved from WinINET to WinHTTP. The latter does not have an equivalent InternetCanonicalizeUrl function.

The WinHTTP docs say that WinHTTPOpenRequest does this automatically but there is nothing there that specifically addresses this.

According to this reference you can use WinHTTPCreateURL which uses a URL_COMPONENTS structure to define the various URL parts. In the latter the lpszExtraInfo property is where you put the ?param=xyz& ... part.

Here is my problem - one of the parameters in the paramter string needs to be canonicalized as it could contain non-URL friendly characters (Example &).

With the WinINET version we used InternetCanonicalizeUrl on the specific URL parts which were then appended to the URL string.

If we have a URL now that looks like this'Name & Surname','Description'

Open in new window

And we pass that to WinHTTPOpenRequest - it does not know that the & in Name & Surname is data and not a parameter separator.

How do we canonicalize individual parameters in the URL with WinHTTP
LVL 65
Julian HansenAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Hi Julian Hansen,

in the linked document about WinHttpCreateUrl ( there's a description of the passed parameter DWORD dwFalgs:

Converts all unsafe characters to their corresponding escape sequences in the path string pointed to by the lpszUrlPath member and in lpszExtraInfo the extra-information string pointed to by the member of the URL_COMPONENTS structure pointed to by the lpUrlComponents parameter.
I think this is the same as using InternetCanonicalizeUrl.

Hope this helps,

Julian HansenAuthor Commented:
Thanks Zoppo but as I mentioned in my post what if my lpszExtra is

groups='Group 1 & 2','Users','Group 3 & 4'&user=fred&ip=

I want that to come out as

Open in new window

Not as

Open in new window

We are taking the same code we had working for WinINET that had a step to run the different parameters through InternetCanonicalizeUrl and passed that to WinHTTP but the query is failing - when we look at the logs it is because WinHTTP is seeing the & - data as parameter separators
you could replace the & and = by sequences like "[amb]" and "[eq]" and after WinHTTPCreateURL undo the replacement.

Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

It's a bit strange - I just used the sample code from, added the ICU_ESCAPE in both calls to WinHttpCreateUrl and did some minor changes to use the string you posted above with the sample URL, i.e.:
void foo()
	LPCWSTR pwszUrl1 = L"";
	DWORD dwUrlLen = 0;

	// Initialize the URL_COMPONENTS structure.
	ZeroMemory( &urlComp, sizeof( urlComp ) );
	urlComp.dwStructSize = sizeof( urlComp );

	// Set required component lengths to non-zero, 
	// so that they are cracked.
	urlComp.dwSchemeLength = (DWORD)-1;
	urlComp.dwHostNameLength = (DWORD)-1;
	urlComp.dwUrlPathLength = (DWORD)-1;
	urlComp.dwExtraInfoLength = (DWORD)-1;

	// Crack the URL.
	if ( !WinHttpCrackUrl( pwszUrl1, (DWORD)wcslen( pwszUrl1 ), 0, &urlComp ) )
		printf( "Error %u in WinHttpCrackUrl.\n", GetLastError() );
		// Change the search data. New data is the same length.
		urlComp.lpszExtraInfo = L"?groups='Group 1 & 2','Users','Group 3 & 4'&user=fred&ip=";
		urlComp.dwExtraInfoLength = wcslen( urlComp.lpszExtraInfo );

		// Obtain the size of the new URL and allocate memory.
		WinHttpCreateUrl( &urlComp, ICU_ESCAPE, NULL, &dwUrlLen );
		LPWSTR pwszUrl2 = new WCHAR[dwUrlLen];

		// Create a new URL.
		if ( !WinHttpCreateUrl( &urlComp, ICU_ESCAPE, pwszUrl2, &dwUrlLen ) )
			printf( "Error %u in WinHttpCreateUrl.\n", GetLastError() );
			// Show both URLs.
			printf( "Old URL:  %S\nNew URL:  %S\n", pwszUrl1, pwszUrl2 );

		// Free allocated memory.
		delete[] pwszUrl2;

Open in new window

When I execute this the output is:
Old URL:
New URL:'Group%201%20&%202','Users','Group%203%20&%204'&user=fred&ip=

Open in new window

For any reason this differs from the result you posted above.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Julian HansenAuthor Commented:
Interesting - our app throws out very verbose logs and it definitely shows that the URL was not encoded.

I am going to match your code to ours and see what is different.

Thanks for this - appreciate the second pair of eyes and the input.
No problem, you know, that's what we're here for :o)
Julian HansenAuthor Commented:
I have not had time to implement but Zoppo is pointing me in the right direction.

Sarabande's solution also has some merit - I will look into that as a fallback.

Thank you both for responding - apologies for the late closing of the question.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.