|
I am attempting to use GetOpenFileName from a service on W2K and WXP. The service is set to interact with the desktop. The problem is that when the open dialog appears and the user selects the "Desktop" icon on the left panel of the open file dialog, it complains about "C:\Documents and Settings\LocalSystem\desktop" not existing. Note the "LocalDesktop" in that string. I want it to be the name of the current user.
So, how do I tell GetOpenFileName to use the currently logged-on user's context when using the open file dialog? Do I need to impersonate the logged-on user before calling GetOpenFileName? If so, how do I do impersonation WITHOUT asking for user credentials?
Some rudimentary example will suffice, you don't have to right the whole she-bang.
thanks you in advance.
ahz
|
|
|
|
|
In the article http://www.codeproject.com/system/newbiespawn.asp[^] the following code is given as a solution for launching a process and waiting for it to finish.
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = "c:\\MyProgram.exe";
ShExecInfo.lpParameters = "";
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
The problem I found with this code is that ShellExecuteEx, in some cirsumstances, may not create a different process. For example, if in the lpFile you specify a URL and there is one instance of IE already running, this existing instance will be used. The documentation says that, in this case, ShellExecuteEx will return NULL in the hProcess. I found that this is not true. It returns a handle for the existing process. The problems is that the process is "signaled" already. Therefore, WaitForSingleObject does not block waiting for the process to finish and returns immediately.
The only difference between my code and the above is that in mine, I've added the flag SEE_MASK_FLAG_DDEWAIT to the fMask so the DDE exchange is guaranteed to be finished before ShellExecuteEx return.
Does anybody know how to solve this problem?
Lula Capixaba
|
|
|
|
|
You might try using CreateProcess instead. The drawback of CreateProcess is that you can't just pass it a URL. The benefit is that if the process didn't exist/create you don't get a process handle.
The benefit/drawback of ShellExecuteEx is that it acts more like the user typed the command.
Another drawback is that it must be called from an STA thread. (Or a thread that didn't call CoInitialize[Ex]).
|
|
|
|
|
Thanks ahz, but let me try to explain why I have to use ShellExecuteEx:
My application displays a list of files located in a repository (in another machine). If the user selects one of the files for viewing/editing, I make a copy of the remote file in the local disk and launch a viewer/editor for the file. This file can be of any type: a .doc, .gif, .txt, .html, .cpp, .h etc. I want to launch the application that is associated with the file extension... that's why I am using ShellExecuteEx. I used to launch it using CreateProcess after manually finding the application associated with the extension in the registry. The problem became complicated when I realized that on Windowx XP, the default viewer for .gif files is the "Windows Picture and Fax Viewer". It is in a DLL called shimgvw.dll and can be launched using a command like this:
rundll32.exe c:\windows\system\shimgvw.dll,ImageView_Fullscreen C:\temp\logo.gif
The problem here is that I don't know how to get the information to launch this viewer from the registry. Presumably, there are other applications like this, that are run from a dll and, therefore, I would need to know which function in the dll to call.
That's why ShellExecuteEx is easier. I don't need to know the exact command to launch the viewer/editor. It's done behind the scenes by Windows.
So I think there two solutions for my problem:
1) Make ShellExecuteEx work and return a valid process handle even when it does not launch another instance of the application (which is the case for the "Windows Picture and Fax Viewer"). In addition, this handle must not be in a signaled state as it does now.
2) Find a way to get all the information needed to launch any viewer/editor using CreateProcess. In the case of the "Windows Picture and Fax Viewer", for example, how do I get the "ImageView_Fullscreen" function info?
Any thoughts?
Lula Capixaba
|
|
|
|
|
Yes, I understand the ease of using ShellExecuteEx. I would have made the same choice myself. I also read your other post about the fact that another instance of the application is already running and gets the file you are ShellExecuteEx-ing. I have some idea about how to go about finding out what application launches the file you are "viewing." For the .gif file you mentioned, you would look in the registry under HKEY_CLASSES_ROOT/giffile/shell/open/command and get the "default" value of that key. Then use FormatMessage to format the command string to run.
There are two problems with this, one you will notice that the executable is "rundll32.exe". This is a program used to launch applications implemented in a dll. This makes it impossible to know if another instance of the application is running. Two, even if you did know if another instance of the application were running how would you tell that application to view the file you want.
I think the approach you want to take is to not wait on the completion of whatever application gets launched by ShellExecuteEx. But rather put the files in the user's temporary files directory and let them clean the files up when they're done with them. Another option: when your application exits, give them the option (in an options dialog) of cleaning up the temporary files you created which is off by default -- this is the approach of most web browsers. To enable this approach use your own directory under the user's temp directory so that you only delete your temporary files. To get the user's temp directory look at SHGetFolderPath.
Hope this helps and good luck.
|
|
|
|
|
Many thanks ahz. I think Mike's answer (on my other post) explained everything. The application I am launching just notifies the existing instance that it must update its contents and simply exists. In this case, there is nothing I can do. I think you are right. I'll have to leave the files there and clean them later, perhaps on a user request because there is no way to wait for an application to terminate.
Note that this approach of allowing only one instance of an application to run, completely invalidates the common WaitForSingleObject approach to wait for an application to terminate. In general, you cannot predict other applications behaviour. Therefore, resource cleanning becomes a nightmare.
I wonder if the existing code base that relies on the WaitForSingleObject method can cope with this situation...
Anyway, thanks again.
Lula Capixaba
|
|
|
|
|
Hello everyone! I want to implement one feature in my program so that it will ask to relogin after the system has been idle for a specified time interval, the same way as screen savers get activated when the system is idle for some time. Any ideas about the solution?
|
|
|
|
|
How about GetLastInputInfo() ?
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
Oh, I guess that's exactly what I need, thanks.
|
|
|
|
|
Hi
Hi
I have a tabcontrol on a view window. I want to show a particular tab Window which has an error because i am validating some data i am using the function
void CNewForm::ShowErrorDialog(int TabNo)
{
TC_ITEM tci;
tci.mask = TCIF_PARAM;
tci.lParam = (LPARAM)m_pDlgHeader;
m_MyTab.SetItem(0, &tci);
CWnd* pWnd = (CWnd *)tci.lParam;
pWnd->ShowWindow(SW_SHOW);
}
It is focussing on particular tab but not showing the window. m_pDlgHeader already created during onInitDialog() function. Please help me why it is not showing the particular tab dialog.
Thanks in advance
Shailesh
|
|
|
|
|
Hello,
I am trying to place the property sheet tabs on the left side rather than the default top of the property sheet?? How do i do that?? Any pointers.
Thanks
|
|
|
|
|
Does this page offer any solutions?
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
I Have a MFC app,
And in my program I have a BMP image I need to be able to print out this image!. How can I do that?
|
|
|
|
|
Hi,
One of the procedure which you can follow is load the image into a dc and print the contents of the DC. Have a look @ the following link, although it is related to OpenGl, i think that you'll get little hints from it
http://www.codeproject.com/opengl/opengl_printing.asp[^]
Sujan
|
|
|
|
|
I seem to be having a problem with the fact that a dialog, created in the resource editor (VC.NET) which is 400 x 300 appears a completely different size on the screen. It seems to be x1.5 in the x and about x1.65 in the y. Apart from having something I don't understand happening with my program it also causes a problem as I have a grid in the backround (a bmp) which I cannot align my controls over properly (they are owner drawn and have parts of the grid in them). The control moves by sometimes 1 and sometimes 2 pixels on screen for every pixel moved in the editor (due to the position being scaled by 1.5 I assume). It is making aligning them impossible.
Any help on this would be appreciated.
Rich
|
|
|
|
|
the dialog editor use logical units, not pixel; so that dialogs can be resized to accomodate different font sizes ( for example ).
I would suggest manually move ( MoveWindow ) all your controls in the OnInitDialog, and Move ( or resize ) your dialog to fit the bitmap size.
Be sure to check that your dialog will be workable if the user select "Large" fonts ( from the display setting ).
Maximilien Lincourt
Your Head A Splode - Strong Bad
|
|
|
|
|
Thanks for that Maximilien,
I have made the change in my code and all is working correctly. It is obvious if you stop and think about it but I don't have time for luxuries like that.
Thanks again for such a quick reply.
Rich
|
|
|
|
|
Hi Guys,
Iam working on a project on MFC & came across this problem.
Wanted to use the devicecontext function "DrawEdge" with the following set properties.It worked fine ,but the colour of the drawnEdge was always "black",eventhough I tried to set a brush(with a colour).
Any idea ,How I can use the "DrawEdge" function so that I can draw with a particular colour instead of "black".....
Don't want to use the "DrawFame" function of the deviceContext,as I want the "Edge_BUMP" effect.(See code
Or Is there anyother function in the "DeviceContext" which performs such an action.
CRect rect;
rect3.SetRect(10,10,300,100);
CBrush brushBlue(RGB(255,112,0));
pDC->SelectObject(&brushBlue);
pDC->DrawEdge(rect,EDGE_BUMP,BF_RECT);
Thanks....
|
|
|
|
|
Try changing the pen color too.
Many times, the edges of objects are drawn using the pen instead of the brush.
|
|
|
|
|
Yes,I tried as follows,selecting a pen first.But still It is drawing "black"
CRect rect3;
rect3.SetRect(10,10,300,100);
CPen newPen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen = pDC->SelectObject(&newPen);
pDC->DrawEdge(rect3,EDGE_BUMP,BF_RECT);
|
|
|
|
|
The function is probably setting element colors itself using GetSysColor(), so you might not be able to override the colors, even though you have set them into the DC. You will have to make your own 'DrawEdge' function.
|
|
|
|
|
Do you have any ideas or suggestions....
|
|
|
|
|
Since you want to control the colors yourself, I suggest setting a pen and making a series of MoveTo and LineTo calls on your own - just do all the drawing the DrawEdge would have done for you on your own.
|
|
|
|
|
I choosed "DrawEdge" co's, with that, I can set the edges to bumped,etched or raised,which I can't do with "LineTo" or "MoveTo" functions.
|
|
|
|
|
Yes you can. You might need to change the pen color a couple times and draw more than one line next to each other, but BUMPED, ETCHED and RAISED are just combinations of shading using pens of different colors drawn next to each other.
Long before 'DrawEdge' existed (back in Windows 3.1 days) we used to do this all the time before '3-D controls' ever existed. Now MS has just added it in as part of the GDI to make it easier for people to achieve the same effect with a single function call. The DrawEdge will also use the current user's selected colors so it obtains the correct shading effect. Since you want to override the colors, you will have to provide the effects yourself.
As an example, here is some MFC source code:
void CDC::FillSolidRect(int x, int y, int cx, int cy, COLORREF clr)<br />
{<br />
ASSERT_VALID(this);<br />
ASSERT(m_hDC != NULL);<br />
<br />
::SetBkColor(m_hDC, clr);<br />
CRect rect(x, y, x + cx, y + cy);<br />
::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);<br />
}<br />
<br />
void CDC::Draw3dRect(LPCRECT lpRect,<br />
COLORREF clrTopLeft, COLORREF clrBottomRight)<br />
{<br />
Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left,<br />
lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);<br />
}<br />
<br />
void CDC::Draw3dRect(int x, int y, int cx, int cy,<br />
COLORREF clrTopLeft, COLORREF clrBottomRight)<br />
{<br />
FillSolidRect(x, y, cx - 1, 1, clrTopLeft);<br />
FillSolidRect(x, y, 1, cy - 1, clrTopLeft);<br />
FillSolidRect(x + cx, y, -1, cy, clrBottomRight);<br />
FillSolidRect(x, y + cy, cx, -1, clrBottomRight);<br />
}
You could create something similar to get the other two effects this one does not draw.
|
|
|
|
|