I want to copy, paste and cut content in my CEdit from my Clipboard - user-interface

This is the event handlers i implemented to the copy, paste and Cut buttons in my MFCRibbonBar:
in the MyRibbonView.cpp:
void CMyRibbonView::OnEditCopy()
{
CWnd *wnd = GetFocus();
if (wnd == pEdit)
pEdit->Copy();
if (!OpenClipboard())
{
AfxMessageBox(_T("Cannot open the Clipboard"));
return;
}
if (!EmptyClipboard())
{
AfxMessageBox(_T("Cannot empty the Clipboard"));
return;
}
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64);
strcpy_s((char*)hGlob, 64, "Current selection\r\n");
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
CString msg;
msg.Format(_T("Unable to set Clipboard data, error: %d"), GetLastError());
AfxMessageBox(msg);
CloseClipboard();
GlobalFree(hGlob);
return;
}
CloseClipboard();
}
void CMyRibbonView::OnEditPaste()
{
if (OpenClipboard())
{
HANDLE hClipboardData = GetClipboardData(CF_TEXT);
char *pchData = (char*)GlobalLock(hClipboardData);
CString strFromClipboard;
strFromClipboard = pchData;
pEdit->SetWindowText(strFromClipboard);
GlobalUnlock(hClipboardData);
CloseClipboard();
}
}
void CMyRibbonView::OnEditCut()
{
OnEditCopy();
pEdit->SetWindowText(L" ");
}
There is no errors, it's just not working. I tested it by adding the messages to check if it's actually the data or not but they're not popping up.

You need to GlobalLock your hGlob memory before copying your character string into it (this operation converts it into a usable pointer for your process - see here), and then call GlobalUnlock after you've done that (so that the clipboard can access hGlob):
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64); // Maybe also need GMEM_MOVEABLE here instead?
char* cCopy = (char*)GlobalLock(hGlob);
strcpy_s(cGlob, 64, "Current selection\r\n");
GlobalUnlock(hGlob);
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
//...
And you'll need a similar arrangement for the paste operation.

Related

How to "refresh" TListBox?

I'm creating an app which shows bill numbers, like the one you see at Mcdonald's. A POS system send bill numbers to my app and the numbers are showed in a TListBox called "ListBoxPrep". Then, when the POS system sends my app the number of a bill to be removed, my app gets rid of it from "ListBoxPrep" and add it to "ListBoxReady". Every communication between the POS and my app is done via TCP connection and I have no problem with it.
The problem I'm facing is that I still see the number remain in "ListBoxPrep" even after deleting it by "pItem->Free();". "pItem" is a pointer of TListBoxItem. I want the numbers disappear as soon as my app receives the "delete signal" from the POS and especially without user's interation such as clicking the panel etc. I think of using TTimer, but I have no idea how to make "ListBoxPrep" refresh by itself. Do you have any idea to do that? Any suggestion would be appreciated. I'm using RAD Studio 10.4.
After my app received the "delete signal" from the POS, I still see the numbers at right side. They are supposed to disappear.
As soon as I click the "ListBoxPrep", the numbers disappear.
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if(sentDataFromPOS .IsEmpty())
{
ShowMessage("Data sent from POS is empty!");
return;
}
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(sentDataFromPOS);
// 2. Add the order number to the "Ready list"
addNumberToReady(sentDataFromPOS);
// 3. Remove the order from the "Prep list"
ListBoxPrep->BeginUpdate();
TListBoxItem* pItem = ListBoxPrep->ItemByIndex(indexOrderToRemove);
pItem->Free(); // HERE I have a problem
// test: To refresh the screen
LayoutLeft->Visible = false;
LayoutLeft->Visible = true;
/*
ListBoxPrep->Enabled = false;
ListBoxPrep->Visible = false;
ListBoxPrep->Enabled = true;
ListBoxPrep->Visible = true;
ListBoxPrep->Repaint();
*/
ListBoxPrep->EndUpdate();
}
TIdTCPServer is a multi-threaded component. Its OnExecute event is called in the context of a worker thread. As such, it MUST synchronize with the main UI thread when accessing UI controls (that goes for ShowMessage() too, BTW). You can use the RTL's TThread::Synchronize() (synchronous) or TThread::Queue() (asynchronous) method for that.
Also, you should not be Free()'ing the TListBoxItem objects directly. You have the index of the desired item, you can use ListBoxPrep->Items->Delete() instead.
If you are using one of the clang-based compilers, try something more like this:
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(nullptr,
[](){ ShowMessage("Data sent from POS is empty!"); }
);
return;
}
TThread::Queue(nullptr, // or Synchronize(), your choice...
[=, this](){ this->orderIsReady(sentDataFromPOS); }
);
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
If, on the other hand, you are using the "classic" Borland compiler, then try this instead:
struct orderHelper
{
String orderNumber;
orderHelper(const String &orderNumber)
: orderNumber(orderNumber)
{
}
void __fastcall orderIsReady()
{
Form1->orderIsReady(orderNumber);
}
};
void __fastcall TForm1::orderIsEmpty()
{
ShowMessage("Data sent from POS is empty!");
}
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(NULL, &orderIsEmpty);
return;
}
orderHelper helper(sentDataFromPOS);
TThread::Synchronize(NULL, &(helper.orderIsReady));
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
Or this:
struct orderHelper
{
String orderNumber;
orderHelper(const String &orderNumber)
: orderNumber(orderNumber)
{
}
void __fastcall orderIsReady()
{
try {
Form1->orderIsReady(orderNumber);
} __finally {
delete this;
}
}
};
void __fastcall TForm1::orderIsEmpty()
{
ShowMessage("Data sent from POS is empty!");
}
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(NULL, &orderIsEmpty);
return;
}
orderHelper *helper = new orderHelper(sentDataFromPOS);
TThread::Queue(NULL, &(helper->orderIsReady));
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
I modified some code in IdTCPServerExecute to remove a few compile errors. Here is the code which has worked well. Thank you again, Remy Lebeau !
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPos = AContext->Connection->Socket->ReadLn();
// test
//sentDataFromPos = "";
if(sentDataFromPos.IsEmpty())
{
TThread::Synchronize(nullptr,
[=](){ ShowMessage("Data sent from POS is empty!"); }
);
return;
}
TThread::Synchronize(nullptr,
// Queue doesn't make the numbers disappear. It doesn't display them at right side either .
[&, this]()
{
this->orderIsReady(sentDataFromPos);
}
);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add an order of the same order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if(indexOrderToRemove != -1)
{
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
}

MFC: how to differentiate "Save" vs "Save As"?

In my previous question (MFC: how to change default file name for CFileDialog?), I overload DoSave function to supply a file name suggestion. Within this function is there way to differentiate "Save" vs "Save As"? Because I should only pop out dialog window if it is "Save As".
BOOL CMyDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
{
if (IsSaveAS() || m_saved_file_name.IsEmpty())
{
CString file_name = some_suggested_file_name;
CFileDialog file_dialog(false, ..., file_name, ...);
if (file_dialog.DoModal() == IDOK)
{
m_saved_file_name = file_dialog.GetPathName();
}
}
OnSaveDocument(m_saved_file_name);
return TRUE;
}
The dialog should be popped when lpszPathName == NULL || *lpszPathName == '\0'.
This covers the case where DoSave is called from OnFileSaveAs:
void CDocument::OnFileSaveAs()
{
if(!DoSave(NULL))
TRACE(traceAppMsg, 0, "Warning: File save-as failed.\n");
}
And also the case where the associated file is read-only and cannot be written to.
BOOL CDocument::DoFileSave()
{
DWORD dwAttrib = GetFileAttributes(m_strPathName);
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
{
// we do not have read-write access or the file does not (now) exist
if (!DoSave(NULL))
{
TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n");
return FALSE;
}
}
else
{
if (!DoSave(m_strPathName))
{
TRACE(traceAppMsg, 0, "Warning: File save failed.\n");
return FALSE;
}
}
return TRUE;
}
It also matches the logic of the builtin DoSave.
BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
// Save the document data to a file
// lpszPathName = path name where to save document file
// if lpszPathName is NULL then the user will be prompted (SaveAs)
// note: lpszPathName can be different than 'm_strPathName'
// if 'bReplace' is TRUE will change file name if successful (SaveAs)
// if 'bReplace' is FALSE will not change path name (SaveCopyAs)
{
CString newName = lpszPathName;
if (newName.IsEmpty())
{
// ...
if (!AfxGetApp()->DoPromptFileName(newName,
// ...

wglCreateContext fails with error code 6 (Invalid Handle)

I'm trying to create a wgl context according to the tutorial at https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL). For whatever reason, wglCreateContext returns null, and GetLastError returns 6, or Invalid Handle. I have used the tutorial before, and it worked just fine.
I'm trying to create a dummy context to a hidden window so that I can create another context for the user window. What's going on?
The Windows API is referred through the winAPI identifier, and wgl is a global struct containing function pointers to OpenGL.
struct WglContext
{
winAPI.HDC hdc;
winAPI.HGLRC handle;
}
__gshared Win32GL wgl;
///WGL-specific global data.
struct Win32GL
{
import oswald : OsWindow, WindowConfig, WindowError;
OsWindow helperWindow;
winAPI.HINSTANCE instance;
PFN_wglCreateContext createContext;
PFN_wglDeleteContext deleteContext;
PFN_wglGetProcAddress getProcAddress;
PFN_wglMakeCurrent makeCurrent;
PFN_wglCreateContextAttribsARB createContextAttribsARB;
PFN_wglGetExtensionStringARB getExtensionStringARB;
PFN_wglGetExtensionStringEXT getExtensionStringEXT;
bool extensionsAreLoaded;
static void initialize()
{
if (wgl.instance !is null)
return; //The library has already been initialized
WindowConfig cfg;
cfg.title = "viewport_gl_helper";
cfg.hidden = true;
auto windowError = OsWindow.createNew(cfg, &wgl.helperWindow);
if (windowError != WindowError.NoError)
{
import std.conv : to;
assert(false, "Failed to create helper window: " ~ windowError.to!string);
}
wgl.instance = winAPI.LoadLibrary("opengl32.dll");
if (wgl.instance is null)
assert(false, "Viweport failed to load opengl32.dll");
wgl.bind(cast(void**)&wgl.createContext, "wglCreateContext\0");
wgl.bind(cast(void**)&wgl.deleteContext, "wglDeleteContext\0");
wgl.bind(cast(void**)&wgl.getProcAddress, "wglGetProcAddress\0");
wgl.bind(cast(void**)&wgl.makeCurrent, "wglMakeCurrent\0");
}
static void terminate()
{
if (!wgl.instance)
return;
winAPI.FreeLibrary(wgl.instance);
wgl.helperWindow.destroy();
}
void bind(void** func, in string name)
{
*func = winAPI.GetProcAddress(this.instance, name.ptr);
}
}
struct WglContext
{
winAPI.HDC hdc;
winAPI.HGLRC handle;
}
WglContext wglCreateTmpContext()
{
assert(wgl.instance);
winAPI.PIXELFORMATDESCRIPTOR pfd;
pfd.nSize = winAPI.PIXELFORMATDESCRIPTOR.sizeof;
pfd.nVersion = 1;
pfd.dwFlags = winAPI.PFD_DRAW_TO_WINDOW | winAPI.PFD_SUPPORT_OPENGL | winAPI.PFD_DOUBLEBUFFER;
pfd.iPixelType = winAPI.PFD_TYPE_RGBA;
pfd.cColorBits = 24;
auto hdc = winAPI.GetDC(wgl.helperWindow.platformData.handle);
const pixelFormat = winAPI.ChoosePixelFormat(hdc, &pfd);
if (winAPI.SetPixelFormat(hdc, pixelFormat, &pfd) == winAPI.FALSE)
assert(false, "Failed to set pixel format for temp context");
writeln(hdc);
writeln(pixelFormat);
winAPI.HGLRC context = wgl.createContext(hdc);
if (context is null)
{
import std.conv: to;
assert(false, "Failed to create temp context: Error Code " ~ winAPI.GetLastError().to!string);
}
if (wgl.makeCurrent(hdc, context) == winAPI.FALSE)
{
wgl.deleteContext(context);
assert(false, "Failed to make temp context current");
}
return WglContext(hdc, context);
}
void main()
{
wgl.initialize(); //Fetches function pointers, and loads opengl32.dll
auto context = wglCreateTmpContext();
wglDeleteContext(context); //Delegates to wgl.deleteContext
wgl.terminate(); //Unloads opengl32.dll and nulls function pointers
}
I know nothing on that winAPI you use. Anyhow, I'm sure of:
You must:
Create a window and get its HWND handle (Windows definition of
HWND, see below). Tipically the window uses WS_CLIPCHILDREN | WS_CLIPSIBLINGS
style; but try also the WS_OVERLAPPEDWINDOW as in the link you
posted.
Verify you get a valid HWND, and a valid HDC from it.
HWND and HDC are defined as *void. I would not trust on auto.

alBufferData() sets AL_INVALID_OPERATION when using buffer ID obtained from alSourceUnqueueBuffers()

I am trying to stream audio data from disk using OpenAL's buffer queueing mechanism. I load and enqueue 4 buffers, start the source playing, and check in a regular intervals to refresh the queue. Everything looks like it's going splendidly, up until the first time I try to load data into a recycled buffer I got from alSourceUnqueueBuffers(). In this situation, alBufferData() always sets AL_INVALID_OPERATION, which according to the official v1.1 spec, it doesn't seem like it should be able to do.
I have searched extensively on Google and StackOverflow, and can't seem to find any reason why this would happen. The closest thing I found was someone with a possibly-related issue in an archived forum post, but details are few and responses are null. There was also this SO question with slightly different circumstances, but the only answer's suggestion does not help.
Possibly helpful: I know my context and device are configured correctly, because loading small wav files completely into a single buffer and playing them works fine. Through experimentation, I've also found that queueing 2 buffers, starting the source playing, and immediately loading and enqueueing the other two buffers throws no errors; it's only when I've unqueued a processed buffer that I run into trouble.
The relevant code:
static constexpr int MAX_BUFFER_COUNT = 4;
#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }
bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
ALenum tErrCode = alGetError();
if(tErrCode != 0)
{
auto tMsg = alGetString(tErrCode);
Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
<< "\tAL call " << pfunc << " failed." << end;
return true;
}
return false;
}
void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
static int called = 0;
++called;
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
if(tState == AL_STATIC)
{
Stop();
// alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
}
ALuint tBufId = AL_NONE;
int tQueuedBuffers = QueuedUpBuffers();
int tReady = ProcessedBuffers();
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
void* tConverted = convert(pData, pFrames);
// the fifth time through, we get AL_INVALID_OPERATION, and call abort()
alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));
alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
if(mBitdepth == BITDEPTH_8)
{
delete (uint8_t*)tConverted;
}
else // if(mBitdepth == BITDEPTH_16)
{
delete (uint16_t*)tConverted;
}
}
void SoundyOutport::PlayBufferedStream()
{
if(!StreamingMode() || !QueuedUpBuffers())
{
Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
return;
}
alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
alCall(alSourcePlay(mSourceId));
}
int SoundyOutport::QueuedUpBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
return tCount;
}
int SoundyOutport::ProcessedBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
return tCount;
}
void SoundyOutport::Stop()
{
if(Playing())
{
alCall(alSourceStop(mSourceId));
}
int tBuffers;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
if(tBuffers)
{
ALuint tDummy[tBuffers];
alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
}
alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}
bool SoundyOutport::Playing()
{
ALint tPlaying;
alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
return tPlaying == AL_PLAYING;
}
bool SoundyOutport::StreamingMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STREAMING;
}
bool SoundyOutport::StaticMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STATIC;
}
And here's an annotated screen cap of what I see in my debugger when I hit the error:
I've tried a bunch of little tweaks and variations, and the result is always the same. I've wasted too many days trying to fix this. Please help :)
This error occurs when you trying to fill buffer with data, when the buffer is still queued to the source.
Also this code is wrong.
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
You can fill buffer with data only if it unqueued from source. But your first if block gets tBufId that queued to the source. Rewrite code like so
if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}

how to host html control in my window using a buffer which contents a html file

I am developing a visual c++ applicatio(x64). what actually i am trying to do is that suppose we have a html file in window explorer(i mean file with file extension ".html"). when we single click on it we get its preview on preview pane(so we don't need to open this file we can see the file in preview pane on a single click to a file).
I have developed a similar type of application but in my case when i click on the "html file" i just get the code of that html file in preview pane(the code which you can see if you open that html file in notepad). which is not expected to happen but I want to have the preview of that "html file" not the code of that html file.
I think i need to host some browser control which will transform my html code in preview pane to the display of html file(If i am correct ???) How to do that ??
Here is my code for that-
IHTMLDocument2 * pDoc=NULL;
HRESULT hr2 = CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (LPVOID *) &pDoc);
if (pDoc)
{
IPersistStreamInit *pPersist = NULL;
pDoc->QueryInterface(IID_IPersistStreamInit,(LPVOID *) &pPersist);
if (pPersist)
{
IMarkupServices *pMS = NULL;
pPersist->InitNew();
pPersist->Release();
pDoc->QueryInterface(IID_IMarkupServices,(LPVOID *) &pMS);
if (pMS)
{
IMarkupContainer *pMC = NULL;
IMarkupPointer *pMkStart = NULL;
IMarkupPointer *pMkFinish = NULL;
pMS->CreateMarkupPointer(&pMkStart);
pMS->CreateMarkupPointer(&pMkFinish);
pMS->ParseString(HtmlFileContents,0,&pMC,pMkStart,pMkFinish);
//this HtmlFileContents is actually a buffer of olechar type which contains the code of html file (the code which you see when you open the html file in notepad)
if (pMC)
{
IHTMLDocument2 *pNewDoc = NULL;
pMC->QueryInterface(IID_IHTMLDocument,(LPVOID *) &pNewDoc);
if (pNewDoc)
{
IHTMLElement *pBody;
pNewDoc->get_body(&pBody);
if (pBody)
{
BSTR strText;
pBody->get_innerText(&strText);
hr = instance->CreatePreviewWindowForHtml(strText); // this function is responsible for displaying the html file in window. you can see its definition below after this code.
SysFreeString(strText);
pBody->Release();
}
pNewDoc->Release();
}
pMC->Release();
}
if (pMkStart)
pMkStart->Release();
if (pMkFinish)
pMkFinish->Release();
pMS->Release();
pMS->Release();
}
}
pDoc->Release();
}
return true;
and the function defintion of CreatePreviewWindowForHtml() is as below-
CreatePreviewWindowForHtml(PCWSTR pszRtfWide)
{
assert(m_hwndPreview3 == NULL);
HRESULT hr = E_FAIL;
if (m_hwndPreview3 == NULL)
{
HRESULT hr5 = HRESULT_FROM_WIN32(GetLastError());
}
if (m_hinstEditLibrary == NULL)
{
// MSFTEDIT_CLASS used below comes from this binary
m_hinstEditLibrary = LoadLibraryW(L"msftedit.dll");
}
if (m_hinstEditLibrary == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
// Create the preview window
HWND pr = m_hwndPreview3 = CreateWindowExW(0, MSFTEDIT_CLASS, NULL,
WS_CHILD | WS_VSCROLL | WS_VISIBLE | ES_MULTILINE | ES_READONLY, // Always create read-only
m_rcParent.left, m_rcParent.top, RECTWIDTH(m_rcParent), RECTHEIGHT(m_rcParent),
m_hwndPreview, NULL, NULL,NULL);
if (m_hwndPreview3 == NULL)
{
MessageBoxA(m_hwndPreview3,strerror(hr),"BTN WND2", MB_ICONINFORMATION);
}
else
{
int const cchRtf = 1 + wcslen(pszRtfWide);
PSTR pszRtf = (PSTR)CoTaskMemAlloc(cchRtf);
if (pszRtf)
{
WideCharToMultiByte(CP_ACP, 0, pszRtfWide, cchRtf, pszRtf, cchRtf, NULL, NULL);
SETTEXTEX st = { ST_DEFAULT, CP_ACP };
LRESULT hr4=SendMessage(m_hwndPreview3, EM_SETTEXTEX, (WPARAM) &st, (LPARAM) pszRtfWide);
if (SUCCEEDED(hr4))
{
hr = AdjustDialogPositionAndSize();
SendMessage(m_hwndPreview3, EM_SETTEXTEX, (WPARAM) &st, (LPARAM) pszRtfWide);
}
CoTaskMemFree(pszRtf);
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
return hr;
}
Any ideas why i have the html code in my window ?? What to do in the code in order to get the preview of html file in my window rather then html code ??
Please tell me if any doubts in understanding me ??
You have the html code in your window because you choose a richedit as the text renderer and your text did not start with "{\rtf".
If you want html display, you need an html renderer instead of a rich edit, something like MFC's CHtmlEditCtrl. If you don't want to use MFC you can write an ActiveX container to host the webbrowser control directly.

Resources