CFileDialog fileDialog(
FALSE, // We are save as file dialog.
_T("*.txt"), // Default save as text format.
_T("hello"),
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("Text Files (*.*)|*.txt|Excel Files (*.xls)|*.xls|Excel Details Files|(*.xls)||"),
this);
// Returns me "xls".
const CString fileExtension = fileDialog.GetFileExt();
// Returns me "Excel Files" or "Excel Details Files"
???
What is the correct way for me to obtain the file extension description?
You're trying to retrieve the description you sent to the API yourself...? You could retrieve it from the internal OPENFILENAME structure using the member CFileDialog::GetOFN and look at the lpstrFilter member of the structure, but you'd have to parse the string yourself.
But the API SHGetFileInfo should be able to retrieve the registered file type description for the operating system. Pass "*.xls" (or whatever extension you want) to it.
Related
I wrote a c++ program and I want to execute my second program inside it, which is a exe file. The problem is I want to share my program to others as one single file.
When I search on the internet, I found this solution.
Just store the second .exe file as a binary resource inside the main
.exe using an .rc file at compile-time. At run-time, you can access it
using FindResource(), LoadResource(), and LockResource(), and then
write it out to a temp file on disk before passing it to system().
But I don't understand how to "store the .exe file as a binary resource"
I am currently using CreateProcess() to start my second program which working greatly.
Can anyone write some example for me?
In your project's resource script (the .rc file in which icons, dialogs, etc. are defined), you can add a binary resource with a line like the following:
IDB_EMBEDEXE BINARY "<path>\\EmbedProgram.exe"
Where the IDB_EMBEDEXE token/macro should be defined in a header file that is included by both that resource script and any C++ source(s) that use(s) it; this will be the lpName argument given to the FindResource() call, which you can form using MAKEINTRESOURCE(IDB_EMBEDEXE). Specify "BINARY" (or L"BINARY" for Unicode builds) for the lpType argument.
Like this:
#define IDB_EMBEDEXE 13232 // Or whatever suitable value you need
//...
// In the C++ code:
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(IDB_EMBEDEXE), _TEXT("BINARY"));
HGLOBAL hGlobal = LoadResource(NULL, hResource);
size_t exeSiz = SizeofResource(NULL, hResource); // Size of the embedded data
void* exeBuf = LockResource(hGlobal); // usable pointer to that data
// You can now write the buffer to disk using "exeBuf" and "exeSiz"
The specified executable file will then be completely embedded (as a binary) resource in your built executable, and can be extracted, written to disk and executed as described in the article you quote.
I'm on Windows 10 Pro and Visual Studio 2013, and I'm using SHGetFileInfoW to get an icon location (path + index) for a file type:
std::wstring wFile { L"a.bas" };
SHFILEINFOW fi {};
DWORD success = ::SHGetFileInfoW(wFile.c_str(),
FILE_ATTRIBUTE_NORMAL,
&fi,
sizeof(fi),
SHGFI_USEFILEATTRIBUTES | SHGFI_ICONLOCATION);
No matter whether wFile refers to an existing file or is just any filename, the call returns 1 indicating success. The iIcon member of fi is set to a number, but szDisplayString is empty. Not just the drive letter is overwritten with \0 (as seemed to happen here) but it is completely filled with \0.
Microsoft recommends using IExtractIcon::GetIconLocation as an alternative, but I need to get the icon for files which are not on a local filesystem, so I can't get an IShellInfo object which would get me this interface pointer.
Getting an icon handle works, on the other hand. Is this function just buggy or am I doing something wrong? Is there a workaround?
Icons can be dynamically generated and might not expose the path to its images. Icon handlers communicate this to the shell by setting the GIL_NOTFILENAME flag in their IExtractIcon::GetIconLocation implementation. If GIL_SIMULATEDOC is set the shell must also typically generate a icon on the fly.
If you call SHGetFileInfo with the SHGFI_SELECTED flag set then then function probably has to generate a new icon no matter which file type you are asking for.
If you are displaying a file list in a ListView/TreeView then you typically use SHGFI_SYSICONINDEX|SHGFI_SHELLICONSIZE|SHGFI_SMALLICON and use the system image list.
Use SHGFI_ICON if you need a HICON.
If SHGFI_ICONLOCATION is specified then SHGetFileInfo uses IExtractIcon:
Retrieve the name of the file that contains the icon representing the file specified by pszPath, as returned by the IExtractIcon::GetIconLocation method of the file's icon handler.
My MFC C++ application is using the following code to fetch details from INI file.
GetPrivateProfileString("MyDefaults", "MyCompanyID", " ", szBuffer, 5000,csConfIniName);
When I provide a local path (Eg: C\Temp\Myfile.ini) to csConfIniName, it can fetch the MyCompanyID value. But when I give a network path eg. \\10.1.1.500\c$\Development\Myfile.ini, GetPrivateProfileString fills szBuffer with a blank value.
Any suggestion?
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.
So I was able to get the AppData folder via SHGetKnownFolderPath and converted the memory address it printed to a readable string via
SHGetKnownFolderPath(FOLDERID_RoamingAppData, NULL, NULL, &wszPath);
_bstr_t bstrPath(wszPath);
std::string strPath((char*)bstrPath);
newstring.append(strPath);
newstring.append(secondvar);
So you probably noticed the newstring.append. What I do is append the folder name I want and file to the end of the AppData location which is C:\Users\*Username*\AppData\Roaming(and append here my folder and file).
Then I use cURL to send the file from newstring to my cURL function called sendfile, however because of the hacks I tried to convert the memory address to a readable string and then append the other information, I then got a heap corrupted message.
I then tried manually putting the path to the directory and file to cURL function curl_formadd and it still wouldn't work. However, if there is a file where the application is, and use it for sending through HTTP, it works. If I add a full path, i.e C:\Users\*Username*\AppData\Roaming\myfolder\myfile.txt to the curl_formadd function, nothing happens.
So how do I go about fetching that file from the directory I want and sending it with cURL?