i got a file name that is predefined as a string.
can i call shellexcute without specifying the full path? like:
ShellExecute(NULL, L"open", PreDefiendFileName, NULL, NULL, 0);
what should i do otherwise if not?
You could:
Fail gracefully: let the user know that the file could not be found and halt the program.
Use a default file that you *know* is there, and inform the user that you are using the default file.
I'd encourage you to think defensively about this problem. E.g. ensure that the file name that is passed is actually a file ("does it have the correct extension?", "does it exist in the file system?") and then only call the ShellExecute function if those checks pass.
Related
I am trying to make an image viewer, and everything works when I hard code the path of the file, but when I try to get the path so I can open files with it, it doesn't work, nothing happens.
When debugging, I found out that CreateFileA returns INVALID_HANDLE_VALUE.
This leads me to believe that the error should be in these 2 lines of code.
LPSTR FileA = GetCommandLine();
HANDLE FileHandle = CreateFileA(FileA, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
When CreateFileA() returns INVALID_HANDLE_VALUE on failure, use GetLastError() to find out WHY it failed. But in this case, GetCommandLine() is likely not returning the path you are expecting.
Assuming that is actually calling the Win32 GetCommandLineA() function, and not some other function in your program, then that function returns the command line that was used to launch the calling process, ie "C:\<path>\myapp.exe <parameters>". If there are no <parameters> present, then you would be trying to open your own program's EXE, not an image file. And if there are <parameters> present, then you would be passing an invalid file path to CreateFileA().
You need to parse the command line to extract just the file path you actually want, THEN you can try to open the file at that path. Have a look at Parsing C Command-Line Arguments and Parsing C++ Command-Line Arguments . Consider using CommandLineToArgvW() to make that easier.
I'm using CaptureStackBackTrace and SymFromAddr to identify the functions in the callstack.
Is there a way to find the source file of each symbol with this (i can't find any documentation for this)? Or i have to use StackWalk ?
The solution was to use SymGetLineFromAddr which gives the file path and the line number. In order to do this you must set SYMOPT_LOAD_LINES flag before calling SymInitialize. Also the 3'rd argument of SymGetLineFromAddr must be not NULL, otherwise it will crash.
Raxvan.
I am attempting to open a .chm file(A windows help file) at a specific page/topic by using a system call in C++.
I can successfully open the .chm file to the start page through the following code, but how can I open a .chm file to a specific page/topic inside the help file?
system("start c:/help/myhelp.chm");
PS: I know system is evil/discouraged but the system part is not really relevant its the command line arguments I pass with the .chm file(that will specify what page I want to open) that I am trying to determine.
Ok the arguments are like so:
system(" /Q /E:ON /C HH.EXE ms-its:myChm.chm::myPageName.htm");
There is an API in the Windows SDK called HtmlHelp in the HtmlHelp.h file. You can call like so:
HtmlHelp(GetDesktopWindow(), L"C:\\helpfile\\::/helptopic.html", HH_DISPLAY_TOPIC, NULL);
The Microsoft Docs - HtmlHelpA function provides more information about the function. HtmlHelp() will normally resolve to HtmlHelpA() or HtmlHelpW() depending on whether Unicode compiler option is set or not.
See as well Microsoft Docs - HTML Help API Overview.
Another option - use ShellExecute. The Microsoft help is not easy to use. This approach is much easier and in line with your question. Here is a quick routine to open a help file and pass an ID number. I have just set up some simple char’s so you can see what is going on:
void DisplayHelpTopic(int Topic)
{
// The .chm file usually has the same name as the application - if you don’t want to hardcode it...
char *CmndLine = GetCommandLine(); // Gets the command the program started with.
char Dir[255];
GetCurrentDirectory (255, Dir);
char str1[75] = "\0"; // Work string
strncat(str1, CmndLine, (strstr(CmndLine, ".exe") - CmndLine)); // Pull out the first parameter in the command line (should be the executable name) w/out the .exe
char AppName[50] = "\0";
strcpy(AppName, strrchr(str1, '\\')); // Get just the name of the executable, keeping the '\' in front for later when it is appended to the directory
char parms[300];
// Build the parameter string which includes the topic number and the fully qualified .chm application name
sprintf(parms,_T("-mapid %d ms-its:%s%s.chm"), Topic, Dir, AppName);
// Shell out, using My Window handle, specifying the Microsoft help utility, hh.exe, as the 'noun' and passing the parameter string we build above
// NOTE: The full command string will look like this:
// hh.exe -mapid 0 ms-its:C:\\Programs\\Application\\HelpFile.chm
HINSTANCE retval = ShellExecute(MyHndl, _T("open"), _T("hh.exe"), parms, NULL, SW_SHOW);
}
The topics are numbered within your .chm file. I set up a #define for each topic so if I had to change the .chm file I could just change the include file to match and not have to worry about searching through the code for hardcoded values.
I shouldnt be able to delete a file with an open handle, correct? So i create a file, then i straight away try to delete it, expecting this to fail. Or am i wrong and the handle doesnt have to be closed before deleting the file?
HANDLE hFile = CreateFile (TEXT(file),
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
//FAIL
}
if(DeleteFile(file))
{
//Should it ever get here cos i dont close the handle?
}
It depends on how the file has been opened. If the share mode has FILE_SHARE_DELETE specified, then it may be deleted by others.
Even if you memory map the file, and it has been opened with this flag (and read/write sharing), then it can still be deleted by the shell (at least I've tried this and it happens, but perhaps the file has simply been renamed and moved to the recycle bin). In such cases, subsequently accessing the memory will result in an 'InPageError' C-style exception.
Yes, it would fail.
The DeleteFile function fails if an application attempts to delete a
file that is open for normal I/O or as a memory-mapped file.
Have you tried this? MS documentation states that:
The DeleteFile function fails if an application attempts to delete a file that is open for normal I/O or as a memory-mapped file.
So if you're not getting that behaviour I'd suggest it's down to the way you've opened the file. Are you sure that your check on whether the file is open is completely comprehensive?Have you tried writing to the file first? Can you see the file outside of your own code? (i.e. from Explorer) Look here for more details.
My C++ winAPI application has a need to create a temporary file prior to uploading the file to a server. So I have searched ways to create a temporary file & found there are many ways to do this.
Can you tell me: For each of the following methods below, in which scenario am I supposed to use that method? And which method would best suite my needs?
Method 1:
// Using CreateFile()
CreateFile( "myfile.txt", GENERIC_ALL, ..., FILE_ATTRIBUTE_TEMPORARY, 0); // removed unecessary parameters
Method 2:
// I think that GetTempFileName also creates the file doesn't it? Not just generates a unique fileName?
// Gets the temp path env string (no guarantee it's a valid path).
dwRetVal = GetTempPath(MAX_PATH, // length of the buffer
lpTempPathBuffer); // buffer for path
// Generates a temporary file name.
uRetVal = GetTempFileName(lpTempPathBuffer, // directory for tmp files
TEXT("DEMO"), // temp file name prefix
0, // create unique name
szTempFileName); // buffer for name
Method 3:
// Create a file & use the flag DELETE_ON_CLOSE. So its a temporary file that will delete when the last HANDLE to it closes
HANDLE h_file = CreateFile( tmpfilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL );
Why are there more than 1 way to create a temp file. And, for example, what is the situation where I would want to use, say, method 2 over method 1?
FILE_ATTRIBUTE_TEMPORARY simply tells Windows not to bother writing the file contents to disk if there's enough cache, because the file is temporary and no other process will be using it.
FILE_FLAG_DELETE_ON_CLOSE means just what it says - when you close the file it will be deleted automatically. This guarantees that it will be temporary.
GetTempFilename creates a name for a temporary file, and guarantees that the filename hasn't been used previously.
You should use all 3 methods when creating a temporary file. None of them interferes with the others.
For method #2 if you use 0 for the "unique ID" you actually need to call SetFileAttributes with FILE_ATTRIBUTE_TEMPORARY to make the generated file temporary in the same sense as method #1 (otherwise it will be a normal ARCHIVE/NOT_CONTENT_INDEXED file.)
Use GetFileAttributes or GetFileInformationByHandle to see what attributes the file actually possesses.