CRichEditCtrl::StreamIn losing formatting - c++

I am creating a CRichEditCtrl control and trying to load some RTF into it. The text seems to load fine, but it loses all formatting, essentially becoming plain text.
I think some sample code should suffice to make it clear:
class MyWindow : public CWnd {
void Setup();
static DWORD CALLBACK StreamInCallback_(
DWORD_PTR dwCookie, LPBYTE pbBuff,
LONG cb, LONG *pcb);
...
CRichEditCtrl content_;
};
void MyWindow::Setup() {
RECT text_rect;
GetClientRect(&text_rect);
text_rect.left += 8;
text_rect.right -= 16;
text_rect.top += 8;
text_rect.bottom -= 36;
content_.Create(WS_CHILD | WS_VISIBLE | ES_MULTILINE,
text_rect, this, 1001);
content_.SetTextMode(TM_RICHTEXT);
CString text = L"{\\rtf1\\par Simple \\b example \\b0}";
EDITSTREAM es;
es.dwCookie = reinterpret_cast<DWORD_PTR>(&text);
es.pfnCallback = StreamInCallback_;
int n = content_.StreamIn(SF_RTF, es);
}
DWORD CALLBACK MyWindow::StreamInCallback_(DWORD_PTR dwCookie, LPBYTE pbBuff,
LONG cb, LONG *pcb) {
CString *pText = reinterpret_cast<CString *>(dwCookie);
if (cb > pText->GetLength()) {
cb = pText->GetLength();
}
// TODO: this will only work for US-ASCII
for (int i = 0; i < cb; i++) {
*(pbBuff + i) = (BYTE) pText->GetAt(i);
}
*pcb = cb;
*pText = pText->Mid(cb);
return 0;
}
You can see an example of what this looks like in the screenshot below:
As you can see, it's got the text OK, but the word "example" should be bold. I've tried lots of different RTF, even taking what's saved by Wordpad and using that directly, but it still only displays the text as plain text and all formatting is lost. No errors are returned from any of the function calls, either.

Sure looks correct to me. Though, I've never used SetTextMode(TM_RICHTEXT) when dealing with RTF content. Try removing that call.
Also, an erroneous StreamInCallback may yield weird text problems. I suggest you do it the right way from start:
DWORD CALLBACK CBStreamIn(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
CString *pstr = (CString*)dwCookie;
if (pstr->GetLength() < cb)
{
*pcb = pstr->GetLength();
memcpy(pbBuff, (LPCSTR) *pstr, *pcb);
pstr->Empty();
}
else
{
*pcb = cb;
memcpy(pbBuff, (LPCSTR) *pstr, *pcb);
*pstr = pstr->Right(pstr->GetLength() - cb);
}
return 0;
}

Try if setting headers in the RTF works. Check following link
http://www.biblioscape.com/rtf15_spec.htm
Check if this works in your richeditctrl.
{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0\\fnil\\fcharset0 Calibri;}}\\par Simple \\b example \\b0}

Related

Win32 Scard.h c++ - having issues with the api [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I'm trying to look into smart card reading and I've immediately encountered an issue that I'm struggling with. I've called the SCardEstablishContext and I'm now trying to list the cards readers. I'm getting success and Its telling me there are 89 bytes worth of string data but the string isn't being written out to me. I'm not sure what the issue could be, my code is pretty much identical to the example code on msdn only I've gotten some memory using virtualalloc for the string to.
I've tried changing types and connecting, disconnecting smart card reader, restarting the system etc etc stepping through in the debugger for each and every change attempted. Same issue, either in getting 89 empty bytes or im hitting my asserts for not succeeding at getting the context or so on.
#include <Windows.h>
#include <stdint.h>
#include <winscard.h>
#include <stdio.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef uint32_t b32;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
#define l_persist static
#define gvar static
#define internal static
#define KiloBytes(Value) ((Value) * 1024LL)
#define MegaBytes(Value) (KiloBytes(Value) * 1024LL)
#if INTERNAL
#define Assert(exp) if (!(exp)) {*((u8*)0) = 0;}
#define AssertWithMessage(exp, message) if (!(exp)) {OutputDebugString("\nAssertion failed: "); OutputDebugString(message); OutputDebugString("\n"); Assert(exp);}
#else
#define Assert(exp)
#define AssertWithMessage(exp, message)
#endif
#define U32_MAX 0xFFFFFFFF
b32 G_IsRunning = true;
LRESULT CALLBACK MainWindowCallback(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
{
LRESULT Result = 0;
switch(Message)
{
case WM_CLOSE:
case WM_QUIT:
case WM_DESTROY:
{
G_IsRunning = false;
} break;
default:
{
Result = DefWindowProc(Window, Message, WParam, LParam);
}
}
return Result;
}
void MessagePump(HWND Window)
{
MSG Message = {};
u32 InputCount = 0;
while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE))
{
switch(Message.message)
{
case WM_QUIT:
{
G_IsRunning = false;
} break;
default:
{
TranslateMessage(&Message);
DispatchMessage(&Message);
} break;
}
}
}
INT CALLBACK
WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, INT ShowCommand)
{
WNDCLASS WindowClass = {};
WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = MainWindowCallback;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = "MainWindowClass";
if (RegisterClass(&WindowClass))
{
HWND Window = CreateWindowEx(0,WindowClass.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,0,0,Instance, 0);
if (Window)
{
SCARDCONTEXT CardContext = U32_MAX;
LONG CardContextSuccess = SCardEstablishContext(SCARD_SCOPE_USER, 0, 0, &CardContext);
Assert(CardContextSuccess == SCARD_S_SUCCESS);
u8 *Memory = (u8*)VirtualAlloc(0, KiloBytes(1), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
u8 *MemoryHead = Memory;
LPSTR ReadersList = (char*)MemoryHead;
LPSTR ReadersListWip = 0;
DWORD ReadersListSize = 0;
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, (LPSTR)&ReadersList, &ReadersListSize);
Assert(ReadersList);
Assert(ReadersListSize);
switch(CardReadersListStatus)
{
case SCARD_S_SUCCESS:
{
ReadersListWip = ReadersList;
while ( '\0' != *ReadersListWip )
{
printf("Reader: %S\n", (wchar_t*)ReadersListWip );
// Advance to the next value.
ReadersListWip = ReadersListWip + wcslen((wchar_t *)ReadersListWip) + 1;
}
} break;
case SCARD_E_NO_READERS_AVAILABLE:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "There were no card readers available");
G_IsRunning = false;
} break;
case SCARD_E_READER_UNAVAILABLE:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "The card reader was unavailable");
G_IsRunning = false;
} break;
default:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "Some other issue with card reader listing");
G_IsRunning = false;
}
}
while(G_IsRunning)
{
MessagePump(Window);
LPSCARDHANDLE CardHandle = 0;
DWORD ActiveProtocol = 0;
LONG CardConnectStatus = SCardConnectA(CardContext, ReadersList, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, (LPSCARDHANDLE)&CardHandle, &ActiveProtocol);
Assert(CardConnectStatus == SCARD_S_SUCCESS);
}
}
}
return 0;
}
Above is the code as it stands after my last batch of tests. I am quite rusty but I can't see why I'm getting a size back but not getting the strings.
Is there an alternative api for card reading?
I recognize that the loop is no good at the end there that was an artefact left from some previous efforts earlier on. I'm stepping through it anyway so I'm ignoring it for now.
Thanks to Raymond Chen's comments I've realised my errors and can progress in learning the SCARD api. Mostly my mistake, but I feel that the documentation on MSDN could have been clearer. Particularly in regards to the third argument to SCardListReaders() which is an in/out parameter. I did not realise that setting the parameter to zero would return the size and then would require a second call to the same function with the buffer of sufficient length. I failed to notice the SCARD_AUTOALLOCATE section of the documentation. Not entirely sure how I manage to overlook that but I somehow did. I found this function quite confusing for those reasons.
Credit for helping me realise my errors goes to the infamous Raymond Chen.
Below I've written some annotated demonstration code for anyone in future who might find the api confusing as I found earlier this evening.
LPSTR ReadersList; //im no longer initializing to zero here because a null argument tells the function to just return the size of the string(s).
#define one_call_version 0
#if one_call_version
DWORD ReadersListSize = SCARD_AUTOALLOCATE; //passing this will cause the function to allocate some memory for you and return the strings inside that block of memory.
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, (LPSTR)&ReadersList, &ReadersListSize);
//ReadersListSize now points to a populate block of memory that needs to be frees via SCardFreeMemory or process termination.
#else //ReadersList = (LPSTR)calloc(ReadersListSize, sizeof(char)); //ReadersList = (LPSTR)malloc(ReadersListSize);
DWORD ReadersListSize = 0;
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, 0, &ReadersListSize); //1ST// call with null 3rd argument will just get the size of the readers list string
//ReadersListSize should now be modified to contain the minimum required size of memory allocation to contain the string(s) in bytes.
ReadersList = (LPSTR)VirtualAlloc(0, ReadersListSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
CardReadersListStatus = SCardListReaders(CardContext, 0, ReadersList, &ReadersListSize); //2ND// call with the buffer of sufficient size for the string(s) as 3rd argument should populate the buffer
#endif //Should now have the ReadersList populated with the names of the connected smart card reader devices.

Trying to get text from tooltips not working

I've been trying for a couple of hours to interrogate tooltips to give up the text they contain to no avail. I've found How to get tooltip text for a given HWND? and tried that without success.
This shouldn't be that hard. I'm just not sure what I'm doing wrong. Here's a section of my code:
BOOL CALLBACK EnumWindowsProc(
_In_ HWND hwnd,
_In_ LPARAM lParam
)
{
TCHAR className[200];
GetClassName(hwnd, className, _countof(className));
ASSERT(IsWindow(hwnd));
if (_tcscmp(className, _T("tooltips_class32")) == 0)
{
TOOLINFO ti = { 0 };
ti.cbSize = sizeof(TOOLINFO);
TCHAR text[500] = { 0 };
ti.lpszText = text;
ti.hwnd = GetParent(hwnd);
IsWindow(ti.hwnd);
ti.uId = GetDlgCtrlID(hwnd);
int result = SendMessage(hwnd, TTM_GETTEXT, _countof(text), (LPARAM)&ti);
CString info;
info.Format(_T("%p: %s \"%s\"\r\n"), hwnd, className, ti.lpszText);
CString& output = *(CString*)lParam;
output += info;
}
return 1;
}
void CTooltipVerifyDlg::OnTimer(UINT_PTR nIDEvent)
{
m_output = "";
VERIFY(EnumWindows(EnumWindowsProc, (LPARAM)&m_output));
SYSTEMTIME systemTime;
GetLocalTime(&systemTime);
CString text;
text.Format(_T("%02u:%02u:%02u.%03u\r\n"), systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
m_output = text + m_output;
this->UpdateData(FALSE);
CDialogEx::OnTimer(nIDEvent);
}
CTooltipVerifyDlg is a dialogue with a text box which I communicate to with m_output, a CString that is bound to the text box.
When the SendMessage call is done, something on my desktop (or even the desktop manager) crashes. Any ideas why it would be crashing and not giving me the text that I desire?

CRichEditCtrl::StreamIn doesn't read the whole text file

I have a text file that I would like to read and then put it in a rich edit box. The problem is, the pbBuff buffer gets the whole file, but then only the first line is added to the CRichEditCtrl widget.
Here is the callback function:
static DWORD CALLBACK StreamInCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
{
CFile* dat = (CFile*) dwCookie;
*pcb = dat->Read(pbBuff, cb);
return 0;
}
And how I set it in the OnInitDialog() function:
CFile dat(_T("readme.txt"), CFile::modeRead);
EDITSTREAM es;
es.dwCookie = (DWORD)&dat;
es.pfnCallback = StreamInCallback;
m_RichEditBesedilo.StreamIn(SF_TEXT, es);

Prompting a user with an input box? [C++]

My goal is to simply use a pop-up box to ask the user for an input. I've searched around quite a bit and pretty much all the results say that creating a messageBox is really easy:
MessageBox (NULL, "Hello World" , "Hello", MB_OKCANCEL);
But that creating a pop-up that takes input is more involved and there isn't a straight forward way to do it. All of the results I could find on Google were dated somewhere from 2001 to 2005. I guess I'm here asking if some more straight forward solution has come about in recent years.
Hopefully something nice and straight forward like in Java:
int number = JOptionPane.showInputDialog ("Enter an integer");
If that isn't the case, could I get a brief explanation of how to do it?
Edit: I couldn't get anything to work. :( I ended up writing the code to do the work in Java, and then wrote one line of C++ code to call the .jar file. :-/ Since the issue was time sensitive, it was better than nothing.
If you are using Visual C++ Express there are a number of free resource editors that can be used to create dialogs. ResEdit is one of the better ones I've found.
You need to create a dialog resource in a .RC file that you add to your project.
Then, It is a very simple case of calling DialogBox - which will load the dialog box from your resource file and place it on the screen. The passed in DialogProc will be called with a number of notifications. Typically you would want to return FALSE for everything, but handle WM_INITDIALOG as a place to initialize the edit control with text, and WM_COMMAND will be sent when a button is clicked.
There is nothing like that for pure C++. Basically what you're trying to do can only be achieved by using an API call to the OS or by using some GUI library like Qt (which I recommend cause it's waaaaay easier then calling native APIs and it's also multi-platform)
Using Qt you can show an input dialog pretty much the same way you do it on java:
bool ok;
QString text = QInputDialog::getText(
"MyApp 3000", "Enter your name:", QLineEdit::Normal,
QString::null, &ok, this );
if ( ok && !text.isEmpty() ) {
// user entered something and pressed OK
} else {
// user entered nothing or pressed Cancel
}
You can download the Qt library here: qt.nokia.com/products/developer-tools/
Microsoft doesn't consider your use case to be common enough to optimize for, as with MessageBox. They expect you to lay out a dialog with many controls on it, perhaps with some complex interaction with the controls, and only respond once the dialog is fully filled in. What you're asking for is just the simplified version of that.
The resource editor is the easiest way to create a dialog, but that's not included in the free Express version of Visual Studio. You would design the dialog with a text control for the prompt and an edit control for the user to fill in. You present the dialog with the DialogBox Windows function, and it returns when the user hits the OK button or the X in the corner of the dialog. Microsoft has some documentation for it here.
There are a few platforms available that try to make the process easier, such as MFC, WTL, Qt, and wx, but this is how you'd do it with the pure Windows API.
My answer is based on Stephen Quan's answer to How to load & call a VBScript function from within C++? Added full UTF-8 support, as you can gather from the code comments in the CPP file. Unlike using Microsoft Script Control to create the InputBox, this can be used in x86 and x64 executables, libraries, and controls.
"inputbox.h":
extern "C" char *InputBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
extern "C" char *PasswordBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
"inputbox.cpp":
#include "inputbox.h"
// Windows API
#include <windows.h>
// VBScript InputBox
#include <atlbase.h>
#include <activscp.h>
#include <comdef.h>
// UTF-8 Support
#include <wchar.h>
#include <string>
#include <vector>
using std::string;
using std::wstring;
using std::vector;
static wstring StringWiden(string Str) {
const size_t wchar_tCount = Str.size() + 1;
vector<wchar_t> Buffer(wchar_tCount);
return wstring { Buffer.data(), (size_t)MultiByteToWideChar(CP_UTF8, 0, Str.c_str(), -1, Buffer.data(), wchar_tCount) };
}
static string StringShorten(wstring Str) {
int nBytes = (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), NULL, 0, NULL, NULL);
vector<char> Buffer((size_t)nBytes);
return string { Buffer.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), Buffer.data(), nBytes, NULL, NULL) };
}
static string StringReplaceAll(string Str, string SubStr, string NewStr) {
size_t Position = 0;
const size_t SubLen = SubStr.length(), NewLen = NewStr.length();
while ((Position = Str.find(SubStr, Position)) != string::npos) {
Str.replace(Position, SubLen, NewStr);
Position += NewLen;
}
return Str;
}
static string CPPNewLineToVBSNewLine(string NewLine) {
size_t Position = 0;
while (Position < NewLine.length()) {
if (NewLine[Position] == '\r' || NewLine[Position] == '\n')
NewLine.replace(Position, 2, "\" + vbNewLine + \"");
Position += 1;
}
return NewLine;
}
class CSimpleScriptSite :
public IActiveScriptSite,
public IActiveScriptSiteWindow {
public:
CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { }
// IUnknown
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
// IActiveScriptSite
STDMETHOD(GetLCID)(LCID* plcid) { *plcid = 0; return S_OK; }
STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti) { return TYPE_E_ELEMENTNOTFOUND; }
STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; }
STDMETHOD(OnScriptTerminate)(const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo) { return S_OK; }
STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; }
STDMETHOD(OnScriptError)(IActiveScriptError* pIActiveScriptError) { return S_OK; }
STDMETHOD(OnEnterScript)(void) { return S_OK; }
STDMETHOD(OnLeaveScript)(void) { return S_OK; }
// IActiveScriptSiteWindow
STDMETHOD(GetWindow)(HWND* phWnd) { *phWnd = m_hWnd; return S_OK; }
STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; }
// Miscellaneous
STDMETHOD(SetWindow)(HWND hWnd) { m_hWnd = hWnd; return S_OK; }
public:
LONG m_cRefCount;
HWND m_hWnd;
};
STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef() {
return InterlockedIncrement(&m_cRefCount);
}
STDMETHODIMP_(ULONG) CSimpleScriptSite::Release() {
if (!InterlockedDecrement(&m_cRefCount)) {
delete this;
return 0;
}
return m_cRefCount;
}
STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow) {
*ppvObject = (IActiveScriptSiteWindow*)this;
AddRef();
return NOERROR;
}
if (riid == IID_IActiveScriptSite) {
*ppvObject = (IActiveScriptSite*)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
static HHOOK hHook = 0;
static bool HideInput = false;
static LRESULT CALLBACK InputBoxProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < HC_ACTION)
return CallNextHookEx(hHook, nCode, wParam, lParam);
if (nCode = HCBT_ACTIVATE) {
if (HideInput == true) {
HWND TextBox = FindWindowExA((HWND)wParam, NULL, "Edit", NULL);
SendDlgItemMessageW((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, L'\x25cf', 0);
}
}
if (nCode = HCBT_CREATEWND) {
if (!(GetWindowLongPtr((HWND)wParam, GWL_STYLE) & WS_CHILD))
SetWindowLongPtr((HWND)wParam, GWL_EXSTYLE, GetWindowLongPtr((HWND)wParam, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
static char *InputBoxHelper(char *Prompt, char *Title, char *Default) {
// Initialize
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
CSimpleScriptSite* pScriptSite = new CSimpleScriptSite();
CComPtr<IActiveScript> spVBScript;
CComPtr<IActiveScriptParse> spVBScriptParse;
hr = spVBScript.CoCreateInstance(OLESTR("VBScript"));
hr = spVBScript->SetScriptSite(pScriptSite);
hr = spVBScript->QueryInterface(&spVBScriptParse);
hr = spVBScriptParse->InitNew();
// Replace quotes with double quotes
string strPrompt = StringReplaceAll(Prompt, "\"", "\"\"");
string strTitle = StringReplaceAll(Title, "\"", "\"\"");
string strDefault = StringReplaceAll(Default, "\"", "\"\"");
// Create evaluation string
string Evaluation = "InputBox(\"" + strPrompt + "\", \"" + strTitle + "\", \"" + strDefault + "\")";
Evaluation = CPPNewLineToVBSNewLine(Evaluation);
wstring WideEval = StringWiden(Evaluation);
// Run InpuBox
CComVariant result;
EXCEPINFO ei = {};
DWORD ThreadID = GetCurrentThreadId();
HINSTANCE ModHwnd = GetModuleHandle(NULL);
hr = pScriptSite->SetWindow(GetAncestor(GetActiveWindow(), GA_ROOTOWNER));
hHook = SetWindowsHookEx(WH_CBT, &InputBoxProc, ModHwnd, ThreadID);
hr = spVBScriptParse->ParseScriptText(WideEval.c_str(), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei);
UnhookWindowsHookEx(hHook);
// Cleanup
spVBScriptParse = NULL;
spVBScript = NULL;
pScriptSite->Release();
pScriptSite = NULL;
CoUninitialize();
// Result
static string strResult;
_bstr_t bstrResult = (_bstr_t)result;
strResult = StringShorten((wchar_t*)bstrResult);
return (char*)strResult.c_str();
}
char *InputBox(char *Prompt, char *Title, char *Default) {
HideInput = false;
return InputBoxHelper(Prompt, Title, Default);
}
char *PasswordBox(char *Prompt, char *Title, char *Default) {
HideInput = true;
return InputBoxHelper(Prompt, Title, Default);
}
Create the two above files and then add them to your Visual Studio project.
In any file you want the input or password box functions, (found in the header), simply include the header:
#include "inputbox.h"
// use functions here
I also got rid of the default Windows application icon in the title bar of the VBScript InputBox, because a lot of people I've seen complain about how ugly it is to see that there.
Let me know if you have any questions.
I have to admit that I haven't really done much in the way of input boxes in ages, but you basically have to go outside C++ in order to get any kind of graphical input box. There's simply no mechanism built into the language for that kind of stuff for portability reasons. I don't remember if it applied to C++ as well, but C doesn't even assume you have a console. Anyway, your best bet would be something along the lines you were already trying: Win32 API, Qt, etc. If you can use the console, however, feel free to just use the iostream library to get the job done.
Using a console window is better suited to the mode of communication where a program prompts the user, continues, prompts the user again, and so on.
And for that you can use the standard library's facilities like cin and cout.
Unlike Visual Basic and other languages, there is no "built in" Input Box like command in c++. Unlike MessageBox that can be just invoked, InputBox() needs to be written. In fact, I have done so. The following article describes how to implement such InputBox as part of a small Static Library that can be used, with no Resources, from any Win32 c++ program. Source code at Github. It can be used as follow:
LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");
For example:
LPWSTR result = SG_InputBox::GetString(
L"Code Project Demo",
L"What is your name");
try this:
InputBox in c++ vs2010
#include "stdafx.h"
#using <system.windows.forms.dll>
#using <Microsoft.VisualBasic.dll>
using namespace System;
int main(array<System::String ^> ^args)
{
Microsoft::VisualBasic::Interaction::InputBox(L"Hello", L"Title", L"DefResp", 500, 500);
return 0;
}

CRichEditCtrl::GetSelText() is not working right

MFC File: winctrl4.cpp
(C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc)
CString CRichEditCtrl::GetSelText() const
{
ASSERT(::IsWindow(m_hWnd));
CHARRANGE cr;
cr.cpMin = cr.cpMax = 0;
::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
CStringA strText;
LPSTR lpsz=strText.GetBufferSetLength((cr.cpMax - cr.cpMin + 1)*2);
lpsz[0] = NULL;
::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpsz);
strText.ReleaseBuffer();
return CString(strText);
}
I am having a weird problem, when I call this it only returns the first character of the selected string. cr is correctly being set but after ::SendMessage(m_hWnd, EM_GETSELTEXT,... the whole string is not present.
I saw similar behavior in my custom code due to WCHAR issues (two-byte character containing a zero in one byte) when CHAR was expected. But this is part of MFC/Win32! Is it possible my .rc file sets something wrong? Is there a Create style relating to this? Or since we create a CFont for the control in question, could that screw it up?
This is not the correct MFC source code, have you edited it? Using CStringA and LPSTR is quite inappropriate, the real code uses CString and LPTSTR so that Unicode is correctly handled. Yes, as posted the code would only return one character.
Seeing the version helped. The bug is described in this feedback article. If you can't reasonably upgrade to VS2008 SP1, you could derive your own class from CRichEditCtrl and replace the function. For example:
CString CRichEditCtrlFix::GetSelText() const
{
ASSERT(::IsWindow(m_hWnd));
CHARRANGE cr;
cr.cpMin = cr.cpMax = 0;
::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
CString strText;
LPTSTR lpsz=strText.GetBufferSetLength((cr.cpMax - cr.cpMin + 1) * 2);
lpsz[0] = NULL;
::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpsz);
strText.ReleaseBuffer();
return CString(strText);
}
To get a wide char string you have to use the EM_GETTEXTEX message. CRichEditCtrl source does not contain a method which utilizes such message.
Here is a correct implementation of GetSelText() which actually does return Unicode characters:
CString CRichEditCtrlFix::GetSelText() const
{
ASSERT(::IsWindow(m_hWnd));
CHARRANGE cr;
cr.cpMin = cr.cpMax = 0;
::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
CString strText;
int sz = (cr.cpMax - cr.cpMin + 1) * sizeof(tchar);
LPTSTR lpsz = strText.GetBufferSetLength(sz);
lpsz[0] = NULL;
GETTEXTEX gte;
memset( &gte, 0, sizeof(GETTEXTEX) );
gte.cb = sz;
gte.flags = GT_SELECTION;
if( sizeof(tchar) == 2 ) gte.codepage = 1200;
::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)&gte, (LPARAM)lpsz);
strText.ReleaseBuffer();
return CString(strText);
}
1200 here means UTF-16LE