I am working on a sample in this I am creating a EMF file with some text in it.
To add a text I am using the API ExtTextOutW() with ETO_IGNORELANGUAGE option.
Return value of this API is TRUE. But when I open the EMF file the text is not present.
Then I saw the records. There is no entey for the ExtTextOutW.
Bellw is the code.
HDC hDC = GetDC(hWnd);
RECT Rect = {0, 0, 21590, 27940};
//Create the EMF file DC
HDC hEMFDC = ::CreateEnhMetaFile(hDC, L"c:\\del\\1.emf", &Rect, L"Test");
if (NULL != hEMFDC)
{
RECT Rect = {0, 0, 300, 155};
HBRUSH hb = CreateSolidBrush(0X00FFFF00);
FillRect(hEMFDC, &Rect, hb);
DeleteObject(hb);
int dx[12] = {25,25,25,25,25,25, 25,25,25,25,25,25};
WCHAR wcsBuffer[] = L"Text Message";
ExtTextOutW(hEMFDC, 10, 10, ETO_IGNORELANGUAGE, NULL, wcsBuffer, wcslen(wcsBuffer), dx);
HENHMETAFILE hmf = CloseEnhMetaFile(hEMFDC);
DeleteEnhMetaFile(hmf);
hEMFDC = NULL;
}
ReleaseDC(hWnd, hDC);
Please let me know any thing I am doing wrong in the above code.
Did you read the documentation for ExtTextOut[W] (MSDN), especially the part for the flags like ETO_IGNORELANGUAGE:
Reserved for system use. If an application sets this flag, it loses
international scripting support and in some cases it may display no
text at all.
Just try it without this flag.
Related
I'd like to add controls to a property sheet without resource script, rather using pure code.
The reason for this I'd like to create a property sheet(mimicking C#'s property grid), calling C routines/WINAPI, from another language, binary-compatible to C; but I'd like to define everything with code, without need of a resource script. Is this possible or the way to go is write my own property-sheet-like, with underlying CreateWindow*() calls? (different approaches to do this are welcome, I'm new to WINAPI) which I suppose property sheet use behind the scenes
Found the solution! I found this post from Raymond Chen where he shows how do that.
the main code goes like this:
BOOL FakeMessageBox(HWND hwnd, LPCWSTR pszMessage, LPCWSTR pszTitle)
{
BOOL fSuccess = FALSE;
HDC hdc = GetDC(NULL);
if (hdc) {
NONCLIENTMETRICSW ncm = { sizeof(ncm) };
if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
DialogTemplate tmp;
// Write out the extended dialog template header
tmp.Write<WORD>(1); // dialog version
tmp.Write<WORD>(0xFFFF); // extended dialog template
tmp.Write<DWORD>(0); // help ID
tmp.Write<DWORD>(0); // extended style
tmp.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
tmp.Write<WORD>(2); // number of controls
tmp.Write<WORD>(32); // X
tmp.Write<WORD>(32); // Y
tmp.Write<WORD>(200); // width
tmp.Write<WORD>(80); // height
tmp.WriteString(L""); // no menu
tmp.WriteString(L""); // default dialog class
tmp.WriteString(pszTitle); // title
// Next comes the font description.
// See text for discussion of fancy formula.
if (ncm.lfMessageFont.lfHeight < 0) {
ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight,
72, GetDeviceCaps(hdc, LOGPIXELSY));
}
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
tmp.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
tmp.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
tmp.WriteString(ncm.lfMessageFont.lfFaceName);
// Then come the two controls. First is the static text.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE); // style
tmp.Write<WORD>(7); // x
tmp.Write<WORD>(7); // y
tmp.Write<WORD>(200-14); // width
tmp.Write<WORD>(80-7-14-7); // height
tmp.Write<DWORD>(-1); // control ID
tmp.Write<DWORD>(0x0082FFFF); // static
tmp.WriteString(pszMessage); // text
tmp.Write<WORD>(0); // no extra data
// Second control is the OK button.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE |
WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
tmp.Write<WORD>(75); // x
tmp.Write<WORD>(80-7-14); // y
tmp.Write<WORD>(50); // width
tmp.Write<WORD>(14); // height
tmp.Write<DWORD>(IDCANCEL); // control ID
tmp.Write<DWORD>(0x0080FFFF); // static
tmp.WriteString(L"OK"); // text
tmp.Write<WORD>(0); // no extra data
// Template is ready - go display it.
fSuccess = DialogBoxIndirect(g_hinst, tmp.Template(),
hwnd, DlgProc) >= 0;
}
ReleaseDC(NULL, hdc); // fixed 11 May
}
return fSuccess;
}
I am doing a D2D/D3D interoperability program. After getting ID3D11Texture2D from the outside, it is rendered in a designated area. I tried CreateDxgiSurfaceRenderTarget but no effect
code below, The code runs "normally", there are no errors and debugging information is displayed, But the interface shows a black screen. If you ignore the param texture, changing to only _back_render_target->FillRectange is effective
HRESULT CGraphRender::DrawTexture(ID3D11Texture2D* texture, const RECT& dst_rect)
{
float dpi = GetDpiFromD2DFactory(_d2d_factory);
CComPtr<ID3D11Texture2D> temp_texture2d;
CComPtr<ID2D1RenderTarget> temp_render_target;
CComPtr<ID2D1Bitmap> temp_bitmap;
D3D11_TEXTURE2D_DESC desc = { 0 };
texture->GetDesc(&desc);
CD3D11_TEXTURE2D_DESC capture_texture_desc(DXGI_FORMAT_B8G8R8A8_UNORM, desc.Width, desc.Height, 1, 1, D3D11_BIND_RENDER_TARGET);
HRESULT hr = _d3d_device->CreateTexture2D(&capture_texture_desc, nullptr, &temp_texture2d);
RETURN_ON_FAIL(hr);
CComPtr<IDXGISurface> dxgi_capture;
hr = temp_texture2d->QueryInterface(IID_PPV_ARGS(&dxgi_capture));
RETURN_ON_FAIL(hr);
D2D1_RENDER_TARGET_PROPERTIES rt_props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), dpi, dpi);
hr = _d2d_factory->CreateDxgiSurfaceRenderTarget(dxgi_capture, rt_props, &temp_render_target);
RETURN_ON_FAIL(hr);
D2D1_BITMAP_PROPERTIES bmp_prop = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), dpi, dpi);
hr = temp_render_target->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), bmp_prop, &temp_bitmap);
RETURN_ON_FAIL(hr);
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
immediate_context->CopyResource(temp_texture2d, texture);
D2D1_POINT_2U src_point = D2D1::Point2U();
D2D1_RECT_U src_rect = D2D1::RectU(0, 0, desc.Width, desc.Height);
hr = temp_bitmap->CopyFromRenderTarget(&src_point, temp_render_target, &src_rect);
RETURN_ON_FAIL(hr);
D2D1_RECT_F d2d1_rect = { (float)dst_rect.left, (float)dst_rect.top, (float)dst_rect.right, (float)dst_rect.bottom};
_back_render_target->DrawBitmap(temp_bitmap, d2d1_rect);
return S_OK;
}
Refer to DirectXTK, DirectXTK's SpritBatch code has a brief look. It is necessary to introduce a bunch of context settings. I don’t understand the relationship yet. I don’t know. Does the existing code have any influence, such as setting TargetView, ViewPort or even Shader.
Is there a relatively simple and effective method, as simple and violent as ID2D1RenderTarget's DrawBitmap?
Latest update:
Well, I found a culprit of some sort. I changed the control to RichEdit20W from the 50W and it displays the Hangul (Korean) now. I did not have to change any other code except for the init, added AfxInitRichEdit2(), and commented out the LoadLibrary(L"MsftEdit.dll"). The AfxInitRichEdit5() is not available for VS2010. All things being equal and Rich Edit 4.1 has been available since VS2005, it should have worked. I can't upgrade to VS2015 right now so I'm stuck. I'm going to offer a bounty though for anybody who can make the Hangul work with 50W and VS2010.
I have a dilemma that I can't seem to solve.
I have an mfc Unicode app that uses CEdit and CRicheditCtrl.
The Rich Edit is 50W loaded from MsftEdit.dll and verified with Spy++
that the class name is RICHEDIT50W.
My problem:
I'm using the same Font Courier New for both the CEdit and CRichEditCtrl.
As a test, I used some of the Hangul symbols to see the output for both
controls.
CEdit outputs ᄀᄁᄂᄃᄄᄅᄆᄇᄈ
while the
CRichEditCtrl outputs a box for each character, like there is no glyph for it.
If they are using the same font, shouldn't I see the same output characters?
I think that font-binding is not a problem, both have the same default font.
Can anybody solve this riddle ?
Thanks in advance!
Note that this happens with some other character sets as well, not just Hangul
Update
I looked at the VS2010 WordPad example, it uses CRichEditView but it
provides wrappers to access the embedded CRichEditCtrl.
I thought I could glean some info but I can't see how they are doing the
Rich Edit control calls.
This is how I am generating the font's for both controls.
But, I'm showing specifically the Rich Edit part.
The doc's say that Font binding should handle switching from the default
font to the font at the current insertion point.
I am doing insertion mostly at the end using
ctrl.SetSel(-1,-1);
ctrl.ReplaceSel( str );
And, according to the doc's, this should change to the correct font as needed,
if other than the default font.
In the WordPad sample, if I paste in the Hangul text, the font switches to
Gulim.
Here is my code:
LOGFONT lf;
int pitch = 10;
memset(&lf, 0, sizeof(LOGFONT));
HDC hdc = ::GetDC(NULL);
lf.lfHeight = -MulDiv( pitch, GetDeviceCaps(hdc, LOGPIXELSY), 72);
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
lstrcpy(lf.lfFaceName, _T("Courier New") );
lf.lfWeight = FW_NORMAL;
lf.lfCharSet = ANSI_CHARSET; // English, but use DEFAULT_CHARSET if not
lf.lfQuality = DEFAULT_QUALITY;
if ( !m_Font.CreateFontIndirect(&lf) )
{ // Ours didn't work, create a system default fixed font
// ( Ignore, example for post only. Never gets called though )
//memset(&lf, 0, sizeof(LOGFONT));
//::GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT), &lf);
//m_Font.CreateFontIndirect(&lf);
}
// Save the generated Font LOGFONT
m_lf = lf;
// Set the default Font CHARFORMAT2
memset( &m_cfDefaultFont, 0, sizeof(m_cfDefaultFont) );
m_cfDefaultFont.cbSize = sizeof(m_cfDefaultFont);
m_cfDefaultFont.dwMask = CFM_CHARSET | CFM_FACE | CFM_WEIGHT ;
m_cfDefaultFont.bCharSet = m_lf.lfCharSet;
lstrcpy( m_cfDefaultFont.szFaceName, m_lf.lfFaceName );
m_cfDefaultFont.wWeight = m_lf.lfWeight;
// Finally set the font in the controls
m_RichEdit.SetFont( &m_Font );
// Same effect as m_RichEdit.SetFont()
//m_RichEdit.SendMessage(EM_SETCHARFORMAT, SCF_ALL, &m_cfDefaultFont);
// This displays nothing but 'box' glyphs
m_RichEdit.SetWindowTextW(_T("ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ"));
Update 2
This is how I initialize the Rich Edit in the app.
And shows the usage of 50W in a dialog control.
-- winapp.cpp
BOOL CMyApp::InitInstance()
{
// ...... //
CString strRichEdit = _T("Msftedit.dll");
m_hMsfteditDll = AfxLoadLibrary( strRichEdit );
if ( m_hMsfteditDll == NULL )
{
CString str;
str.Format(_T("Error: Cannot find Rich Edit component %s"), strRichEdit );
AfxMessageBox(str);
return FALSE;
}
return TRUE;
}
int CRegexFormatApp::ExitInstance()
{
if ( m_hMsfteditDll != NULL )
AfxFreeLibrary( m_hMsfteditDll );
return CWinAppEx::ExitInstance();
}
// =========================
-- .rc
CONTROL "",IDC_RICH_EDIT,"RICHEDIT50W",WS_VSCROLL | WS_HSCROLL,40,15,148,28
-- Dlg.h
CRichEditCtrl m_RichEdit;
-- Dlg.cpp
void Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICH_EDIT, m_RichEdit); // Use .rc setting to Create/Attach
}
BOOL Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CreateAndSetRichFont(); // Code shown above
m_RichEdit.SetWindowTextW( ... );
}
This code should work in a Unicode project:
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
LoadLibrary(L"MsftEdit.dll");
...
}
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
static CRichEditCtrl redit;
CWnd *wnd = &redit;
wnd->Create(MSFTEDIT_CLASS, L"ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ",
WS_CHILD | WS_VISIBLE, CRect(0,0,300,300), this, 1001, 0);
...
//redit is not to be mixed up with controls created in dialog editor.
}
Edit ----------------
NONCLIENTMETRICS info = { sizeof(info) };
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
LOGFONT logfont = info.lfMessageFont;
//CClientDC has automatic cleanup, use it instead of GetDC
CClientDC dc(this);
logfont.lfHeight = -MulDiv(abs(logfont.lfHeight), dc.GetDeviceCaps(LOGPIXELSY), 76);
CFont font;
font.CreateFontIndirect(&logfont);
m_RichEdit.SetFont(&font);
m_RichEdit.SetWindowText(L"ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ");
m_RichEdit.SetSel(1, 1);
CString test = L"(Test, ελληνικά)";
//Test to make sure we can see Unicode text
AfxMessageBox(test);
m_RichEdit.ReplaceSel(test);
//optional:
//get default CHARFORMAT
CHARFORMAT2 charFormat;
//m_RichEdit.GetSelectionCharFormat(charFormat);
m_RichEdit.GetDefaultCharFormat(charFormat);
In a traditional Windows program that uses GDI for graphics, you would have to worry about only drawing the area of the window that needs to be redrawn; this is the "update rect" and is accessed either by PAINTSTRUCT.rcPaint or by a call to GetUpdateRect(). (This is also available as an HRGN through other means.)
Do I need to do the same thing with Direct2D? All the examples on MSDN just draw the entire client area indiscriminately and searching online hasn't turned up anything else.
Or in other words, would anything bad happen to parts outside the update rect if I only draw within the update rect, for instance either manually or with PushAxisAlignedClip() or PushLayer()?
Furthermore, the documentation for ID2D1HwndRenderTarget::Resize() says
After this method is called, the contents of the render target's back-buffer are not defined, even if the D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS option was specified when the render target was created.
Does this mean that whatever update region would be caused by resizing (such as shown by this picture from this page) is invalid and I should redraw the whole window (for instance, by calling InvalidateRect(NULL)) on a resize?
Thanks.
Yes. Use PushAxisAlignedClip with D2D1_ANTIALIAS_MODE_ALIASED.
Call ID2D1HwndRenderTarget::Resize when the window is resized. Do pay attention to the HRESULT it returns. It can return D2DERR_RECREATE_TARGET, but you may not know that it can also return D2DERR_DISPLAY_STATE_INVALID (which can also be returned by EndDraw, btw). And yes, call InvalidateRect(NULL) after that.
I also recommend using D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS because otherwise you'll run into nasty bugs on some stupid driver/hardware configurations and in other events. Don't ask me why -- it just doesn't behave well without this. You'll get bug reports that your whole rendering area just becomes filled with black. It took me months to figure out that all I had to do was to use that flag. I was never able to repro the problem locally.
No. You have to do near the same thing as normal with gdi. Instead of using a HBITMAP backbuffer, you have to use d2d bitmap. In wm_size, you resize and redraw your d2d bitmap, and in wm_paint instead of bitblt a hbitmap you have to use the render drawbitmap method. and render just the part from the paintstruct rect member (hope this help you) :
Global or class members :
ID2D1Factory* g_pD2DFactory = NULL;
ID2D1HwndRenderTarget* g_pRenderTarget = NULL;
ID2D1SolidColorBrush* g_pBlackBrush = NULL;
ID2D1SolidColorBrush* g_pWhiteBrush = NULL;
ID2D1BitmapRenderTarget* g_bitmapRenderTarget = NULL; //for d2d bitmap
The global or class static wndproc:
case WM_CREATE: {
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory))) {
throw;
}
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
HRESULT hr = g_pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(lpcs->cx, lpcs->cy)),
&g_pRenderTarget
);
if (FAILED(hr)) {
throw;
}
if (FAILED(g_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &g_pBlackBrush))) {
throw;
}
if (FAILED(g_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &g_pWhiteBrush))) {
throw;
}
break;
}
case WM_SIZE: {
if(FAILED(g_pRenderTarget->Resize(D2D1::SizeU(LOWORD(lParam), HIWORD(lParam))))) {
throw;
}
D2D_SAFE_RELEASE(g_bitmapRenderTarget)
g_pRenderTarget->CreateCompatibleRenderTarget(&g_bitmapRenderTarget);
g_bitmapRenderTarget->BeginDraw();
g_bitmapRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::AliceBlue));
g_bitmapRenderTarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(100,100), 50,50), g_pBlackBrush);
g_bitmapRenderTarget->EndDraw();
break;
}
case WM_PAINT: {
HDC hDc;
PAINTSTRUCT ps;
LPCRECT lpRect;
ID2D1Bitmap* bitmap;
D2D1_RECT_F d2d1Rect;
hDc = BeginPaint(hWnd, &ps);
lpRect = &ps.rcPaint;
d2d1Rect = D2D1::RectF(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
g_bitmapRenderTarget->GetBitmap(&bitmap);
g_pRenderTarget->BeginDraw();
g_pRenderTarget->DrawBitmap(
bitmap, d2d1Rect, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
d2d1Rect
);
g_pRenderTarget->EndDraw();
EndPaint(hWnd, &ps);
return 0;
}
Here is an example code which sends a mouse click (using xlib). For simplicity events are sent to the fullscreen window (root and window coordinates are the same) and window id is obtained using wmctrl.
Display *display = XOpenDisplay(NULL);
XWarpPointer(display, None, RootWindow(display, DefaultScreen(display)), 0, 0, 0, 0, 300, 200);
XEvent event;
memset(&event, 0x00, sizeof(event));
event.type = ButtonPress;
event.xbutton.button = button;
event.xbutton.same_screen = True;
event.xbutton.root = RootWindow(display, DefaultScreen(display));
event.xbutton.window = 81788929;
event.xbutton.subwindow = 0;
event.xbutton.x_root = 300;
event.xbutton.y_root = 200;
event.xbutton.x = 300;
event.xbutton.y = 200;
event.xbutton.state = 0;
XSendEvent(display, PointerWindow, True, ButtonPressMask, &event);
XFlush(display);
XCloseDisplay(display);
Above code works fine. I ported it to xcb:
Display *display = XOpenDisplay(NULL);
XWarpPointer(display, None, RootWindow(display, DefaultScreen(display)), 0, 0, 0, 0, 300, 200);
xcb_button_press_event_t event;
memset(&event, 0x00, sizeof(event));
event.event = 81788929;
event.same_screen = 1;
event.root = RootWindow(display, DefaultScreen(display));
event.root_x = 300;
event.root_y = 200;
event.event_x = 300;
event.event_y = 200;
event.child = 0;
event.state = 0;
xcb_connection_t *conn = XGetXCBConnection(display);
xcb_send_event(conn, false, 81788929, XCB_EVENT_MASK_BUTTON_PRESS, (char*)(&event));
xcb_flush(conn);
XCloseDisplay(display);
XCB code doesn't work: destination window doesn't get any event. What is wrong ?
Edit1
When I use following code for a connection:
xcb_connection_t *conn;
xcb_screen_t *screen;
conn = xcb_connect (NULL, NULL);
screen = xcb_setup_roots_iterator (xcb_get_setup (conn)).data;
and later:
event.root = screen->root;
it also doesn't work.
Nowhere in your code there are error checks. Anyway, I suspect that XGetXCBConnection(display); does not return you a valid Xcb connection. Why you may ask? Because for this to work Xlib must have been built as a wrapper around Xcb and the internal structures properly been set up.
I suggest you create the connection and open the display purely with Xcb and see if this solves the problem.