Open file with Windows' native program within C++ code
Asked Answered
F

3

3

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.

Firelock answered 26/2, 2011 at 13:47 Comment(4)
Your entire question is about Windows and Windows Explorer, then the last sentence requests a cross-platform solution. Am I missing something?Andreas
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.Firelock
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.Andreas
Yes, as I know, system() requires opening program's full path which I do not know.Firelock
R
7

On Windows, you can use the ShellExecute function.

Reedbuck answered 26/2, 2011 at 13:53 Comment(0)
S
4

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.

Serles answered 26/2, 2011 at 13:56 Comment(8)
Why assume that the asker is using Qt?Andreas
@Cody, I wasn't assuming that. However, doing things in a cross platform way without using a cross-platform library is nearly impossible, so using one is a good idea anyway. I just picked up the one I am most familiar with.Serles
Qt has too tangled licence so I preferred wxWidgets.Firelock
@Slav, I see. Then using Qt just to open a file is probably not a good idea. Qt was LGPLed not so long ago, by the way, just in case you want to use it someday.Serles
@Slav, still, you may wish to look at the Qt sources to figure out how they do it in a cross-platform way.Serles
Oh, that's the good idea! Is there some link to Qt's online sources with interlinks?Firelock
@Slav, I wish there was! Every time I had to find something there I have to dig in the unpacked tarball, which is both slow and annoying, although not that hard. If you find something, let me know. If I figure out something from the sources, I'll update my answer with more information.Serles
Heh, pretty big stuff, isn't it? May be it's better to switch from wxWidgets from Qt...Firelock
A
2

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

Affricative answered 26/2, 2011 at 14:7 Comment(1)
Note that GetSafeHwnd is an MFC function. It's not part of the standard Windows API. All you have to specify there is a window handle (HWND).Andreas

© 2022 - 2024 — McMap. All rights reserved.