This is probably a pretty basic question, but I can't seem to get it. I am working on a visualC++ project and I basically want to get a string from a GUI and then use that as a filename. I have written the following thus far, where IDC_FILE_NAME is the ID of the edit control box but I'm not sure if that is even the way to accomplish this.
m_pFileName = (CEdit*)GetDlgItem( IDC_FILE_NAME );
CString fName =_T(" ");
GetDlgItemTextA(IDC_FILE_NAME, fName);
but I'm not sure if that is even the way to accomplish this.
The answer is YES and NO.
YES if properly used,
NO, not as you do it.
Do not use UNICLODE/ANSI specific versions of functions unless you want to force UNICODE or ANSI.
Your code should look like:
CString csText;
GetDlgItemText(IDC_FILE_NAME, csText);
NOTE GetDlgItemText
This has been tested with VS2015:
//
// Get string from CEdit m_ceDate;
// where
// DDX_Control(pDX, IDC_EDIT_DATE, m_ceDate);
char cdateBuf[128];
UINT nCountOfCharacters = GetDlgItemText(IDC_EDIT_DATE, cdateBuf, 16);
CString csDate = cdateBuf;
Related
I am trying to set up a MFC C++ App in Visual Studio 2019 such that modifies the user's text as they are typing.
Current layout is 2 radio buttons,
ID= rdbOn (set to Group = True, with Value int variable m_isOn = 1)
ID= rdbOff, m_isOn value would be = 0
and 1 Edit Control,
ID= txtInputBox, with Value CString variable m_inputString
Currently, for testing I can see how it would work for a button on click, it would take something like the following and just SetDlgItemText of the result. But that would be after they have typed, not WHILE they are typing.
void Onsomebtnclick()
{
//convert CString to String of m_inputString
//do some string manipulation
//convert back to CString
//SetDlgItemText(txtInputBox, result)
}
Update:
got EN_CHANGE to work
I was able to get EN_CHANGE working with the flag suggestion from user #GoGoWorx. However, now I just have a slight problem that the cursor is back to the beginning of the edit control txtInput.
I'm reading about using a CEdit::SetSel but don't know how to use that directly in my code. I tried
CEdit control MFC, placing cursor to end of string after SetWindowText
someDlg::someFunction()
{
//some logic stuff to get a result string
SetDlgItemText(txtInputBox, result);
//need it to set the cursor to the end
//I tried these, but it didn't recognize (expression must have class type?)
//txtInputBox.SetSel(0, -1);
//txtInputBox.SetSel(-1);
}
It sounds like you need to use the ON_EN_CHANGE message-map notification (called after the control has been updated due to typing or pasting for example)
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_EN_CHANGE(IDC_EDIT_CONTROL, &CMyDialog::OnEnChangeEditControl)
END_MESSAGE_MAP()
void CMyDialog::OnEnChangeEditControl()
{
// Copy or call your Onsomebtnclick() here
}
I'm not sure what you're using for the numeric identifier for the edit control, since these are typically upper case defines - replace IDC_EDIT_CONTROL above with your define (possibly txtInputBox, but again, these are normally upper case, so I'm not sure).
Also change CMyDialog for the name of your dialog class too.
Note that we're using the ON_EN_CHANGE message-map handler here instead of the ON_EN_UPDATE, since the ON_EN_CHANGE message is sent after the control has been updated, whereas ON_EN_UPDATE is called just before it's updated.
The message-map handlers are described in the Remarks section of the CEdit control documentation: https://learn.microsoft.com/en-us/cpp/mfc/reference/cedit-class?view=msvc-160
Regarding your concern about modifying things as the user types - this should be fine, since every change (keystroke or paste from clipboard, etc.) should trigger this handler to be called, where you can change whatever you need. Just be sure that when you're updating the control, you don't trigger the ON_EN_CHANGE again and end up in a recursive 'change' loop.
You might be able to do this with some sort of flag to indicate you're the one updating the control, as opposed to the user, however it's probably better to subclass the CEdit control to do what you're wanting. There are a few examples out there of how to do this (it's not as difficult as it might sound), for example:
https://www.codeproject.com/Articles/27376/Avoiding-EN-CHANGE-notifications
How to convert System::string^ in to LPCTSTR ?
As my requirement is to clone a file using function CopyFile, it works fine if i give Fix name (OldFile.jpg and LatestFile.jpg) to its parameters (below Code: Works Fine)
LPCTSTR in_f,out_f;
in_f = _T("d:\\Old.jpg");
out_f = _T("d:\\Latest.jpg");
CopyFile(in_f,out_f,false);
above code clone the Old.jpeg in to a Latest.jpg but when i trying to give name (Latest.jpg) which is coming out from some String it won't create file (below Code: NOT Working)
String^ Name = "Latest";
//------Capture Current Date & Time
DateTime datetime = DateTime::Now;
//-------Convert Date Timt in to String
Name = Name + String::Format("{0}",datetime);
Name = Name->Replace('/','-');
Name = Name->Replace(':','-');
Name = Name + ".jpg";
LPCTSTR in_f,out_f;
in_f = _T("d:\\Old.jpg");
out_f = (LPCTSTR)Name; //Trying to Assign Current Latest file Name With date Time here
CopyFile(in_f,out_f,false);
The Problem is CopyFile Took LPCTSTR type as an argument , where as i am giving a type System::string^, So suggest me how to convert this System::string^ in to LPCTSTR so that i can add the current date time with in the name of my file.
I am Using VC++2010 and Windows form Application
Standard warning: While it's certainly possible to write the main body of your application in C++/CLI, or even write the GUI in C++/CLI using WinForms, it is not recommended. C++/CLI is intended for interop scenarios: where C# or other .Net code needs to interface with unmanaged C++, C++/CLI can provide the translation between the two. For primary development, it is recommended to use C# with either WinForms or WPF if you want managed code, or C++ with MFC if you want unmanaged.
I'm not sure I agree with Hans's comment that TCHAR is obsolete, but doing an explicit conversion to a wide string and calling CopyFileW is a good option.
Also, one could go the other direction, and convert from unmanaged to managed strings, and use the .Net method to copy files, File::Copy(String^, String^, Boolean).
To convert to a LPCTSTR, I would use marshal_as. Because it's implemented with templates, the compiler will resolve your LPCTSTR to call either the LPCSTR or LPCWSTR version, as appropriate.
Microsoft doesn't have dedicated documentation pages for each templated version of marshal_as, but the Overview of Marshaling in C++ page is a good place to start.
My test program:
#include <msclr\marshal.h>
int main(array<System::String^>^ args)
{
String^ managedStr = "I came from managed land!\r\n";
// This controls the lifetime of the LPCTSTR that marshal_as returns.
// When this goes out of scope, the LPCTSTR will no longer be valid,
// so be aware of its lifetime.
msclr::interop::marshal_context context;
LPCTSTR unmanagedStr = context.marshal_as<LPCTSTR>(managedStr);
OutputDebugString(unmanagedStr);
return 0;
}
Result:
I came from managed land!
You need to append a \0 character at the end of the Name string, since CopyFile() expects zero-terminated strings.
EDIT: As LucasTrzesniewski has pointed out, pinning a .NET string automatically yields a zero-terminated character array. This is documented in the C# specification. See the comments below for more information.
Moreover, you have to "pin" the string in memory, so the garbage collector won't move it around. Then you can create a pointer to the first character of the string. C++/CLI provides some utility types and functions to do this. Here's an example:
pin_ptr<const WCHAR> psName = PtrToStringChars (Name)
PtrToStringChars() is an inline function declared in vcclr.h. psName should be assignable to a LPCTSTR parameter - if not, use a cast. Note that PtrToStringChars() doesn't work if the input string is a nullptr. You need to test explicitly for this case. (However, in your case, Name is certainly not a nullptr).
The String remains pinned until the variable psName gets out of scope. This happens after leaving the { ... } block in which it's declared, e.g. after leaving the current function. No explicit unpinning is needed.
You need to marshaling it to "const char *" and make a static_cast to LPCTSTR.
Take a look at this https://msdn.microsoft.com/en-us/library/bb384865.aspx
I have got a library which was made for a desktop windows project. It is done in MFC VC++ by somebody else, and it works correctly. I will use one particular function from the library as an example for explaining the situation.
The example function goes like this:
CString GetFulPath(); // .h file
In the cpp file,
CString CwFolderBrowser::GetFullPath()
{
CString path;
if(this->M_pIDLIST!=NULL)
{
LPTSTR fullPath=path.GetBuffer(MAX_PATH);
::SHGetPathFromIDList(this->M_pIDLIST, fullPath); //ITEMIDLISTからパスを得る
path.ReleaseBuffer();
}
return path;
}
Now, I can include this library in my project and do something like:
CwFolderBrowser cFolderBrowser;
if(cFolderBrowser.ShowDialog() == TRUE)
cPath = cFolderBrowser.GetFullPath();
This will show a folder browser dialog and let me choose a folder. It works fine on desktop windows.
Currently, I am working on Windows CE device. We have converted the library for use with Windows CE by removing unsupported functions and stuff. The library compiles and builds correctly without errors.
Next, I create an MFC Smart Device project, include the converted library, its h file and lib files and set the proper directories for dlls. The project builds fine. I can #include the library's h file properly too.
The problem arises as soon as I call the GetFullPath function:
cPath = cFolderBrowser.GetFullPath();
It gives me an unresolved external link error! The Intellisense does show this function in its list and I can choose it and everything. But in vain.
Strangely, If I modify the library and change GetFullPath()'s signature as below,
LPCTSTR GetFulPath(); // .h file LPCTSTR instead of CString
In the cpp file,
LPCTSTR CwFolderBrowser::GetFullPath() // Return type changed to LPCTSTR
{ // instead of CString
... // Body modified accordingly
}
then, the unresolved external Link error disappears and it works!
I am stumped about this strange behaviour, because, I can use CString normally in the MFC Smart Device project and there are no errors. The link error shows up only when I try to call functions from the library (and other such libraries) dll. At the same time, BOOL, int etc. seems to have no problems as function return types.
Ofcourse, I can go through each library and change every instanceof a CString return to LPCTSTR, but that would be a very big change. I would like to know why CString works fine in project as well as dll when on desktop, while, on Win CE, it works in the project but not i the DLL (At the same time, the DLL itself compiles fine without errors wether it uses CString or LPCTSTR!).
So, basically, I would like to keep the function CString if possible, and would like to know the reason why this happens. The exact same error also happenes in other libraries too.
Any help is appreciated. Thank you.
UPDATE:
I saw a page on ATL & MFC 7.0 which said about using the /Zc:wchat_t option. I have checked the Dll project as well as my application. Both use the same option of 'Treat wchar_t as Built-in type' as Yes. So, that option matches up.
Further, as I mentioned above, changing the function return to LPCTSTR works. The error disappears. Everything is going fine until I convert the returned LPCTSTR back to CString. The CString turns out as empty/Null. This happens both inside the dll code itself, as well as in my application code too.
UPDATE2:
Thanks to Michael and Cody, I changed the function to LPCTSTR and made sure that the values were not going out of scope before I could use them like they suggested. Now the empty/Null problem is solved and I can get the path values properly.
The problem that remains is that I have to convert all the CString functions to LPCTSTR, which is not exactly feasible. I would like to keep the functions as CString.
This is a classic problem and has been asked often here on SO.
This cannot work:
LPCTSTR CwFolderBrowser::GetFullPath()
{
CString path;
if(this->M_pIDLIST!=NULL)
{
LPTSTR fullPath=path.GetBuffer(MAX_PATH);
::SHGetPathFromIDList(this->M_pIDLIST, fullPath);
path.ReleaseBuffer();
}
return (LPCTSTR)path; // << here you return a pointer to the zero
// terminated string in the path object,
} // but path will be deleted as soon as it goes
// out of scope
Maybe in some cases the function appears to work because the memory of the deleted CString object has not yet been overwritten.
You should do this (no error treatment here for simplicity):
LPCTSTR CwFolderBrowser::GetFullPath(TCHAR *pathbuffer)
{
if(this->M_pIDLIST!=NULL)
{
::SHGetPathFromIDList(this->M_pIDLIST, pathbuffer);
}
return (LPCTSTR)pathbuffer;
}
...
// call like this
TCHAR pathbuffer[MAX_PATH];
GetFullPath(pathbuffer);
using MFC and Unicode-Build
i want to change the colum-header-text of a listctrl and to do so i have to convert an LPCTSTR to an LPWSTR. what i do now is
void CSPCListViewCtrl::SetHeaderText(long lCol, LPCTSTR lColText)
{
CListCtrl& ListCtrl = GetListCtrl();
LV_COLUMN lvc;
::ZeroMemory((void *)&lvc, sizeof(LVCOLUMN));
lvc.mask |= LVCF_TEXT;
ListCtrl.GetColumn(lCol, &lvc);
lvc.pszText = const_cast<LPWSTR>(lColText);
ListCtrl.SetColumn(lCol, &lvc);
}
it seems to work but the const_cast looks somewhat strange and wrong to me so i tried out something like
USES_CONVERSION;
lvc.pszText = CT2W(lColText);
this seems to work in release-build but produces garbage in debug-build so i wonder what is the correct way to do it?
TL;DR: Using const_cast<LPTSTR>(lColText) is safe when calling CListCtrl::SetColumn.
But why then is the pszText member of the LVCOLUMN structure declared non-const? The LVCOLUMN structure is used both to set and retrieve information. When retrieving a column's text, you need to pass in a modifiable buffer (and length argument). When setting a columns text, on the other hand, the system uses the pszText member and internally stores a copy. It does not attempt to write to it. This is documented as well, even if very subtly:
cchTextMax
Size in TCHARs of the buffer pointed to by the pszText member. If the structure is not receiving information about a column, this member is ignored.
This is a common pattern in the Windows API, where the same structure is used both as an input and output parameter. The only option to work around this would have been to introduce a const-ified version for those structures. When the Windows API was invented 30 years ago, this wasn't deemed necessary or useful. Besides, it would have made a common pattern (read-update-write) more tedious and error prone, as the data would have to be manually copied between unrelated types.
Now that you know, that using a const_cast is safe in the scenario you described, you may be wondering, if it is a good idea to use it. That depends on a number of factors, e.g.
Can you come up with a helpful comment to concisely explain, why this is ok? Something along the lines of // Totally safe, it's just that M$ sucks probably won't cut it.
Will all members on your team understand the implications, or will this present a red herring in heap corruption debug sessions?
Do you have coding guidelines that allow the use of const_casts?
Are you using static code analysis tools that won't produce false positives for const_casts?
If you find that you cannot satisfactorily answer all those questions, you may consider implementing (technically unnecessary) manual copying (and exchange a const_cast for exception handling):
void CSPCListViewCtrl::SetHeaderText(long lCol, LPCTSTR lColText) {
CListCtrl& ListCtrl = GetListCtrl();
LVCOLUMN lvc = {0};
lvc.mask |= LVCF_TEXT;
// Create modifiable copy of lColText
size_t colTextLength = _tcslen(lColText);
std::vector<TCHAR> buffer(colTextLength + 1);
std::copy(lColText, lColText + colTextLength + 1, buffer.data());
lvc.pszText = buffer.data();
ListCtrl.SetColumn(lCol, &lvc);
}
One more note on your use of character string encodings: You are mixing the use of Generic-Text Mappings with explicit Unicode (UTF-16LE) encoding. To add consistency, you should change the lColText argument to type LPCWSTR, and use an LVCOLUMNW structure (as well as a const_cast<LPWSTR> if you decide to go that route). Unfortunately, when using MFC, you will have to resort to using the generic-text mappings when calling any class members. But at least you will get a compiler error in case of mismatching character encodings.
You can use CString::GetBuffer()
void SetHeaderText(long lCol, LPCTSTR lColText)
{
LV_COLUMN lvc;
::ZeroMemory((void *)&lvc, sizeof(LVCOLUMN));
lvc.mask |= LVCF_TEXT;
list.GetColumn(lCol, &lvc);
CString str = lColText;
lvc.pszText = str.GetBuffer();
list.SetColumn(lCol, &lvc);
str.ReleaseBuffer();
//ReleaseBuffer is option in this case because
//"str" is local variable and is destroyed before being used again*
}
SetHeaderText(0, L"text");
In UNICODE, LPTSTR is just LPWSTR (or simply wchar_t*)
If for some reason you have ANSI text, then you can use CString for conversion
CStringA ansi = "Text";
CStringW wide = CStringW(ansi);
SetHeaderText(0, wide);
See also
CString::GetBuffer()
I am currently reviewing code written in c#, visual studio 2012.
In lot of places, the code is written using this key word, for ex:
this.pnlPhoneBasicDtls.Visible = true;
this.SetPhAggStats(oStats);
There are many other places where the controls of the page are referred using this key word.
Can somebody advise do we really need to use this here?
Any consequences of removing this keyword?
Thanks in advance..
No, "this" is optional. It's usually included in code generated by a tool and by people who feel the need to be explicit or who want to differentiate it from an argument to the method.
Its Optional you can use the
Property directly like pnlPhoneBasicDtls.Visible = true;
The this keyword is usually optional.
It's sometimes used to disambiguate fields from arguments if the same name is being used for both, for example:
void Main()
{
var sc = new SomeClass();
sc.SomeMethod(123);
Console.WriteLine(sc.thing);
}
public class SomeClass
{
public int thing;
public void SomeMethod(int thing)
{
this.thing = thing + 1;
}
}
In the example above it does make a difference. Inside SomeMethod, this.thing refers to the field and thing refers to the argument.
(Note that the simpler assignment thing = thing is picked up as a compiler error, since it is a no-op.)
Of course, if you use ReSharper then any unnecessary this. (together with unused using statements, unreachable code, etc.) will be greyed out and you can remove them very quickly. The same is probably true of similar tools like CodeRush.