4

I'm creating a project with C++Builder XE7, in which a user can click on a button to open a web link, e.g. to open a support page, or to share his experience on a social media. For that, I use the ShellExecute() function, and it works well, except for one button.

When I click on this button, simply nothing happens. The ShellExecute() function returns without error (the returned value is 42), but my default browser does not open, and the web page isn't shown at all.

Here is my ShellExecute() implementation

const HINSTANCE result = ::ShellExecute(handle, "open", url.c_str(), NULL, NULL, SW_SHOWDEFAULT);

I also tried the ShellExecuteEx() function:

::SHELLEXECUTEINFO info;
std::memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.hwnd   = handle;
info.lpVerb = "open";
info.lpFile = url.c_str();
info.nShow  = SW_SHOWDEFAULT;

if (!::ShellExecuteEx(&info))

The url parameter contains the website link I am trying to open. For security reasons, I cannot post it here as a sample, however I tested it in my browser (FireFox) and it works well. On the other hand, if I execute my code by just replacing the url content with Google's website, all works as expected.

The handle is just the Handle parameter of the parent frame.

I also tried to tweak the ShellExecute/Ex() parameters, like the hwnd and nShow fields, but no change.

Can anybody point me to what is wrong?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Jean-Milost Reymond
  • 1,833
  • 1
  • 15
  • 36
  • 1
    Could you post a [mcve]? Also what is you default browser? What happens if you do Start-Run and then type some url such as `http://www.stackoverflow.com/`. – Jabberwocky Jul 03 '17 at 16:07
  • I cannot publish more code, unfortunately. The code before the call to ShellExecute() is just the building of the URL, inside a function, and I'm not allowed to show it. On the caller side, this function just is called inside the button event, with the handle of the button parent. So the above code is already the most simplest code sample I'm allowed to provide. – Jean-Milost Reymond Jul 03 '17 at 16:19
  • And all is fine with my Windows configuration. As I said in the above post, my default browser is FireFox, and Start-Run opens it with the provided link as expected. And also, the same ShellExecute() in my code works just well with a simple link, like http://www.google.com. But the behavior of ShellExecute() itself is very strange with my url: why it returns without doing nothing, and without error? May be a ShellExecute() bug? – Jean-Milost Reymond Jul 03 '17 at 16:28
  • Does that url include query string? You don't have to post the exact URL, just post a similar one or modify existing url and paste it – Asesh Jul 03 '17 at 16:52
  • The url is formatted like this:http: // www. mysite.xxx/selectPage.php?arg1=xxx&arg2=yyy&...&argX=a text containing \"quotes\" and some %26amp%3b special chars! – Jean-Milost Reymond Jul 03 '17 at 17:10
  • It you care about proper error reporting, call `ShellExecuteEx`. – IInspectable Jul 03 '17 at 19:17
  • I already tried that, the situation is the same: ShellExecuteEx() returns no errors, but also do nothing – Jean-Milost Reymond Jul 03 '17 at 19:39
  • 2
    _a text containing \"quotes\"_ ... have you actually encoded the double quotes or is this just how you copied the string from your C++ source? – zett42 Jul 03 '17 at 20:59
  • 1
    In `argX=a text containing ...`, are you encoding space characters and other reserved characters in `%HH` format? If not, you need to. – Remy Lebeau Jul 03 '17 at 21:17

1 Answers1

4

The url is formatted like this: http:// www. mysite.xxx/selectPage.php?arg1=xxx&arg2=yyy&...&argX=a text containing "quotes" and some %26amp%3b special chars!

In this example you have to URL-encode the double quotes and the spaces because these are not valid characters for the query part of an URL.

Fix it by replacing double quotes with %22 and spaces with %20. I suggest to use a function like UrlEscape() to properly encode the URL.

Although most browsers have an error tolerance for user input and will also accept an URL which does not have valid encoding, it's better to strictly follow the spec because you are not guaranteed that tolerance.

In addition, the double quotes will make problems when the URL is passed as a command-line argument to the command associated with the URL protocol. This is because double quotes are reserved characters for defining command-line parameters that contain spaces.

For instance, on my machine the http protocol is associated with the following command (see HKEY_CLASSES_ROOT\http\shell\open\command):

"C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -osint -url "%1"

You can see that the double quotes are already used to enclose the last parameter, which obviously gets messed up if you have unencoded double quotes within the URL.

Example for correctly encoding an URL for use with ShellExecuteEx():

#include <windows.h>
#include <Shellapi.h>

int main()
{
    ::CoInitialize(nullptr);

    SHELLEXECUTEINFOW info{ sizeof(info) };
    info.fMask  = SEE_MASK_NOASYNC; // because we exit process after ShellExecuteEx()
    info.lpVerb = L"open";
    info.lpFile = L"http://www.google.de/search?q=ShellExecuteEx%20URL%20%22double%20quotes%22";
    info.nShow  = SW_SHOWDEFAULT;

    if( !::ShellExecuteExW( &info ) )
    {
        DWORD err = ::GetLastError();
        printf("ShellExecuteEx failed with error %d\n", err );
    }

    ::CoUninitialize();
}
Community
  • 1
  • 1
zett42
  • 25,437
  • 3
  • 35
  • 72
  • 1
    You should also encode space characters as `%20` as well: `"http://www.google.de/search?q=ShellExecuteEx%20URL%20%22double%20quotes%22"`. But more importantly, `lpVerb` should be `NULL` instead of `"open"` to launch the user's default browser. – Remy Lebeau Jul 03 '17 at 21:22
  • @RemyLebeau Why? – zett42 Jul 03 '17 at 21:23
  • 3
    Because unencoded spaces are not allowed in a URL's query component, per [RFC 3986 Section 3.4](https://tools.ietf.org/html/rfc3986#section-3.4). A query can only have `pchar`, `/`, and `?` characters in it, and the definition of `pchar` does not include the unencoded space character. Any character not explicitly allowed in `pchar` must be percent-encoded instead, which is `%20` for a space character. – Remy Lebeau Jul 03 '17 at 21:30
  • @RemyLebeau Fixed, thanks for the link. When testing the code it worked without encoding spaces, but ofc it's better to follow the spec. – zett42 Jul 03 '17 at 21:36
  • Encoding the part containing the text resolved the issue. A huge thank you to all those who took the time to answer me – Jean-Milost Reymond Jul 04 '17 at 13:45