File handling WIN32 API

Hi,
I'm troubling finding information about what happens to my application when a user right-clicks on a file and selects for example "Open with" and then my program.

Where do I find the information needed to setup my application for handling this? (For WIN32 API)


Regards,
Simon H.A.
The usual way is getting the filename via the command line. If your application is a Windows application, your entry point is WinMain or wWinMain:

1
2
3
4
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmdShow)
{
    //lpCmdLine will have the file name.
}
Okay, I'll have another question then.
If my application is already opened, I would like to send this command-line to my current window. How do I do that since I can't send a pointer to a string because the newly opened application will close immediately after it sends the command-line and therefore the data is lost.

Regards,
Simon H.A.
You need to communicate the command line with some sort of inter-process communication, such as the clipboard (not really recommended, but possible), a custom message, the WM_COPYDATA message, anonymous or named pipes, sockets, a shared file in some folder, etc. Look up IPC in Google for a full list of possibilities.
Okay, thanks for your reply. I'll try some different solutions.

Regards,
Simon H.A.
I suggest you to use a custom message, with mutexes (or check every window's class name).

So, Define a new Window Message (#define WM_OPENFILE (WM_USER+1) ) then enumerate windows (EnumWindows) with, as LPARAM, the filename of the file requested and get their class name (GetClassName) and compare it with your class. If it's the same, send a WM_OPENFILE message with the filename as a LPARAM. Then from your message loop in your actual program handle WM_OPENFILE to open this file.
I've tried to use the WM_COPYDATA message, and it's suitable for my needs.

Regards,

Simon H.A.
Sounds like you are wanting a single-instance program? In the event the program already has an instance you just want to pass along the command line to the existing instance, right? You can use CreateMutex() as suggested here: http://support.microsoft.com/kb/243953 Also I think you can use the class name you created the app with FindWindow() to locate the running instance and pass whatever to it.
FindWindow has been deprecated by EnumWindows.
I would not use FindWindow() or EnumWindows() because it could hang your application if another program is not responding, instead I'd use a well defined file, registry key, etc
Why should it lock when another program is not responding? It doesn't send messages to window AFAIK. And anyways, you may find it true, if this specific program is REALLY busy with 100% of cpu use or sort-of, and your EnumWindows runs too slow because your entire PC is getting locked.
Not neccesarily the 3rd partyprogram is using 100% CPU, it is enough to just sleep and not respond to WM_GETTEXT or any messages posted to the queue.

And YOUR program will be locked too, waiting for EnumWindows() to return, which will never happen.
It is my understanding that FindWindow() doesn't rely on WM_GETTEXT just for that reason exactly, and therefore won't lock the caller if a window of a frozen app is enumerated. I ran a search but could not find the document I read about this.

I guess it can be checked rather simply by creating two apps: One that creates a main window and then freezes with Sleep() and one that enumerates windows. It should enumerate the frozen window just fine. For anyone really interested. :-P
I experimented and this is where my pay grade ends. I get "something" in the message box but it isn't what I sent on the command line. Do LPWSTR and std::wstring not play well together? (I find it beyond frustrating that there is no ASCII /UTF-8 equivalent for CommandLineTo ArgvW()!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#define PI_MSG 9999

#include <windows.h>
#include <string>

HANDLE hInstanceMutex;

LRESULT CALLBACK wProc (HWND,UINT,WPARAM,LPARAM);

const char *szClassName = "MySingleInstanceTestApp";

int WINAPI WinMain (HINSTANCE I,HINSTANCE PI,LPSTR Arg, int Show)
{
  hInstanceMutex = CreateMutex(0,TRUE,szClassName);
  if(hInstanceMutex)
  {
    if(GetLastError() == ERROR_ALREADY_EXISTS) // another instance is lurking
    {
      HWND inst = FindWindow(szClassName,0); // let's get the window handle
      if(inst) // we found it
      {
        std::wstring arg_string;
        int argc;
        LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(),&argc); // get argc,argv
        if(argv) // we have arguments
        {
          for(int i = 0; i < argc; i++)
          {
            arg_string += argv[i]; // lets make them one line
            arg_string += L" ";
          }
          SendMessage(inst,PI_MSG,0,(LPARAM)(LPWSTR)arg_string.c_str()); // pass to open instance
          LocalFree(argv);
        }
      }
      return 0; // we die, only single instance allowed
    }
  }
  HWND hWnd;
  MSG M;
  WNDCLASSEX wcx;
  ZeroMemory(&wcx,sizeof(WNDCLASSEX));

  wcx.hInstance = I;
  wcx.lpszClassName = szClassName;
  wcx.lpfnWndProc = wProc;
  wcx.style = CS_DBLCLKS;
  wcx.cbSize = sizeof (WNDCLASSEX);
  wcx.hIcon = LoadIcon(0,IDI_APPLICATION);
  wcx.hIconSm = LoadIcon(0,IDI_APPLICATION);
  wcx.hCursor = LoadCursor(0,IDC_ARROW);
  wcx.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

  if (!RegisterClassEx(&wcx)) return 0; // fail

   hWnd = CreateWindowEx (0,szClassName,"Single Instance Test Application",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,544,375,HWND_DESKTOP,0,I,0);
   ShowWindow (hWnd,Show);
   while(GetMessage(&M,0,0,0))
   {
     TranslateMessage(&M);
     DispatchMessage(&M);
   }
   return M.wParam;
}


LRESULT CALLBACK wProc(HWND H,UINT M,WPARAM W,LPARAM L)
{
  switch(M)
  {
    case PI_MSG: // another instance tried to start with arguments
    {
      LPWSTR pi_cmd = (LPWSTR)L; // stored argument string in LPARAM
      if(pi_cmd)
      {
        MessageBoxW(H,pi_cmd,L"Message From Other Instance",MB_ICONASTERISK);
      }
    } break;
    case WM_DESTROY:
    {
      PostQuitMessage(0);
    } break;
    default:
      return DefWindowProc(H,M,W,L);
  }
  return 0;
}
Last edited on
closed account (DSLq5Di1)
SendMessage(inst,PI_MSG,0,(LPARAM)(LPWSTR)arg_string.c_str()); // pass to open instance

Passing a pointer from one process to another has no meaning, each process has it's own virtual address space, the other process wouldn't know what to do with that pointer. http://en.wikipedia.org/wiki/Process_isolation

This is where inter-process communication comes in:-
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574

Example usage of WM_COPYDATA:-
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649009
Texan40, use:

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);

Then you are getting the command line as you desire and you can use CommandLineToArgvW().

I always use this entry point and I always code for UNICODE only since i don't have to code for Windows Me or below.
This will always work, no matter you use ANSI or Unicode build:
1
2
3
4
5
int argc;
LPWSTR * argv = CommandLineToArgvW (GetCommandLineW(), &argc);

// use argc and argv as usual
::LocalFree (argv);
Last edited on
Instead of trying to deal with a message pump would it be "easier" to pass messages between instances in a file mapping?

Edit: Actually I missed sloppy9's post. WM_COPYDATA looks promising.
Last edited on
Topic archived. No new replies allowed.