Login Page - Create Account

Support Board


Date/Time: Fri, 07 Mar 2025 00:55:57 +0000



DrawText (winapi) problem in sc.p_GDIFunction, possible bug.

View Count: 822

[2022-02-18 19:44:16]
User978306 - Posts: 4
Hi, Support.

Trying to create text output at MainPriceGraph, but can not..

Sample SierraChart study:

void  draw_text_function(HWND hwnd, HDC hdc, SCStudyInterfaceRef sc);

SCSFExport scsf_draw_text_test(SCStudyInterfaceRef sc)
{
  if (sc.SetDefaults)
  {
    sc.GraphName = "draw text test";

    sc.UpdateAlways = 1;
    sc.AutoLoop = 0;
    sc.GraphRegion = 0;
    sc.p_GDIFunction = draw_text_function;

    return;
  }
}

void draw_text_function(HWND hwnd, HDC hdc, SCStudyInterfaceRef sc)
{
  RECT rc;
  ::GetClientRect(hwnd, &rc);
  ::InflateRect(&rc, -300, -300);

  int old_mode = ::SetMapMode(hdc, MM_TEXT);

  TCHAR font_face[] = "Consolas";
  long font_height = -MulDiv(18, ::GetDeviceCaps(hdc, LOGPIXELSY), 72);

  HFONT font = ::CreateFontA(font_height, 0, 0, 0,
    FW_SEMIBOLD, 0, 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
    DEFAULT_QUALITY, FF_DONTCARE | DEFAULT_PITCH, font_face);

  if (font == nullptr)
    sc.AddMessageToLog("Create study font operatoin error!", 1);

  HGDIOBJ old_font = ::SelectObject(hdc, font);
  std::stringstream ss;
  ss.str("test output string");

  int old_bk_mode = ::SetBkMode(hdc, TRANSPARENT);
  ::SetTextColor(hdc, RGB(255, 0, 0));

  int result = ::DrawTextA(hdc, ss.str().c_str(),
    (int)ss.str().length(), &rc, DT_VCENTER | DT_CENTER | DT_SINGLELINE);

  HPEN pen = ::CreatePen(PS_SOLID, 1, RGB(204, 204, 204));
  ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
  HGDIOBJ old_pen = ::SelectObject(hdc, pen);

  Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);

  ::DeleteObject(font);
  ::DeleteObject(pen);
  
  ::SetBkMode(hdc, old_bk_mode);
  ::SelectObject(hdc, old_font);
  ::SelectObject(hdc, old_pen);
  ::SetMapMode(hdc, old_mode);

  ::DeleteObject(font);
  ::DeleteObject(pen);
}

First attachment contains screenshot of chart with applied study, can see empty rectangle only.
For check, I have created a template VS windows application project and placed inside WM_PAINT block absolutely same code from draw_text_function , have a correct output, can be found in second attachment.

Code:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
            RECT rc;
            GetClientRect(hWnd, &rc);
            InflateRect(&rc, -300, -300);

            WCHAR lpsz_face[] = L"Consolas";
            long font_height = -MulDiv(26, ::GetDeviceCaps(hdc, LOGPIXELSY), 72);

            HFONT font = ::CreateFontW(font_height, 0, 0, 0,
              FW_SEMIBOLD, 0, 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
              CLEARTYPE_NATURAL_QUALITY, FF_DONTCARE | DEFAULT_PITCH, lpsz_face);

            HGDIOBJ old_font = ::SelectObject(hdc, font);
        
            std::wstringstream ss;
            ss << L"sample text output";

            int old_bk_mode = ::SetBkMode(hdc, TRANSPARENT);
            ::SetTextColor(hdc, RGB(255, 0, 0));

            int result = ::DrawTextW(hdc, (LPWSTR)ss.str().c_str(), (int)ss.str().length(),
              &rc, DT_CENTER| DT_VCENTER | DT_SINGLELINE);

            HPEN pen = ::CreatePen(PS_SOLID, 1, RGB(204, 204, 204));
            ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
            ::SelectObject(hdc, pen);

            Rectangle(hdc, rc.left,rc.top,rc.right,rc.bottom);
            
            ::DeleteObject(font);
            ::DeleteObject(pen);

EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

imagefirst_attachment.png / V - Attached On 2022-02-18 19:38:28 UTC - Size: 14.29 KB - 179 views
imagesecond_attachment.png / V - Attached On 2022-02-18 19:40:57 UTC - Size: 32.57 KB - 183 views
[2022-02-20 11:46:09]
Sierra_Chart Engineering - Posts: 18672
We have looked into this. Refer to the code example below. Use ::TextOutW.

In the next release of Sierra Chart it will also solve a problem where an exception was occurring when unloading a study DLL which has a custom drawing function.

Also take note of the new placement for;
sc.p_GDIFunction = DrawToChart;

#include "sierrachart.h"

// SCDLLName("GDI Example")

// This file demonstrates the functionality to use the Windows Graphics Device
// Interface (GDI) with ACSIL to freely draw inside of the chart window

// Windows GDI documentation can be found here:
// http://msdn.microsoft.com/en-nz/library/windows/desktop/dd145203%28v=vs.85%29.aspx

/*==========================================================================*/
// Drawing function declaration
void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc);


/*==========================================================================*/
SCSFExport scsf_DrawToChartExample(SCStudyInterfaceRef sc)
{
  if (sc.SetDefaults)
  {
    // Set the configuration and defaults

    sc.GraphName = "Draw To Chart Example";

    sc.AutoLoop = 0;
    return;
  }


  // This is where we specify the drawing function. This function will be called
  // when the study graph is drawn on the chart. We are placing this after
  // if (sc.SetDefaults). So in case the study DLL is unloaded and reloaded,
  // this will continue to be set to the correct address.
  sc.p_GDIFunction = DrawToChart;


}
/*==========================================================================*/

// This is the actual drawing function. This function is specified by the
// "sc.p_GDIFunction" member in the main study function above. This drawing
// function is called when Sierra Chart draws the study on the chart. This
// will only occur after there has been a call to the main "scsf_" study
// function which is defined above.

// This drawing function has access to the ACSIL "sc." structure.
// However, any changes to the variable members will have no effect.


void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc )
{
  //Create a Yellow brush
  HBRUSH Brush = CreateSolidBrush(RGB(255,255,0));

  //Select the brush into the device context
  HGDIOBJ PriorBrush = SelectObject(DeviceContext, Brush);

  //Draw a rectangle at the top left of the chart
  Rectangle(DeviceContext, sc.StudyRegionLeftCoordinate + 5, sc.StudyRegionTopCoordinate + 5, sc.StudyRegionLeftCoordinate + 200, sc.StudyRegionTopCoordinate + 200);

  int RightCoordinate = sc.StudyRegionRightCoordinate;

  //Remove the brush from the device context and put the prior brush back in. This is critical!
  SelectObject(DeviceContext,PriorBrush);

  //Delete the brush. This is critical! If you do not do this, you will end up with
  // a GDI leak and crash Sierra Chart.
  DeleteObject(Brush);

  ::SetTextAlign(DeviceContext, TA_NOUPDATECP);

  //Must use the wide character version
  ::TextOutW(DeviceContext, 250, 250, L"Hello.", 6);

  return;
}

/*==========================================================================*/


Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, use the Teton service:
Sierra Chart Teton Futures Order Routing
Date Time Of Last Edit: 2022-02-20 11:49:17

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account