3
votes

My C++ program creates .png file and I need to open (view) this file right after creation - is there a way to open it as so it was opened within Windows explorer - so file wiil be opened with user's preferred program and if there are no associated programs with file's format - Windows will show dialog window in which user will be able to select any program to open that file.

Crossplatform (+Linux, +MacOS, +BSD) solution will be perfect.

Thanks.

3
Your entire question is about Windows and Windows Explorer, then the last sentence requests a cross-platform solution. Am I missing something?Cody Gray
Program will run both on Windows and *nix and I write much of platform-dependent code with macros but it will be better to have cross-platform solution.Slaus
I suppose you've tried the system() command? That's the quickest way I can think of to go cross-platform, but I assume it doesn't do exactly what you want, if you're asking this question.Cody Gray
Yes, as I know, system() requires opening program's full path which I do not know.Slaus

3 Answers

7
votes

On Windows, you can use the ShellExecute function.

4
votes

If you used Qt to develop your cross-platform application, then the QDesktopServices::openUrl() method would do the job. It is of course cross-platform, like everything in Qt.

Since you're already using wxWidgets, using Qt just to open a file is obviously an overkill. And since wxWidgets is mostly GUI stuff, it probably doesn't have anything like that, although I can't be sure as I've never used it myself.

Still, if you want to do it in a cross-platform way, here is what Qt does for Windows:

quintptr returnValue = (quintptr)ShellExecute(0, 0,
  (wchar_t*)filePath.utf16(), 0, 0, SW_SHOWNORMAL);
// ShellExecute returns a value greater than 32 if successful
return (returnValue > 32);

Here, filePath.utf16() is the Unicode null-terminated file path.

Here is the relevant part for X11/Unix:

if (launch(url, QLatin1String("xdg-open")))
    return true;
if (X11->desktopEnvironment == DE_GNOME 
    && launch(url, QLatin1String("gnome-open"))) {
    return true;
} else {
    if (X11->desktopEnvironment == DE_KDE 
        && launch(url, QLatin1String("kfmclient exec")))
        return true;
}
if (launch(url, QLatin1String("firefox")))
    return true;
if (launch(url, QLatin1String("mozilla")))
    return true;
if (launch(url, QLatin1String("netscape")))
    return true;
if (launch(url, QLatin1String("opera")))
    return true;
return false;

Here, the launch() function basically starts the indicated application, passing it the URL to open. Not just the file path, like in Windows, but the complete URL like file:///home/user/tmp/file.doc. Not sure that it matters, though. It also percent-encodes all non-ASCII characters in the URL before passing it to the program. Not sure if it matters for all the programs that the openDocument() tries. I have tested it with xdg-open, and it doesn't care if it's percent-encoded or not.

Here is the part that detects desktop environment and sets X11->desktopEnvironment accordingly:

    X11->desktopEnvironment = DE_UNKNOWN;
    Atom type;
    int format;
    unsigned long length, after;
    uchar *data = 0;
    int rc;
    do {
        if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
            X11->desktopEnvironment = DE_KDE;
            break;
        }
        if (qgetenv("DESKTOP_SESSION") == "gnome") {
            X11->desktopEnvironment = DE_GNOME;
            break;
        }
        // GNOME_DESKTOP_SESSION_ID is deprecated for some reason, but still check it
        if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
            X11->desktopEnvironment = DE_GNOME;
            break;
        }
        rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(_DT_SAVE_MODE),
                                0, 2, False, XA_STRING, &type, &format, &length,
                                &after, &data);
        if (rc == Success && length) {
            if (!strcmp(reinterpret_cast<char *>(data), "xfce4")) {
                // Pretend that xfce4 is gnome, as it uses the same libraries.
                // The detection above is stolen from xdg-open.
                X11->desktopEnvironment = DE_GNOME;
                break;
            }
            // We got the property but it wasn't xfce4. Free data before it gets overwritten.
            XFree(data);
            data = 0;
        }
    } while(0);

Wow, that was something. And I have removed the parts that detects other environments because they aren't used in openDocument().

And lastly, here is the glorious Mac version of the openDocument():

// LSOpen does not work in this case, use QProcess open instead.
return QProcess::startDetached(QLatin1String("open"), QStringList() << file.toLocalFile());

Really? That's it? Wow, there must be something to the Mac platform after all. Here, QProcess::startDetached() just starts a new process, passing the file path as an argument. It is largely equivalent to the system() call, but doesn't wait for the process to terminate. Not sure if that matters, and I have no idea how to do it on Mac without using QProcess, as I've never even seen a Mac.

1
votes

Here is an example of opening a bitmap from an application:

ShellExecute(   GetSafeHwnd(),
                      _T("open"),
                      "Test.bmp",
                      NULL,
                      NULL,
                      SW_SHOW);

For the cross-platform version if you google your request you'll find a lot of information.

Bye