C++ Open file dialog in window - c++

I have C++ code to show dialog chooser file. I want to the user can only chooser type file specified. My dialog can show type file specified but the user can input other type file in File name like my picture
So, how can I make the user only input File name and search type file specified in lpstrFilter? OR Can i disable File name box?
This is my code:
const wchar_t* ChooserFile(const char* typeFile)
{
try
{
ZeroMemory( &sfn , sizeof( sfn));
sfn.lStructSize = sizeof ( sfn );
sfn.hwndOwner = NULL ;
wchar_t w_syFile[MAX_PATH];
//mbstowcs(w_syFile, syFile, strlen(syFile)+1);//Plus null
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, w_syFile, MAX_PATH, syFile, _TRUNCATE);
sfn.lpstrFile = w_syFile ;
sfn.lpstrFile[0] = _T('\0');
sfn.nMaxFile = sizeof( syFile );
//TypeFile
sfn.lpstrFilter = TEXT("Microsoft Office Word Documents (*.xlsx)\0*.XLSX\0");
sfn.nFilterIndex =1;
sfn.lpstrFileTitle = NULL ;
sfn.nMaxFileTitle = 0 ;
sfn.lpstrInitialDir=NULL;
//sfn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT|OFN_EXPLORER | OFN_ENABLEHOOK ;
sfn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_NOVALIDATE|OFN_HIDEREADONLY ;
if (GetOpenFileName( &sfn ) != TRUE)
{
wstrPathFile = TEXT("");
return wstrPathFile.c_str();
}
DWORD retval=0;
//BOOL success;
TCHAR buffer[BUFSIZE]=TEXT("");
TCHAR buf[BUFSIZE]=TEXT("");
TCHAR** lppPart={NULL};
wchar_t wstrPath[BUFSIZE];
retval = GetFullPathNameW(sfn.lpstrFile,sfn.nMaxFile,wstrPath,lppPart);
if (retval==0)
{
wstrPathFile = TEXT("");
return wstrPathFile.c_str();
}
std::wstring s(wstrPath);
wstrPathFile = s;
wcout<<wstrPathFile<<endl;
return wstrPathFile.c_str();
}
catch (...)
{
PrintToFile("ChooserFile","Error");
wstrPathFile = TEXT("");
return wstrPathFile.c_str();
}
}

I want to the user can only chooser type file specified.
You can't stop the user choosing whatever file they like by typing into the file name edit control. So, you should simply let them do that and instead validate that the file name matches your requirements.
You have a couple of options to do that:
Let the dialog return and if the file name does not meet your requirements, present the user with an error dialog letting them know what went wrong.
Supply a hook procedure in the lpfnHook member of the OPENFILENAME struct. That will get sent a CDN_FILEOK notification message when the user attempts to accept a file. Perform your validation in response to that message. If the file name does not meet requirements, show a message to that effect and return a non-zero value to force the dialog to remain open.

Your code is commenting out the OFN_EXPLORER and OFN_ENABLEHOOK flags, so you must already know about the existence of Explorer-style hooking. As others have told you, you can use that hook to catch the CDN_FILEOK notification to accept/reject a selected filename. For example:
UINT_PTR CALLBACK MyOFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if (uiMsg == WM_NOTIFY)
{
LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;
if (ofn->hdr.code == CDN_FILEOK)
{
LPOPENFILENAMEW lpOFN = (LPOPENFILENAMEW) ofn->lpOFN;
LPWSTR lpExt = PathFindExtensionW(lpOFN->lpstrFile);
if (lstrcmpiW(lpExt, L".XLSX") != 0)
{
SetWindowLongPtr(hdlg, DWL_MSGRESULT, 1);
return 1;
}
}
}
return 0;
}
std::wstring ChooserFile(const char* typeFile)
{
OPENFILEAMEW sfn = {0};
wchar_t w_syFile[MAX_PATH+1] = {0};
size_t convertedChars = 0;
sfn.lStructSize = sizeof(sfn);
sfn.hwndOwner = NULL;
mbstowcs_s(&convertedChars, w_syFile, MAX_PATH, syFile, _TRUNCATE);
sfn.lpstrFile = w_syFile;
sfn.nMaxFile = MAX_PATH;
//TypeFile
sfn.lpstrFilter = L"Microsoft Office Word Documents (*.xlsx)\0*.XLSX\0";
sfn.nFilterIndex = 1;
sfn.lpstrFileTitle = NULL;
sfn.nMaxFileTitle = 0;
sfn.lpstrInitialDir = NULL;
sfn.lpfnHook = &MyOFNHookProc;
sfn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOVALIDATE | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLEHOOK;
if (!GetOpenFileNameW(&sfn))
return L"";
WCHAR szPath[MAX_PATH+1] = {0};
DWORD retval = GetFullPathNameW(sfn.lpstrFile, MAX_PATH, szPath, NULL);
if ((retval == 0) || (retval > MAX_PATH))
return L"";
std::wstring wstrPath(szPath, retval);
std::wcout << wstrPath << endl;
return wstrPath;
}

Related

How to populate CredUIPromptForWindowsCredentials() username field?

Basically, all I'm interested in is to grab the password field in plain text from the data returned, to validate it later on in code. Currently, I'm using CREDUIWIN_GENERIC, but I hate that the user can mess with the username field, so I guess filling it with something by default would be good. I tried CREDUIWIN_ENUMERATE_CURRENT_USER, but it has been returning the password in an unknown encrypted format.
I know that it has something to do with filling the pulAuthPackage, but I have no clue how to do it.
Here is my code:
BOOL save = false;
DWORD authPackage = 0;
LPVOID authBuffer;
ULONG authBufferSize = 0;
CREDUI_INFO credUiInfo;
static WCHAR username[CREDUI_MAX_USERNAME_LENGTH * sizeof(WCHAR)] = { 0 };
static WCHAR password[CREDUI_MAX_PASSWORD_LENGTH * sizeof(WCHAR)] = { 0 };
DWORD uLen = CREDUI_MAX_USERNAME_LENGTH;
DWORD pLen = CREDUI_MAX_PASSWORD_LENGTH;
credUiInfo.pszCaptionText = TEXT("Authentication");
credUiInfo.pszMessageText = TEXT("Please enter your Key in \"Password\".");
credUiInfo.cbSize = sizeof(credUiInfo);
credUiInfo.hbmBanner = NULL;
credUiInfo.hwndParent = NULL;
LPVOID inBuffer = NULL;
ULONG inBufferSize = 0;
HRESULT rc = CredUIPromptForWindowsCredentials(&(credUiInfo), 0, &(authPackage), inBuffer, inBufferSize, &authBuffer, &authBufferSize, &(save), CREDUIWIN_GENERIC);
if (rc == ERROR_SUCCESS)
{
CredUnPackAuthenticationBufferW(0, authBuffer, authBufferSize, username, &uLen, NULL, 0, password, &pLen);
wstring ws(password);
string res(ws.begin(), ws.end());
return res;
}

C++ How To Convert String YYYYMMDD To TimeStamp

I have a program that gets installed on my laptop to a json file.
I retrieve the date of the installed program from registry and I would like to convert that date to a timestamp.
This is my code :
HKEY hUninstKey = NULL;
HKEY hAppKey = NULL;
WCHAR InstallDate[1024];
WCHAR *sRoot = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
long lResult = ERROR_SUCCESS;
DWORD dwType = KEY_ALL_ACCESS;
DWORD dwBufferSize = 0;
//Open the "Uninstall" key.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, sRoot, 0, KEY_READ, &hUninstKey) != ERROR_SUCCESS)
{
}
for (DWORD dwIndex = 0; lResult == ERROR_SUCCESS; dwIndex++)
{
//Enumerate all sub keys...
dwBufferSize = sizeof(sAppKeyName);
if ((lResult = RegEnumKeyEx(hUninstKey, dwIndex, sAppKeyName,
&dwBufferSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS)
{
//Open the sub key.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, sSubKey, 0, KEY_READ, &hAppKey) != ERROR_SUCCESS)
{
RegCloseKey(hAppKey);
RegCloseKey(hUninstKey);
}
//Get the display name value from the application's sub key.
dwBufferSize = sizeof((RegQueryValueEx(hAppKey, L"InstallDate", NULL, &dwType, (unsigned char*)InstallDate, &dwBufferSize) == ERROR_SUCCESS))
{
// Display Date Of Installed Program
const TCHAR* xInstallDate = (TCHAR*)InstallDate;
char DateInstall[MAX_LENGTH + 200];
wcstombs_s(&nNumCharConverted, DateInstall, MAX_LENGTH + 200,
xInstallDate, MAX_LENGTH + 200);
file << "\"',date='" << DateInstall << endl;
}
else {
//Display name value doe not exist, this application was probably uninstalled.
}
RegCloseKey(hAppKey);
}
}
RegCloseKey(hUninstKey);
Could anyone please help with my code?
You should look into the usage of std::chrono::parse. It converts string streams into chrono objects which represent time.
This is the documentation of std::chrono::parse: https://en.cppreference.com/w/cpp/chrono/parse
This is a relevant question on SO (you are possibly a duplicate): How to parse a date string into a c++11 std::chrono time_point or similar?

SHGetFileInfo not return the icon location

I try to extract the icon of file and return it to GetIconLocation of shell extension.
in general I change the icons of files (te.docx.xx) with the extension of xx and returns the icon of file without the xx. (for this I cretae temp file in temp directory with the original extension e.g te.docx)
my operating system is windows 7 x64.
my code is:
STDMETHODIMP CTxtIconShlExt::GetIconLocation (
UINT uFlags, LPTSTR szIconFile, UINT cchMax,
int* piIndex, UINT* pwFlags )
{
DWORD dwFileSizeLo, dwFileSizeHi;
DWORDLONG qwSize;
HANDLE hFile;
OutputDebugStringW(L"Hello world, from GetIconLocation !");
std::string strFilePath;
std::string tempFolder="c:\\.tmp";
std::string tempFile="tmpfile";
std::string fileWithOutDN;
SHFILEINFO retShFileInfo;
for(int i = 0; m_szFilename[i] != 0; i++)
{
strFilePath += m_szFilename[i];
}
fileWithOutDN= strFilePath.substr(0,strFilePath.size()-3 );
std::string extension = fileWithOutDN.substr(fileWithOutDN.find_last_of("."));
CreateDirectory(tempFolder.c_str(),NULL);
tempFile=tempFolder+"\\"+tempFile+extension;
GetFileAttributes(tempFile.c_str()); // from winbase.h
if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(tempFile.c_str()) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
//File not found
HANDLE h = CreateFile(tempFile.c_str(), // name of the file
GENERIC_WRITE, // open for writing
0, // sharing mode, none in this case
0, // use default security descriptor
CREATE_ALWAYS, // overwrite if exists
FILE_ATTRIBUTE_NORMAL,
0);
if (h)
{
CloseHandle(h);
}else
{
return S_FALSE; //faild to create file
}
}
ZeroMemory(&retShFileInfo, sizeof(SHFILEINFO));
CoInitialize(NULL);
SHGetFileInfo(tempFile.c_str(),256,&retShFileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_LARGEICON);
lstrcpyn ( szIconFile, retShFileInfo.szDisplayName, cchMax );
*piIndex = retShFileInfo.iIcon;
*pwFlags = 0;
return S_OK;
my problem is that the retShFileInfo.szDisplayName return an empty array (all items are zero), it should return full path to icon location.
I try to play with the combination of the flags but nothing was helpful

AddFontMemResourceEx

The following code should work to load a font from a binary resource stored in my executable to system memory according to all of the examples I have found but it is not working. "myfont" is the name of the ttf associated with IDR_FONT in the resource file.
DWORD Count ;
HRSRC Resource = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_FONT),"BINARY") ;
DWORD Length = SizeofResource(GetModuleHandle(NULL),Resource) ;
HGLOBAL Address = LoadResource(GetModuleHandle(NULL),Resource) ;
HANDLE Handle = AddFontMemResourceEx(Address,Length,0,&Count) ;
if(Handle==0)
{
MessageBox(hWnd,"Font load failed", "Error",NULL);
}
LOGFONT logfont; //set window font
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfEscapement = 0;
memcpy(logfont.lfFaceName, "myfont", LF_FACESIZE);
logfont.lfHeight = 14;
logfont.lfItalic = FALSE;
logfont.lfOrientation = 0;
logfont.lfOutPrecision = OUT_TT_PRECIS;
logfont.lfQuality = PROOF_QUALITY;
logfont.lfStrikeOut = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfWeight = FW_DONTCARE;
hFont = CreateFontIndirect(&logfont);
Any ideas what I am doing incorrectly?
There are two problems with your code.
You are not checking any of the API functions for failure. Most likely, your call to FindResource() is failing because "BINARY" is not a standard resource type. User-defined resources should use RCDATA instead:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_RCDATA);
Or maybe FONT if it is an actual standard FONT resource:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_FONT);
The actual name of the resource type depends on the content of the .RC file you used to add the resource to the executable, though.
The other problem, and more importatly, is that you are not actually accessing the raw data of the resource so you can pass the real font data to AddFontMemResourceEx(). You need to use LockResource() for that.
Try something more like this instead:
HANDLE AddResourceFont(LPCTSTR ResID, DWORD *Installed)
{
if (Installed) *Installed = 0;
HMODULE hMod = GetModuleHandle(NULL);
DWORD Count, ErrorCode;
HRSRC Resource = FindResource(hMod, ResID, RT_RCDATA); // or RT_FONT or whatever your actual resource type is
if (!Resource)
{
ErrorCode = GetLastError();
//...
return NULL;
}
DWORD Length = SizeofResource(hMod, Resource);
if ((Length == 0) && (GetLastError() != 0))
{
ErrorCode = GetLastError();
//...
return NULL;
}
HGLOBAL Address = LoadResource(hMod, Resource);
if (!Address)
{
ErrorCode = GetLastError();
//...
return NULL;
}
PVOID FontData = LockResource(Address);
if (!FontData)
{
ErrorCode = GetLastError();
//...
return NULL;
}
HANDLE Handle = AddFontMemResourceEx(FontData, Length, 0, &Count);
if (!Handle)
{
ErrorCode = GetLastError();
//...
return NULL;
}
if (Installed) *Installed = Count;
return Handle;
}
.
DWORD Count = 0;
HANDLE hFont = AddResourceFont(MAKEINTRESOURCE(IDR_FONT), &Count);
if (hFont)
{
//...
RemoveFontMemResourceEx(hFont);
}

C++ send HTML email through Outlook

[objective]
Basic C++ console application needs to be able to send HTML emails through Outlook 2007 (which runs minimized) - attachments are not necessary. This method works with plain text and I'm not sure if it can be modified to fit the requirements of HTML. I read somewhere that perhaps you could reference an attachment and it would become the body. I'm just not sure what to do next. Suggestions?
[what I have so far]
BOOL SendMail(CHAR *lpszFrom, CHAR *lpszTo, CHAR *lpszSubject, CHAR *lpszMessage)
{
BOOL bSent = FALSE;
HINSTANCE hMAPI = ::LoadLibrary(_T("mapi32.dll"));
if(0==hMAPI) return bSent;
typedef ULONG (FAR PASCAL *PFN_MAPILogon)(ULONG,LPTSTR,LPTSTR,FLAGS,ULONG,LPLHANDLE);
typedef ULONG (FAR PASCAL *PFN_MAPISendMail)(LHANDLE,ULONG,lpMapiMessage,FLAGS,ULONG);
typedef ULONG (FAR PASCAL *PFN_MAPILogoff)(LHANDLE,ULONG,FLAGS,ULONG);
PFN_MAPILogon MAPILogon = (PFN_MAPILogon)::GetProcAddress(hMAPI,"MAPILogon");
PFN_MAPISendMail MAPISendMail = (PFN_MAPISendMail)::GetProcAddress(hMAPI,"MAPISendMail");
PFN_MAPILogoff MAPILogoff = (PFN_MAPILogoff)::GetProcAddress(hMAPI,"MAPILogoff");
const BOOL bFunctionsLoaded = (0!=MAPILogon)&&(0!=MAPISendMail)&&(0!=MAPILogoff);
ASSERT(bFunctionsLoaded);
if(bFunctionsLoaded)
{
LHANDLE session = 0;
VERIFY(SUCCESS_SUCCESS==MAPILogon(0,0,0,MAPI_NEW_SESSION,0,&session));
ASSERT(0!=session);
MapiRecipDesc recipient;
::ZeroMemory(&recipient,sizeof(recipient));
recipient.ulRecipClass = MAPI_TO;
recipient.lpszName = lpszTo;
MapiMessage message;
::ZeroMemory(&message,sizeof(message));
message.lpszSubject = lpszSubject;
message.lpszNoteText = lpszMessage;
message.nRecipCount = 1;
message.lpRecips = &recipient;
bSent = SUCCESS_SUCCESS == MAPISendMail(session,0,&message,0,0);
VERIFY(SUCCESS_SUCCESS==MAPILogoff(session,0,0,0));
}
::FreeLibrary(hMAPI);
return bSent;
}
Called by...
SendMail("from","to","subject","body");
It looks like MAPI isn't suited for HTML emails.
http://support.microsoft.com/kb/268440
I've sent HTML emails through MFC but that isn't MAPI.
I was sending an requiring the same thing - i found that attaching an html file would result in the html file being used in the body of the email.
the code below was found on this site ( somewhere ) and it works great.
code
bool SendMail(HWND hWndParent, std::string strAttachmentFileName, std::string strSubject,std::string& err)
{
// The attachment must exist as a file on the system
// or MAPISendMail will fail, so......
if (strAttachmentFileName.empty())
return false;
// You may want to remove this check, but if a valid
// HWND is passed in, the mail dialog will be made
// modal to it's parent.
//if (!hWndParent || !::IsWindow(hWndParent))
// return false;
HINSTANCE hMAPI = ::LoadLibraryA("MAPI32.DLL");
if (!hMAPI)
return false;
// Grab the exported entry point for the MAPISendMail function
ULONG (PASCAL *SendMail)(ULONG, ULONG_PTR,
MapiMessage*, FLAGS, ULONG);
(FARPROC&)SendMail = GetProcAddress(hMAPI,
"MAPISendMail");
if (!SendMail)
return false;
// TCHAR szFileName[_MAX_PATH];
// TCHAR szPath[_MAX_PATH];
// TCHAR szSubject[_MAX_PATH];
// ::strcpy(&szFileName[0], strAttachmentFileName.c_str());
// ::strcpy(&szPath[0], strAttachmentFileName.c_str());
// ::strcpy(&szSubject[0], strSubject.c_str());
MapiFileDesc fileDesc;
::ZeroMemory(&fileDesc, sizeof(fileDesc));
fileDesc.nPosition = (ULONG)-1;
fileDesc.lpszPathName = (char *)strAttachmentFileName.c_str();
fileDesc.lpszFileName = (char *)strAttachmentFileName.c_str();
MapiMessage message;
::ZeroMemory(&message, sizeof(message));
message.lpszSubject = (char *)strSubject.c_str();//&szSubject[0];//szSubject;
message.nFileCount = 1;
message.lpFiles = &fileDesc;
// Ok to send
int nError = SendMail(0, (ULONG_PTR)hWndParent,
&message, MAPI_LOGON_UI|MAPI_DIALOG, 0);
if (nError != SUCCESS_SUCCESS &&
nError != MAPI_USER_ABORT &&
nError != MAPI_E_LOGIN_FAILURE)
err = "error";
return false;
err="ok";
return true;
}