2692 lines
65 KiB
C++
2692 lines
65 KiB
C++
/*++
|
|
|
|
Copyright (C) 1992-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.cpp
|
|
|
|
Abstract:
|
|
|
|
This file contains miscellaneous utiltity routines, mostly
|
|
low-level windows helpers. These routines are not specific
|
|
to the System Monitor control.
|
|
|
|
--*/
|
|
|
|
//==========================================================================//
|
|
// Includes //
|
|
//==========================================================================//
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include <ole2.h> // for SystemTimeToVariantTime
|
|
#include <stdarg.h> // For ANSI variable args. Dont use UNIX <varargs.h>
|
|
#include <stdio.h> // for vsprintf.
|
|
#include <stdlib.h> // For itoa
|
|
#include <string.h> // for strtok
|
|
#include <olectl.h> // for VT_COLOR
|
|
#include <tchar.h>
|
|
#include <math.h>
|
|
#include <winperf.h>
|
|
#include "utils.h"
|
|
#include "unihelpr.h"
|
|
#include "globals.h"
|
|
#include "winhelpr.h"
|
|
#include "polyline.h" // For eDataSourceType
|
|
#include "smonmsg.h" // For error string IDs.
|
|
|
|
#define RESOURCE_STRING_BUF_LEN 256
|
|
#define NUM_RESOURCE_STRING_BUFFERS 16
|
|
#define MISSING_RESOURCE_STRING TEXT("????")
|
|
|
|
#define szHexFormat TEXT("0x%08lX")
|
|
#define szLargeHexFormat TEXT("0x%08lX%08lX")
|
|
|
|
LPCWSTR cszSqlDataSourceFormat = L"SQL:%s!%s";
|
|
|
|
//==========================================================================//
|
|
// Local Functions //
|
|
//==========================================================================//
|
|
|
|
|
|
|
|
VOID
|
|
ClientRectToScreen (
|
|
IN HWND hWnd,
|
|
IN OUT LPRECT lpRect
|
|
)
|
|
/*
|
|
Effect: Remaps lpRect from client coordinates to screen
|
|
coordinates. Analogous to ClientToScreen for rectangles.
|
|
|
|
Note: To convert a rectangle from the client coordinates of
|
|
Wnd1 to the client coordinates of Wnd2, call:
|
|
|
|
ClientRectToScreen (hWnd1, &rect) ;
|
|
ScreenRectToClient (hWnd2, &rect) ;
|
|
|
|
See Also: ClientToScreen (windows), ScreenRectToClient.
|
|
|
|
Internals: Since a rectangle is really only two points, let
|
|
windows do the work with ClientToScreen.
|
|
*/
|
|
{ /* ClientRectToScreen */
|
|
POINT pt1, pt2 ;
|
|
|
|
pt1.x = lpRect->left ;
|
|
pt1.y = lpRect->top ;
|
|
|
|
pt2.x = lpRect->right ;
|
|
pt2.y = lpRect->bottom ;
|
|
|
|
ClientToScreen (hWnd, &pt1) ;
|
|
ClientToScreen (hWnd, &pt2) ;
|
|
|
|
lpRect->left = pt1.x ;
|
|
lpRect->top = pt1.y ;
|
|
|
|
lpRect->right = pt2.x ;
|
|
lpRect->bottom = pt2.y ;
|
|
} // ClientRectToScreen
|
|
|
|
|
|
VOID
|
|
ScreenRectToClient (
|
|
IN HWND hWnd,
|
|
IN OUT LPRECT lpRect
|
|
)
|
|
/*
|
|
Effect: Remaps lpRect from screen coordinates to client
|
|
coordinates. Analogous to ScreenToClient for rectangles.
|
|
|
|
Note: To convert a rectangle from the client coordinates of
|
|
Wnd1 to the client coordinates of Wnd2, call:
|
|
|
|
ClientRectToScreen (hWnd1, &rect) ;
|
|
ScreenRectToClient (hWnd2, &rect) ;
|
|
|
|
See Also: ScreenToClient (windows), ClientRectToScreen.
|
|
|
|
Internals: Since a rectangle is really only two points, let
|
|
windows do the work with ScreenToClient.
|
|
*/
|
|
{ // ScreenRectToClient
|
|
POINT pt1, pt2 ;
|
|
|
|
pt1.x = lpRect->left ;
|
|
pt1.y = lpRect->top ;
|
|
|
|
pt2.x = lpRect->right ;
|
|
pt2.y = lpRect->bottom ;
|
|
|
|
ScreenToClient (hWnd, &pt1) ;
|
|
ScreenToClient (hWnd, &pt2) ;
|
|
|
|
lpRect->left = pt1.x ;
|
|
lpRect->top = pt1.y ;
|
|
|
|
lpRect->right = pt2.x ;
|
|
lpRect->bottom = pt2.y ;
|
|
} // ScreenRectToClient
|
|
|
|
|
|
//==========================================================================//
|
|
// Exported Functions //
|
|
//==========================================================================//
|
|
|
|
|
|
VOID
|
|
Line (
|
|
IN HDC hDC,
|
|
IN HPEN hPen,
|
|
IN INT x1,
|
|
IN INT y1,
|
|
IN INT x2,
|
|
IN INT y2
|
|
)
|
|
{
|
|
HPEN hPenPrevious = NULL;
|
|
|
|
assert ( NULL != hDC );
|
|
|
|
if ( NULL != hDC ) {
|
|
if ( NULL != hPen ) {
|
|
hPenPrevious = (HPEN)SelectObject (hDC, hPen) ;
|
|
}
|
|
|
|
MoveToEx (hDC, x1, y1, NULL) ;
|
|
LineTo (hDC, x2, y2) ;
|
|
|
|
if ( NULL != hPen ) {
|
|
SelectObject (hDC, hPenPrevious);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Fill (
|
|
IN HDC hDC,
|
|
IN DWORD rgbColor,
|
|
IN LPRECT lpRect
|
|
)
|
|
{
|
|
HBRUSH hBrush = NULL;
|
|
|
|
assert ( NULL != hDC && NULL != lpRect );
|
|
|
|
if ( NULL != hDC && NULL != lpRect ) {
|
|
|
|
hBrush = CreateSolidBrush (rgbColor) ;
|
|
|
|
if ( NULL != hBrush ) {
|
|
FillRect (hDC, lpRect, hBrush) ;
|
|
DeleteObject (hBrush) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT
|
|
TextWidth (
|
|
IN HDC hDC,
|
|
IN LPCTSTR lpszText
|
|
)
|
|
{
|
|
SIZE size ;
|
|
INT iReturn;
|
|
|
|
iReturn = 0;
|
|
|
|
assert ( NULL != hDC && NULL != lpszText );
|
|
|
|
if ( NULL != lpszText && NULL != hDC) {
|
|
if ( GetTextExtentPoint (hDC, lpszText, lstrlen (lpszText), &size) ) {
|
|
iReturn = size.cx;
|
|
}
|
|
}
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
INT
|
|
FontHeight (
|
|
IN HDC hDC,
|
|
IN BOOL bIncludeLeading
|
|
)
|
|
{
|
|
TEXTMETRIC tm ;
|
|
INT iReturn = 0;
|
|
|
|
assert ( NULL != hDC );
|
|
|
|
if ( NULL != hDC ) {
|
|
GetTextMetrics (hDC, &tm) ;
|
|
if (bIncludeLeading) {
|
|
iReturn = tm.tmHeight + tm.tmExternalLeading;
|
|
} else {
|
|
iReturn = tm.tmHeight;
|
|
}
|
|
}
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
INT
|
|
TextAvgWidth (
|
|
IN HDC hDC,
|
|
IN INT iNumChars
|
|
)
|
|
{
|
|
TEXTMETRIC tm ;
|
|
INT xAvgWidth ;
|
|
INT iReturn = 0;
|
|
|
|
assert ( NULL != hDC );
|
|
|
|
if ( NULL != hDC ) {
|
|
GetTextMetrics (hDC, &tm) ;
|
|
|
|
xAvgWidth = iNumChars * tm.tmAveCharWidth ;
|
|
|
|
// add 10% slop
|
|
iReturn = MulDiv (xAvgWidth, 11, 10);
|
|
}
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
VOID
|
|
DialogEnable (
|
|
IN HWND hDlg,
|
|
IN WORD wID,
|
|
IN BOOL bEnable
|
|
)
|
|
/*
|
|
Effect: Enable or disable (based on bEnable) the control
|
|
identified by wID in dialog hDlg.
|
|
|
|
See Also: DialogShow.
|
|
*/
|
|
{
|
|
HWND hControl ;
|
|
|
|
assert ( NULL != hDlg );
|
|
|
|
if ( NULL != hDlg ) {
|
|
hControl = GetDlgItem (hDlg, wID) ;
|
|
|
|
if (hControl) {
|
|
EnableWindow (hControl, bEnable) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DialogShow (
|
|
IN HWND hDlg,
|
|
IN WORD wID,
|
|
IN BOOL bShow
|
|
)
|
|
{
|
|
HWND hControl ;
|
|
|
|
assert ( NULL != hDlg );
|
|
|
|
if ( NULL != hDlg ) {
|
|
|
|
hControl = GetDlgItem (hDlg, wID) ;
|
|
|
|
if (hControl) {
|
|
ShowWindow (hControl, bShow ? SW_SHOW : SW_HIDE) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
LongToCommaString (
|
|
IN LONG lNumber,
|
|
OUT LPTSTR lpszText )
|
|
{
|
|
BOOL bNegative ;
|
|
TCHAR szTemp1 [40] ;
|
|
TCHAR szTemp2 [40] ;
|
|
LPTSTR lpsz1 ;
|
|
LPTSTR lpsz2 ;
|
|
INT i ;
|
|
INT iDigit ;
|
|
LPTSTR pszReturn = NULL;
|
|
|
|
assert ( NULL != lpszText );
|
|
|
|
if ( NULL != lpszText ) {
|
|
// Convert the number to a reversed string.
|
|
lpsz1 = szTemp1 ;
|
|
bNegative = (lNumber < 0) ;
|
|
lNumber = labs (lNumber) ;
|
|
|
|
if (lNumber) {
|
|
while (lNumber) {
|
|
iDigit = (INT) (lNumber % 10L) ;
|
|
lNumber /= 10L ;
|
|
*lpsz1++ = (TCHAR) (TEXT('0') + iDigit) ;
|
|
}
|
|
}
|
|
else
|
|
*lpsz1++ = TEXT('0') ;
|
|
|
|
*lpsz1++ = TEXT('\0') ;
|
|
|
|
// Reverse the string and add commas
|
|
lpsz1 = szTemp1 + lstrlen (szTemp1) - 1 ;
|
|
lpsz2 = szTemp2 ;
|
|
|
|
if (bNegative)
|
|
*lpsz2++ = TEXT('-') ;
|
|
|
|
for (i = lstrlen (szTemp1) - 1; i >= 0 ; i--) {
|
|
|
|
*lpsz2++ = *lpsz1-- ;
|
|
|
|
if (i && !(i % 3))
|
|
*lpsz2++ = TEXT(',') ;
|
|
}
|
|
|
|
*lpsz2++ = TEXT('\0') ;
|
|
|
|
pszReturn = lstrcpy (lpszText, szTemp2) ;
|
|
}
|
|
|
|
return pszReturn;
|
|
}
|
|
|
|
|
|
|
|
FLOAT DialogFloat (
|
|
IN HWND hDlg,
|
|
IN WORD wControlID,
|
|
OUT BOOL *pbOK)
|
|
/*
|
|
Effect: Return a floating point representation of the string
|
|
value found in the control wControlID of hDlg.
|
|
|
|
Internals: We use sscanf instead of atof becuase atof returns a
|
|
double. This may or may not be the right thing to do.
|
|
*/
|
|
{
|
|
TCHAR szValue [20] ;
|
|
FLOAT eValue = 0.0;
|
|
INT iNumScanned ;
|
|
|
|
assert ( NULL != hDlg );
|
|
|
|
if ( NULL != hDlg ) {
|
|
DialogText (hDlg, wControlID, szValue) ;
|
|
//ReconvertDecimalPoint (szValue) ;
|
|
iNumScanned = _stscanf (szValue, TEXT("%e"), &eValue) ;
|
|
|
|
if (pbOK)
|
|
*pbOK = (iNumScanned == 1) ;
|
|
|
|
}
|
|
return (eValue) ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MenuEnableItem (
|
|
IN HMENU hMenu,
|
|
IN WORD wID,
|
|
IN BOOL bEnable
|
|
)
|
|
/*
|
|
Effect: Enable or disable, depending on bEnable, the menu item
|
|
associated with id wID in the menu hMenu.
|
|
|
|
Any disabled menu items are displayed grayed out.
|
|
|
|
See Also: EnableMenuItem (windows).
|
|
*/
|
|
{
|
|
return (EnableMenuItem (hMenu, wID,
|
|
bEnable ? (MF_ENABLED | MF_BYCOMMAND) :
|
|
(MF_GRAYED | MF_BYCOMMAND))) ;
|
|
}
|
|
|
|
|
|
INT
|
|
WindowHeight (
|
|
IN HWND hWnd )
|
|
{
|
|
RECT rectWindow ;
|
|
INT iReturn = 0;
|
|
|
|
assert ( NULL != hWnd );
|
|
|
|
if ( NULL != hWnd ) {
|
|
GetWindowRect (hWnd, &rectWindow) ;
|
|
|
|
iReturn = rectWindow.bottom - rectWindow.top ;
|
|
}
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
INT
|
|
WindowWidth (
|
|
IN HWND hWnd )
|
|
{
|
|
RECT rectWindow ;
|
|
INT iReturn = 0;
|
|
|
|
assert ( NULL != hWnd );
|
|
|
|
if ( NULL != hWnd ) {
|
|
GetWindowRect (hWnd, &rectWindow) ;
|
|
iReturn = rectWindow.right - rectWindow.left ;
|
|
}
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
VOID
|
|
WindowResize (
|
|
IN HWND hWnd,
|
|
IN INT xWidth,
|
|
IN INT yHeight
|
|
)
|
|
/*
|
|
Effect: Change the size of the window hWnd, leaving the
|
|
starting position intact. Redraw the window.
|
|
|
|
If either xWidth or yHeight is NULL, keep the
|
|
corresponding dimension unchanged.
|
|
|
|
Internals: Since hWnd may be a child of another parent, we need
|
|
to scale the MoveWindow arguments to be in the client
|
|
coordinates of the parent.
|
|
|
|
*/
|
|
{
|
|
RECT rectWindow ;
|
|
HWND hWndParent ;
|
|
|
|
assert ( NULL != hWnd );
|
|
|
|
if ( NULL != hWnd ) {
|
|
GetWindowRect (hWnd, &rectWindow) ;
|
|
hWndParent = WindowParent (hWnd) ;
|
|
|
|
if (hWndParent)
|
|
ScreenRectToClient (hWndParent, &rectWindow) ;
|
|
|
|
MoveWindow (
|
|
hWnd,
|
|
rectWindow.left,
|
|
rectWindow.top,
|
|
xWidth ? xWidth : rectWindow.right - rectWindow.left,
|
|
yHeight ? yHeight : rectWindow.bottom - rectWindow.top,
|
|
TRUE) ;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WindowSetTopmost (
|
|
IN HWND hWnd,
|
|
IN BOOL bTopmost
|
|
)
|
|
/*
|
|
Effect: Set or clear the "topmost" attribute of hWnd. If a window
|
|
is "topmost", it remains ontop of other windows, even ones
|
|
that have the focus.
|
|
*/
|
|
{
|
|
SetWindowPos (hWnd, bTopmost ? HWND_TOPMOST : HWND_NOTOPMOST,
|
|
0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) ;
|
|
}
|
|
|
|
|
|
VOID
|
|
WindowEnableTitle (
|
|
IN HWND hWnd,
|
|
IN BOOL bTitle)
|
|
{
|
|
DWORD dwStyle ;
|
|
|
|
assert ( NULL != hWnd );
|
|
|
|
if ( NULL != hWnd ) {
|
|
|
|
dwStyle = WindowStyle (hWnd) ;
|
|
|
|
if (bTitle)
|
|
dwStyle = WS_TILEDWINDOW | dwStyle ;
|
|
else
|
|
dwStyle &= ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) ;
|
|
|
|
if (!bTitle)
|
|
SetMenu (hWnd, NULL) ;
|
|
|
|
WindowSetStyle (hWnd, dwStyle) ;
|
|
SetWindowPos (hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
|
|
SWP_NOZORDER | SWP_FRAMECHANGED );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
DeviceNumColors (
|
|
IN HDC hDC
|
|
)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
INT nPlanes = 0;
|
|
INT nBitsPixel = 0;
|
|
|
|
assert ( NULL != hDC );
|
|
|
|
if ( NULL != hDC ) {
|
|
nPlanes = GetDeviceCaps (hDC, PLANES) ;
|
|
nBitsPixel = GetDeviceCaps (hDC, BITSPIXEL) ;
|
|
|
|
bReturn = (1 << (nPlanes * nBitsPixel)) ;
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
VOID
|
|
DrawBitmap (
|
|
IN HDC hDC,
|
|
IN HBITMAP hBitmap,
|
|
IN INT xPos,
|
|
IN INT yPos,
|
|
IN LONG lROPCode)
|
|
{
|
|
BITMAP bm;
|
|
HDC hDCMemory = NULL;
|
|
INT iByteCount = 0;
|
|
HBITMAP hBitmapOrig = NULL;
|
|
|
|
assert ( NULL != hDC && NULL != hBitmap );
|
|
|
|
if ( NULL != hDC && NULL != hBitmap ) {
|
|
|
|
hDCMemory = CreateCompatibleDC (hDC) ;
|
|
|
|
if ( NULL != hDCMemory ) {
|
|
hBitmapOrig = (HBITMAP)SelectObject (hDCMemory, hBitmap) ;
|
|
|
|
if ( NULL != hBitmap ) {
|
|
ZeroMemory ( &bm, sizeof ( BITMAP ) );
|
|
iByteCount = GetObject (hBitmap, sizeof (BITMAP), (LPSTR) &bm) ;
|
|
|
|
if ( 0 < iByteCount ) {
|
|
|
|
BitBlt (
|
|
hDC, // DC for Destination surface
|
|
xPos, yPos, // location in destination surface
|
|
bm.bmWidth, bm.bmHeight, // dimension of bitmap
|
|
hDCMemory, // DC for Source surface
|
|
0, 0, // location in source surface
|
|
lROPCode) ; // ROP code
|
|
}
|
|
}
|
|
DeleteDC (hDCMemory) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT
|
|
MessageBoxResource (
|
|
IN HWND hWndParent,
|
|
IN WORD wTextID,
|
|
IN WORD wTitleID,
|
|
IN UINT uiStyle)
|
|
{
|
|
return MessageBox (hWndParent, ResourceString(wTextID),
|
|
ResourceString(wTitleID), uiStyle);
|
|
}
|
|
|
|
BOOL NeedEllipses (
|
|
IN HDC hAttribDC,
|
|
IN LPCTSTR pszText,
|
|
IN INT nTextLen,
|
|
IN INT xMaxExtent,
|
|
IN INT xEllipses,
|
|
OUT INT *pnChars
|
|
)
|
|
{
|
|
|
|
SIZE size;
|
|
|
|
*pnChars = 0;
|
|
// If no space or no chars, just return
|
|
if (xMaxExtent <= 0 || nTextLen == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
assert ( NULL != hAttribDC
|
|
&& NULL != pszText
|
|
&& NULL != pnChars );
|
|
|
|
if ( NULL == hAttribDC
|
|
|| NULL == pszText
|
|
|| NULL == pnChars ) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Find out how many characters will fit
|
|
GetTextExtentExPoint(hAttribDC, pszText, nTextLen, xMaxExtent, pnChars, NULL, &size);
|
|
|
|
// If all or none fit, we're done
|
|
if (*pnChars == nTextLen || *pnChars == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
// How many chars will fit with ellipses?
|
|
if (xMaxExtent > xEllipses) {
|
|
GetTextExtentExPoint(hAttribDC, pszText, *pnChars, (xMaxExtent - xEllipses),
|
|
pnChars, NULL, &size);
|
|
} else {
|
|
*pnChars = 0;
|
|
}
|
|
|
|
// Better to show one char than just ellipses
|
|
if ( 0 == *pnChars ) {
|
|
*pnChars = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID FitTextOut (
|
|
IN HDC hDC,
|
|
IN HDC hAttribDC,
|
|
IN UINT fuOptions,
|
|
IN CONST RECT *lprc,
|
|
IN LPCTSTR lpString,
|
|
IN INT cbCount,
|
|
IN INT iAlign,
|
|
IN BOOL fVertical
|
|
)
|
|
{
|
|
TCHAR achBuf[MAX_PATH + ELLIPSES_CNT + 1];
|
|
INT iExtent;
|
|
INT nOutCnt = 0;
|
|
SIZE size;
|
|
INT x,y;
|
|
|
|
assert ( NULL != hAttribDC
|
|
&& NULL != lprc
|
|
&& NULL != lpString );
|
|
|
|
if ( NULL != hAttribDC
|
|
&& NULL != lprc
|
|
&& NULL != lpString ) {
|
|
|
|
iExtent = fVertical ? (lprc->bottom - lprc->top) : (lprc->right - lprc->left);
|
|
|
|
GetTextExtentPoint (hAttribDC, ELLIPSES, ELLIPSES_CNT, &size) ;
|
|
|
|
if (NeedEllipses(hAttribDC, lpString, cbCount, iExtent, size.cx, &nOutCnt)) {
|
|
|
|
// Todo: Handle strings > MAX_PATH
|
|
ZeroMemory ( achBuf, sizeof (achBuf) );
|
|
|
|
nOutCnt = min(nOutCnt,MAX_PATH);
|
|
cbCount = min(cbCount, MAX_PATH);
|
|
memcpy(achBuf,lpString,cbCount * sizeof(TCHAR));
|
|
lstrcpy(&achBuf[nOutCnt],ELLIPSES);
|
|
nOutCnt += ELLIPSES_CNT;
|
|
lpString = achBuf;
|
|
}
|
|
|
|
if (fVertical) {
|
|
switch (iAlign) {
|
|
|
|
case TA_CENTER:
|
|
y = (lprc->top + lprc->bottom) / 2;
|
|
break;
|
|
|
|
case TA_RIGHT:
|
|
y = lprc->top;
|
|
break;
|
|
|
|
default:
|
|
y = lprc->bottom;
|
|
break;
|
|
}
|
|
|
|
x = lprc->left;
|
|
}
|
|
else {
|
|
switch (iAlign) {
|
|
|
|
case TA_CENTER:
|
|
x = (lprc->left + lprc->right) / 2;
|
|
break;
|
|
|
|
case TA_RIGHT:
|
|
x = lprc->right;
|
|
break;
|
|
|
|
default:
|
|
x = lprc->left;
|
|
break;
|
|
}
|
|
|
|
y = lprc->top;
|
|
}
|
|
|
|
ExtTextOut(hDC, x, y, fuOptions, lprc, lpString, nOutCnt, NULL);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
TruncateLLTime (
|
|
IN LONGLONG llTime,
|
|
OUT LONGLONG* pllTime
|
|
)
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
BOOL bReturn = FALSE;
|
|
|
|
assert ( NULL != pllTime );
|
|
|
|
if ( NULL != pllTime ) {
|
|
if ( FileTimeToSystemTime((FILETIME*)&llTime, &SystemTime) ) {
|
|
SystemTime.wMilliseconds = 0;
|
|
bReturn = SystemTimeToFileTime(&SystemTime, (FILETIME*)pllTime);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LLTimeToVariantDate (
|
|
IN LONGLONG llTime,
|
|
OUT DATE *pdate
|
|
)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
SYSTEMTIME SystemTime;
|
|
|
|
assert ( NULL != pdate );
|
|
|
|
if ( NULL != pdate ) {
|
|
if ( FileTimeToSystemTime((FILETIME*)&llTime, &SystemTime) ) {
|
|
bReturn = SystemTimeToVariantTime(&SystemTime, pdate);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
VariantDateToLLTime (
|
|
IN DATE date,
|
|
OUT LONGLONG *pllTime
|
|
)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
SYSTEMTIME SystemTime;
|
|
|
|
|
|
assert ( NULL != pllTime );
|
|
|
|
if ( NULL != pllTime ) {
|
|
if ( VariantTimeToSystemTime(date, &SystemTime) ) {
|
|
bReturn = SystemTimeToFileTime(&SystemTime,(FILETIME*)pllTime);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
HRESULT
|
|
StringFromStream (
|
|
LPSTREAM pIStream,
|
|
LPTSTR *ppsz,
|
|
INT nLen
|
|
)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
ULONG bc;
|
|
LPSTR pszAnsi;
|
|
LPTSTR pszTemp;
|
|
|
|
USES_CONVERSION
|
|
|
|
assert ( NULL != pIStream && NULL != ppsz );
|
|
|
|
if ( NULL != pIStream
|
|
&& NULL != ppsz ) {
|
|
|
|
*ppsz = NULL;
|
|
|
|
if (nLen == 0) {
|
|
hr = S_OK;
|
|
} else {
|
|
|
|
pszAnsi = (LPSTR)alloca(nLen + 1);
|
|
hr = pIStream->Read(pszAnsi, nLen, &bc);
|
|
|
|
if ( SUCCEEDED (hr) ) {
|
|
if (bc != (ULONG)nLen) {
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED (hr) ) {
|
|
|
|
// Convert to internal char type
|
|
pszAnsi[nLen] = 0;
|
|
pszTemp = A2T(pszAnsi);
|
|
|
|
*ppsz = new TCHAR [lstrlen(pszTemp) + 1];
|
|
if ( NULL != *ppsz ) {
|
|
lstrcpy(*ppsz, pszTemp);
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// WideStringFromStream also supports multi-sz
|
|
//
|
|
HRESULT
|
|
WideStringFromStream (
|
|
LPSTREAM pIStream,
|
|
LPTSTR *ppsz,
|
|
INT nLen
|
|
)
|
|
{
|
|
ULONG bc;
|
|
LPWSTR pszWide = NULL;
|
|
HRESULT hr = E_POINTER;
|
|
|
|
assert ( NULL != pIStream && NULL != ppsz );
|
|
|
|
// This method does not perform conversion from W to T.
|
|
assert ( sizeof(WCHAR) == sizeof(TCHAR) );
|
|
|
|
if ( NULL != pIStream
|
|
&& NULL != ppsz ) {
|
|
|
|
*ppsz = NULL;
|
|
|
|
if (nLen == 0) {
|
|
hr = S_OK;
|
|
} else {
|
|
pszWide = (LPWSTR)alloca( (nLen + 1) * sizeof(WCHAR) );
|
|
hr = pIStream->Read(pszWide, nLen*sizeof(WCHAR), &bc);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
if (bc != (ULONG)nLen*sizeof(WCHAR)) {
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr)) {
|
|
// Write ending NULL for non-multisz strings.
|
|
pszWide[nLen] = L'\0';
|
|
|
|
*ppsz = new WCHAR [nLen + 1];
|
|
if ( NULL != *ppsz ) {
|
|
memcpy(*ppsz, pszWide, (nLen+1)*sizeof(WCHAR) );
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Property bag I/O - only include if user knows about IStream
|
|
//
|
|
#ifdef __IPropertyBag_INTERFACE_DEFINED__
|
|
|
|
HRESULT
|
|
IntegerToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
INT intData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_I4;
|
|
vValue.lVal = intData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
OleColorToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
OLE_COLOR& clrData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_COLOR; // VT_COLOR = VT_I4
|
|
vValue.lVal = clrData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ShortToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
SHORT iData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_I2;
|
|
vValue.iVal = iData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
BOOLToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
BOOL bData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_BOOL;
|
|
vValue.boolVal = (SHORT)bData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
DoubleToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
DOUBLE dblData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_R8;
|
|
vValue.dblVal = dblData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
FloatToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
FLOAT fData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_R4;
|
|
vValue.fltVal = fData;
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CyToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
CY& cyData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_CY;
|
|
vValue.cyVal.int64 = cyData.int64;
|
|
|
|
hr = VariantChangeType ( &vValue, &vValue, NULL, VT_BSTR );
|
|
|
|
if ( SUCCEEDED ( hr ) )
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
typedef struct _HTML_ENTITIES {
|
|
LPTSTR szHTML;
|
|
LPTSTR szEntity;
|
|
} HTML_ENTITIES;
|
|
|
|
HTML_ENTITIES g_htmlentities[] = {
|
|
_T("&"), _T("&"),
|
|
_T("\""), _T("""),
|
|
_T("<"), _T("<"),
|
|
_T(">"), _T(">"),
|
|
NULL, NULL
|
|
};
|
|
|
|
HRESULT
|
|
StringToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
LPCTSTR szData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
LPTSTR szTrans = NULL;
|
|
BOOL bAllocated = FALSE;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_BSTR;
|
|
vValue.bstrVal = NULL;
|
|
|
|
if ( NULL != szData ) {
|
|
int i;
|
|
ULONG lSize = 0;
|
|
LPTSTR szScan;
|
|
|
|
for( i=0 ;g_htmlentities[i].szHTML != NULL; i++ ){
|
|
szScan = (LPTSTR)szData;
|
|
while( *szScan != _T('\0') ){
|
|
if( *szScan == *g_htmlentities[i].szHTML ){
|
|
lSize += (6*sizeof(TCHAR));
|
|
}
|
|
szScan++;
|
|
}
|
|
}
|
|
if( lSize > 0 ){
|
|
szTrans = (LPTSTR)malloc(lSize);
|
|
if( szTrans != NULL ){
|
|
bAllocated = TRUE;
|
|
ZeroMemory( szTrans, lSize );
|
|
szScan = (LPTSTR)szData;
|
|
while( *szScan != _T('\0') ){
|
|
BOOL bEntity = FALSE;
|
|
for( i=0; g_htmlentities[i].szHTML != NULL; i++ ){
|
|
if( *szScan == *g_htmlentities[i].szHTML ){
|
|
bEntity = TRUE;
|
|
_tcscat( szTrans, g_htmlentities[i].szEntity );
|
|
break;
|
|
}
|
|
}
|
|
if( !bEntity ){
|
|
_tcsncat( szTrans, szScan, 1 );
|
|
}
|
|
szScan++;
|
|
}
|
|
}
|
|
}else{
|
|
szTrans = (LPTSTR)szData;
|
|
}
|
|
vValue.bstrVal = SysAllocString ( T2W( szTrans ) );
|
|
|
|
if ( NULL != vValue.bstrVal ) {
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
VariantClear ( &vValue );
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
} else {
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
}
|
|
}
|
|
if( NULL != szTrans && bAllocated ){
|
|
free( szTrans );
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
LLTimeToPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
LPCTSTR szPropName,
|
|
LONGLONG& rllData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
BOOL bStatus;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_DATE;
|
|
|
|
bStatus = LLTimeToVariantDate ( rllData, &vValue.date );
|
|
|
|
if ( bStatus ) {
|
|
|
|
hr = pIPropBag->Write(szPropName, &vValue );
|
|
|
|
VariantClear ( &vValue );
|
|
|
|
} else {
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
IntegerFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
INT& rintData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_I4;
|
|
vValue.lVal = 0;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rintData = vValue.lVal;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
OleColorFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
OLE_COLOR& rintData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_COLOR; // VT_COLOR == VT_I4;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rintData = vValue.lVal;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
BOOLFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
BOOL& rbData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_BOOL;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rbData = vValue.boolVal;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
DoubleFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
DOUBLE& rdblData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_R8;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rdblData = vValue.dblVal;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
FloatFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
FLOAT& rfData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_R4;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rfData = vValue.fltVal;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ShortFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
SHORT& riData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_I2;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
riData = vValue.iVal;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CyFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
CY& rcyData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_CY;
|
|
vValue.cyVal.int64 = 0;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
hr = VariantChangeType ( &vValue, &vValue, NULL, VT_CY );
|
|
|
|
if ( SUCCEEDED ( hr ) ) {
|
|
rcyData.int64 = vValue.cyVal.int64;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
StringFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
LPTSTR szData,
|
|
INT& riBufSize )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
if ( NULL != szData ) {
|
|
lstrcpy ( szData, _T("") );
|
|
}
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_BSTR;
|
|
vValue.bstrVal = NULL;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED(hr) && vValue.bstrVal ) {
|
|
INT iNewBufSize = SysStringLen(vValue.bstrVal) + 2;
|
|
if ( iNewBufSize > 2 ) {
|
|
|
|
if ( riBufSize >= iNewBufSize && NULL != szData ) {
|
|
|
|
LPTSTR szTrans = (LPTSTR)malloc(iNewBufSize);
|
|
|
|
if( szTrans != NULL ){
|
|
lstrcpy ( szData, W2T( vValue.bstrVal) );
|
|
for( int i=0;g_htmlentities[i].szHTML != NULL;i++ ){
|
|
LPTSTR szScan = NULL;
|
|
while( szScan = _tcsstr( szData, g_htmlentities[i].szEntity ) ){
|
|
*szScan = _T('\0');
|
|
_tcscpy( szTrans, szData );
|
|
_tcscat( szTrans, g_htmlentities[i].szHTML );
|
|
szScan += _tcslen( g_htmlentities[i].szEntity);
|
|
_tcscat( szTrans, szScan );
|
|
_tcscpy( szData, szTrans );
|
|
}
|
|
}
|
|
free( szTrans );
|
|
}else{
|
|
lstrcpy ( szData, W2T( vValue.bstrVal) );
|
|
}
|
|
}
|
|
riBufSize = iNewBufSize;
|
|
} else {
|
|
riBufSize = 0;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
LLTimeFromPropertyBag (
|
|
IPropertyBag* pIPropBag,
|
|
IErrorLog* pIErrorLog,
|
|
LPCTSTR szPropName,
|
|
LONGLONG& rllData )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
VARIANT vValue;
|
|
|
|
assert ( NULL != pIPropBag );
|
|
|
|
if ( NULL != pIPropBag ) {
|
|
|
|
VariantInit( &vValue );
|
|
vValue.vt = VT_DATE;
|
|
|
|
hr = pIPropBag->Read(szPropName, &vValue, pIErrorLog );
|
|
|
|
if ( SUCCEEDED(hr) ) {
|
|
if ( !VariantDateToLLTime ( vValue.date, &rllData ) ) {
|
|
hr = E_FAIL;
|
|
}
|
|
VariantClear( &vValue );
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
#endif // Property bag
|
|
|
|
LPTSTR
|
|
ResourceString (
|
|
UINT uID
|
|
)
|
|
{
|
|
|
|
static TCHAR aszBuffers[NUM_RESOURCE_STRING_BUFFERS][RESOURCE_STRING_BUF_LEN];
|
|
static INT iBuffIndex = 0;
|
|
|
|
// Use next buffer
|
|
if (++iBuffIndex >= NUM_RESOURCE_STRING_BUFFERS)
|
|
iBuffIndex = 0;
|
|
|
|
// Load and return string
|
|
if (LoadString(g_hInstance, uID, aszBuffers[iBuffIndex], RESOURCE_STRING_BUF_LEN))
|
|
return aszBuffers[iBuffIndex];
|
|
else
|
|
return MISSING_RESOURCE_STRING;
|
|
}
|
|
|
|
DWORD
|
|
FormatSystemMessage (
|
|
DWORD dwMessageId,
|
|
LPTSTR pszSystemMessage,
|
|
DWORD dwBufSize )
|
|
{
|
|
DWORD dwReturn = 0;
|
|
HINSTANCE hPdh = NULL;
|
|
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
|
|
|
|
assert ( NULL != pszSystemMessage );
|
|
|
|
if ( NULL != pszSystemMessage ) {
|
|
pszSystemMessage[0] = _T('\0');
|
|
|
|
hPdh = LoadLibrary( _T("PDH.DLL") );
|
|
|
|
if ( NULL != hPdh ) {
|
|
dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
|
|
}
|
|
|
|
dwReturn = ::FormatMessage (
|
|
dwFlags,
|
|
hPdh,
|
|
dwMessageId,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
pszSystemMessage,
|
|
dwBufSize,
|
|
NULL );
|
|
|
|
if ( NULL != hPdh ) {
|
|
FreeLibrary( hPdh );
|
|
}
|
|
|
|
if ( _T('\0') == pszSystemMessage[0] ) {
|
|
_stprintf ( pszSystemMessage, _T("0x%08lX"), dwMessageId );
|
|
}
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
INT
|
|
GetNumSeparators (
|
|
LPTSTR& rpDecimal,
|
|
LPTSTR& rpThousand )
|
|
{
|
|
#define NUM_BUF_LEN 4
|
|
INT iLength;
|
|
|
|
static TCHAR szDecimal[NUM_BUF_LEN];
|
|
static TCHAR szThousand[NUM_BUF_LEN];
|
|
|
|
rpDecimal = NULL;
|
|
rpThousand = NULL;
|
|
|
|
iLength = GetLocaleInfo (
|
|
LOCALE_USER_DEFAULT,
|
|
LOCALE_SDECIMAL,
|
|
szDecimal,
|
|
NUM_BUF_LEN );
|
|
|
|
if ( 0 != iLength ) {
|
|
iLength = GetLocaleInfo (
|
|
LOCALE_USER_DEFAULT,
|
|
LOCALE_STHOUSAND,
|
|
szThousand,
|
|
NUM_BUF_LEN );
|
|
|
|
}
|
|
|
|
if ( 0 != iLength ) {
|
|
rpDecimal = szDecimal;
|
|
rpThousand = szThousand;
|
|
}
|
|
|
|
return iLength;
|
|
}
|
|
|
|
LPTSTR
|
|
GetTimeSeparator ( void )
|
|
{
|
|
#define TIME_MARK_BUF_LEN 5
|
|
static INT iInitialized; // Initialized to 0
|
|
static TCHAR szTimeSeparator[TIME_MARK_BUF_LEN];
|
|
|
|
if ( 0 == iInitialized ) {
|
|
INT iLength;
|
|
|
|
iLength = GetLocaleInfo (
|
|
LOCALE_USER_DEFAULT,
|
|
LOCALE_STIME,
|
|
szTimeSeparator,
|
|
TIME_MARK_BUF_LEN );
|
|
|
|
// Default to colon for time separator
|
|
if ( _T('\0') == szTimeSeparator[0] ) {
|
|
lstrcpy (szTimeSeparator, _T(":") );
|
|
}
|
|
|
|
iInitialized = 1;
|
|
}
|
|
|
|
assert ( _T('\0') != szTimeSeparator[0] );
|
|
|
|
return szTimeSeparator;
|
|
}
|
|
|
|
BOOL
|
|
DisplayThousandsSeparator ( void )
|
|
{
|
|
long nErr;
|
|
HKEY hKey = NULL;
|
|
DWORD dwRegValue;
|
|
DWORD dwDataType;
|
|
DWORD dwDataSize;
|
|
DWORD dwDisposition;
|
|
|
|
static INT siInitialized; // Initialized to 0
|
|
static BOOL sbUseSeparator; // Initialized to 0 ( FALSE )
|
|
|
|
// check registry setting to see if thousands separator is enabled
|
|
if ( 0 == siInitialized ) {
|
|
nErr = RegOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
_T("Software\\Microsoft\\SystemMonitor"),
|
|
&hKey );
|
|
|
|
if( ERROR_SUCCESS != nErr ) {
|
|
nErr = RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
_T("Software\\Microsoft\\SystemMonitor"),
|
|
0,
|
|
_T("REG_DWORD"),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition );
|
|
}
|
|
|
|
dwRegValue = 0;
|
|
if ( ERROR_SUCCESS == nErr ) {
|
|
|
|
dwDataSize = sizeof(DWORD);
|
|
nErr = RegQueryValueExW (
|
|
hKey,
|
|
_T("DisplayThousandsSeparator"),
|
|
NULL,
|
|
&dwDataType,
|
|
(LPBYTE) &dwRegValue,
|
|
(LPDWORD) &dwDataSize );
|
|
|
|
if ( ERROR_SUCCESS == nErr
|
|
&& REG_DWORD == dwDataType
|
|
&& sizeof(DWORD) == dwDataSize )
|
|
{
|
|
if ( 0 != dwRegValue ) {
|
|
sbUseSeparator = TRUE;
|
|
}
|
|
}
|
|
siInitialized = 1;
|
|
}
|
|
|
|
if ( NULL != hKey ) {
|
|
nErr = RegCloseKey( hKey );
|
|
}
|
|
}
|
|
|
|
return sbUseSeparator;
|
|
}
|
|
|
|
INT
|
|
FormatNumberInternal (
|
|
LPTSTR pNumOrig,
|
|
LPTSTR pNumFormatted,
|
|
INT cchars,
|
|
UINT uiPrecision,
|
|
UINT uiLeadingZero,
|
|
UINT uiGrouping,
|
|
UINT uiNegativeMode )
|
|
{
|
|
INT iLength = 0;
|
|
TCHAR* pszSrc;
|
|
|
|
static INT siInitialized; // Initialized to 0
|
|
static NUMBERFMT NumberFormat;
|
|
|
|
assert ( NULL != pNumOrig && NULL != pNumFormatted );
|
|
|
|
if ( NULL != pNumOrig && NULL != pNumFormatted ) {
|
|
|
|
iLength = 2;
|
|
|
|
NumberFormat.NumDigits = uiPrecision;
|
|
NumberFormat.LeadingZero = uiLeadingZero;
|
|
NumberFormat.NegativeOrder = uiNegativeMode;
|
|
|
|
if ( DisplayThousandsSeparator() ) {
|
|
NumberFormat.Grouping = uiGrouping;
|
|
} else {
|
|
NumberFormat.Grouping = 0;
|
|
}
|
|
|
|
if ( 0 == siInitialized ) {
|
|
iLength = GetNumSeparators (
|
|
NumberFormat.lpDecimalSep,
|
|
NumberFormat.lpThousandSep );
|
|
siInitialized = 1;
|
|
}
|
|
|
|
// GetNumberFormat requires "." for decimal point.
|
|
if ( NumberFormat.lpDecimalSep != NULL) {
|
|
if (0 != lstrcmpi(NumberFormat.lpDecimalSep, _T(".")) ) {
|
|
|
|
for ( pszSrc = pNumOrig; *pszSrc != '\0'; pszSrc++) {
|
|
if ( *pszSrc == NumberFormat.lpDecimalSep[0] ) {
|
|
TCHAR szDecimalDot[2];
|
|
lstrcpy (szDecimalDot, _T("."));
|
|
*pszSrc = szDecimalDot[0];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( 0 != iLength ) {
|
|
iLength = GetNumberFormat (
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
pNumOrig,
|
|
&NumberFormat,
|
|
pNumFormatted,
|
|
cchars );
|
|
}
|
|
}
|
|
// Return 0 on failure, number of chars on success.
|
|
// GetNumberFormat includes the null terminator in the length.
|
|
return iLength;
|
|
}
|
|
|
|
INT
|
|
FormatHex (
|
|
double dValue,
|
|
LPTSTR pNumFormatted,
|
|
BOOL bLargeFormat
|
|
)
|
|
{
|
|
INT iLength = 0;
|
|
TCHAR szPreFormat[24];
|
|
|
|
assert ( NULL != pNumFormatted );
|
|
|
|
if ( NULL != pNumFormatted ) {
|
|
iLength = 8;
|
|
// Localization doesn't handle padding blanks.
|
|
_stprintf (
|
|
szPreFormat,
|
|
(bLargeFormat ? szLargeHexFormat : szHexFormat ),
|
|
(ULONG)dValue );
|
|
wcscpy(pNumFormatted,szPreFormat);
|
|
}
|
|
|
|
return iLength;
|
|
}
|
|
|
|
INT
|
|
FormatNumber (
|
|
double dValue,
|
|
LPTSTR pNumFormatted,
|
|
INT ccharsFormatted,
|
|
UINT /* uiMinimumWidth */,
|
|
UINT uiPrecision )
|
|
{
|
|
INT iLength = 0;
|
|
TCHAR szPreFormat[24];
|
|
INT iLeadingZero = FALSE;
|
|
|
|
assert ( NULL != pNumFormatted );
|
|
// This method enforces number format commonality
|
|
if ( NULL != pNumFormatted ) {
|
|
|
|
assert ( 8 > uiPrecision );
|
|
|
|
// Localization doesn't handle padding blanks.
|
|
_stprintf (
|
|
szPreFormat,
|
|
TEXT("%0.7f"), // assumes 7 >= uiPrecision
|
|
dValue );
|
|
|
|
if ( 1 > dValue )
|
|
iLeadingZero = TRUE;
|
|
|
|
iLength = FormatNumberInternal (
|
|
szPreFormat,
|
|
pNumFormatted,
|
|
ccharsFormatted,
|
|
uiPrecision,
|
|
iLeadingZero, // Leading 0
|
|
3, // Grouping
|
|
1 ); // Negative format
|
|
}
|
|
|
|
// Return 0 on failure, number of chars on success.
|
|
// GetNumberFormat includes the null terminator in the length.
|
|
return iLength;
|
|
}
|
|
|
|
INT
|
|
FormatScientific (
|
|
double dValue,
|
|
LPTSTR pszNumFormatted,
|
|
INT ccharsFormatted,
|
|
UINT /* uiMinimumWidth */,
|
|
UINT uiPrecision )
|
|
{
|
|
INT iLength = 0;
|
|
TCHAR szPreFormat[24];
|
|
TCHAR szPreFormNumber[24];
|
|
TCHAR *pche;
|
|
INT iPreLen;
|
|
INT iPostLen;
|
|
INT iLeadingZero = FALSE;
|
|
|
|
assert ( NULL != pszNumFormatted );
|
|
// This method enforces number format commonality
|
|
if ( NULL != pszNumFormatted ) {
|
|
|
|
assert ( 8 > uiPrecision );
|
|
assert ( 32 > ccharsFormatted );
|
|
|
|
// Localization doesn't handle padding blanks.
|
|
_stprintf (
|
|
szPreFormat,
|
|
TEXT("%0.8e"), // assumes 8 >= uiPrecision
|
|
dValue );
|
|
|
|
pche = _tcsrchr(szPreFormat, _T('e'));
|
|
if (pche != NULL) {
|
|
iPreLen = (INT)((UINT_PTR)pche - (UINT_PTR)szPreFormat); // Number of bytes
|
|
iPostLen = lstrlen(pche) + 1;
|
|
|
|
memcpy(szPreFormNumber, szPreFormat, iPreLen);
|
|
|
|
iPreLen /= sizeof (TCHAR); // Number of characters
|
|
|
|
szPreFormNumber[iPreLen] = 0;
|
|
|
|
if ( 1 > dValue ) {
|
|
iLeadingZero = TRUE;
|
|
}
|
|
|
|
iLength = FormatNumberInternal (
|
|
szPreFormNumber,
|
|
pszNumFormatted,
|
|
ccharsFormatted,
|
|
uiPrecision,
|
|
iLeadingZero, // Leading 0
|
|
0, // Grouping
|
|
1 ); // Negative format
|
|
|
|
if( ( iLength + iPostLen ) < ccharsFormatted ) {
|
|
lstrcat( pszNumFormatted, pche );
|
|
iLength += iPostLen;
|
|
}
|
|
}
|
|
}
|
|
// Return 0 on failure, number of chars on success.
|
|
// GetNumberFormat includes the null terminator in the length.
|
|
return iLength;
|
|
}
|
|
|
|
void
|
|
FormatDateTime (
|
|
LONGLONG llTime,
|
|
LPTSTR pszDate,
|
|
LPTSTR pszTime )
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
assert ( NULL != pszDate && NULL != pszTime );
|
|
if ( NULL != pszDate
|
|
&& NULL != pszTime ) {
|
|
|
|
FileTimeToSystemTime((FILETIME*)&llTime, &SystemTime);
|
|
GetTimeFormat (LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, pszTime, MAX_TIME_CHARS) ;
|
|
GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, &SystemTime, NULL, pszDate, MAX_DATE_CHARS) ;
|
|
}
|
|
}
|
|
|
|
// CreateTargetDC is based on AtlCreateTargetDC.
|
|
HDC
|
|
CreateTargetDC(HDC hdc, DVTARGETDEVICE* ptd)
|
|
{
|
|
USES_CONVERSION
|
|
|
|
// cases hdc, ptd, hdc is metafile, hic
|
|
// NULL, NULL, n/a, Display
|
|
// NULL, !NULL, n/a, ptd
|
|
// !NULL, NULL, FALSE, hdc
|
|
// !NULL, NULL, TRUE, display
|
|
// !NULL, !NULL, FALSE, ptd
|
|
// !NULL, !NULL, TRUE, ptd
|
|
|
|
if ( NULL != ptd ) {
|
|
LPDEVMODE lpDevMode;
|
|
LPOLESTR lpszDriverName;
|
|
LPOLESTR lpszDeviceName;
|
|
LPOLESTR lpszPortName;
|
|
|
|
if (ptd->tdExtDevmodeOffset == 0)
|
|
lpDevMode = NULL;
|
|
else
|
|
lpDevMode = (LPDEVMODE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);
|
|
|
|
lpszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset);
|
|
lpszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset);
|
|
lpszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);
|
|
|
|
return ::CreateDC(W2T(lpszDriverName), W2T(lpszDeviceName),
|
|
W2T(lpszPortName), lpDevMode);
|
|
} else if ( NULL == hdc ) {
|
|
return ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
|
|
} else if ( GetDeviceCaps(hdc, TECHNOLOGY) == DT_METAFILE ) {
|
|
return ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
|
|
} else
|
|
return hdc;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
FUNCTION : HitTestLine
|
|
|
|
PARAMETERS : POINT pt0 - endpoint for line segment
|
|
POINT pt1 - endpoint for line segment
|
|
POINTS ptMouse - mouse coordinates of hit
|
|
INT nWidth - width of pen
|
|
|
|
PURPOSE : test if mouse click occurred on line segment while
|
|
adjusting for the width of line
|
|
|
|
CALLS : GetDC
|
|
ReleaseDC
|
|
SetGraphicsMode
|
|
SetWorldTransform
|
|
|
|
MESSAGES : none
|
|
|
|
RETURNS : BOOL - TRUE if the point was within the width of the
|
|
pen about the line
|
|
FALSE if the point lies outside of the width
|
|
of the pen about the line
|
|
|
|
COMMENTS : uses VECTOR2D.DLL
|
|
|
|
HISTORY : 9/20/93 - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
BOOL HitTestLine( POINT pt0, POINT pt1, POINTS ptMouse, INT nWidth )
|
|
{
|
|
POINT PtM;
|
|
VECTOR2D tt0, tt1;
|
|
double dist;
|
|
INT nHalfWidth;
|
|
|
|
nHalfWidth = (nWidth/2 < 1) ? 1 : nWidth/2;
|
|
|
|
//
|
|
//convert the line into a vector
|
|
//
|
|
|
|
POINTS2VECTOR2D(pt0, pt1, tt0);
|
|
//
|
|
//convert the mouse points (short) into POINT (long)
|
|
//
|
|
|
|
MPOINT2POINT(ptMouse ,PtM);
|
|
POINTS2VECTOR2D(pt0, PtM, tt1);
|
|
|
|
//
|
|
//if the mouse click is past the endpoints of
|
|
//a line segment return FALSE
|
|
//
|
|
|
|
if (pt0.x <= pt1.x)
|
|
{
|
|
if (PtM.x < pt0.x || PtM.x > pt1.x)
|
|
return (FALSE);
|
|
}
|
|
else
|
|
{
|
|
if (PtM.x > pt0.x || PtM.x < pt1.x)
|
|
return (FALSE);
|
|
}
|
|
//
|
|
//this is the call to the function that does the work
|
|
//of obtaining the distance of the point to the line
|
|
//
|
|
dist = vDistFromPointToLine(&pt0, &pt1, &PtM);
|
|
|
|
//
|
|
//TRUE if the distance is within the width of the pen about the
|
|
//line otherwise FALSE
|
|
//
|
|
return (dist >= -nHalfWidth && dist <= nHalfWidth);
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
vSubtractVectors
|
|
|
|
The vSubtractVectors function subtracts the components of a two
|
|
dimensional vector from another. The resultant vector
|
|
c = (a1 - b1, a2 - b2).
|
|
|
|
Parameters
|
|
|
|
v0 A pointer to a VECTOR2D structure containing the components
|
|
of the first two dimensional vector.
|
|
v1 A pointer to a VECTOR2D structure containing the components
|
|
of the second two dimensional vector.
|
|
vt A pointer to a VECTOR2D structure in which the components
|
|
of the two dimensional vector obtained from the subtraction of
|
|
the first two are placed.
|
|
|
|
Return value
|
|
|
|
A pointer to a VECTOR2D structure containing the new vector obtained
|
|
from the subtraction of the first two parameters.
|
|
|
|
HISTORY : - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
PVECTOR2D vSubtractVectors(PVECTOR2D v0, PVECTOR2D v1, PVECTOR2D v)
|
|
{
|
|
if (v0 == NULL || v1 == NULL)
|
|
v = (PVECTOR2D)NULL;
|
|
else
|
|
{
|
|
v->x = v0->x - v1->x;
|
|
v->y = v0->y - v1->y;
|
|
}
|
|
return(v);
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
vVectorSquared
|
|
|
|
The vVectorSquared function squares each of the components of the
|
|
vector and adds then together to produce the squared value of the
|
|
vector. SquaredValue = a.x * a.x + a.y * a.y.
|
|
|
|
Parameters
|
|
|
|
v0 A pointer to a VECTOR2D structure containing the vector upon which
|
|
to determine the squared value.
|
|
|
|
Return value
|
|
|
|
A double value which is the squared value of the vector.
|
|
|
|
HISTORY : - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
double vVectorSquared(PVECTOR2D v0)
|
|
{
|
|
double dSqLen;
|
|
|
|
if (v0 == NULL)
|
|
dSqLen = 0.0;
|
|
else
|
|
dSqLen = (double)(v0->x * v0->x) + (double)(v0->y * v0->y);
|
|
return (dSqLen);
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
vVectorMagnitude
|
|
|
|
The vVectorMagnitude function determines the length of a vector by
|
|
summing the squares of each of the components of the vector. The
|
|
magnitude is equal to a.x * a.x + a.y * a.y.
|
|
|
|
Parameters
|
|
|
|
v0 A pointer to a VECTOR2D structure containing the vector upon
|
|
which to determine the magnitude.
|
|
|
|
Return value
|
|
|
|
A double value which is the magnitude of the vector.
|
|
|
|
HISTORY : - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
double vVectorMagnitude(PVECTOR2D v0)
|
|
{
|
|
double dMagnitude;
|
|
|
|
if (v0 == NULL)
|
|
dMagnitude = 0.0;
|
|
else
|
|
dMagnitude = sqrt(vVectorSquared(v0));
|
|
return (dMagnitude);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
vDotProduct
|
|
|
|
The function vDotProduct computes the dot product of two vectors. The
|
|
dot product of two vectors is the sum of the products of the components
|
|
of the vectors ie: for the vectors a and b, dotprod = a1 * a2 + b1 * b2.
|
|
|
|
Parameters
|
|
|
|
v0 A pointer to a VECTOR2D structure containing the first vector used
|
|
for obtaining a dot product.
|
|
v1 A pointer to a VECTOR2D structure containing the second vector used
|
|
for obtaining a dot product.
|
|
|
|
Return value
|
|
|
|
A double value containing the scalar dot product value.
|
|
|
|
HISTORY : - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
double vDotProduct(PVECTOR2D v0, PVECTOR2D v1)
|
|
{
|
|
return ((v0 == NULL || v1 == NULL) ? 0.0
|
|
: (v0->x * v1->x) + (v0->y * v1->y));
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
vProjectAndResolve
|
|
|
|
The function vProjectAndResolve resolves a vector into two vector
|
|
components. The first is a vector obtained by projecting vector v0 onto
|
|
v1. The second is a vector that is perpendicular (normal) to the
|
|
projected vector. It extends from the head of the projected vector
|
|
v1 to the head of the original vector v0.
|
|
|
|
Parameters
|
|
|
|
v0 A pointer to a VECTOR2D structure containing the first vector
|
|
v1 A pointer to a VECTOR2D structure containing the second vector
|
|
ppProj A pointer to a PROJECTION structure containing the resolved
|
|
vectors and their lengths.
|
|
|
|
Return value
|
|
|
|
void.
|
|
|
|
HISTORY : - created - denniscr
|
|
|
|
************************************************************************/
|
|
|
|
void vProjectAndResolve(PVECTOR2D v0, PVECTOR2D v1, PPROJECTION ppProj)
|
|
{
|
|
VECTOR2D ttProjection, ttOrthogonal;
|
|
double vDotProd;
|
|
double proj1 = 0.0;
|
|
//
|
|
//obtain projection vector
|
|
//
|
|
//c = a * b
|
|
// ----- b
|
|
// |b|^2
|
|
//
|
|
|
|
ttOrthogonal.x = 0.0;
|
|
ttOrthogonal.y = 0.0;
|
|
vDotProd = vDotProduct(v1, v1);
|
|
|
|
if ( 0.0 != vDotProd ) {
|
|
proj1 = vDotProduct(v0, v1)/vDotProd;
|
|
}
|
|
|
|
ttProjection.x = v1->x * proj1;
|
|
ttProjection.y = v1->y * proj1;
|
|
//
|
|
//obtain perpendicular projection : e = a - c
|
|
//
|
|
vSubtractVectors(v0, &ttProjection, &ttOrthogonal);
|
|
//
|
|
//fill PROJECTION structure with appropriate values
|
|
//
|
|
ppProj->LenProjection = vVectorMagnitude(&ttProjection);
|
|
ppProj->LenPerpProjection = vVectorMagnitude(&ttOrthogonal);
|
|
|
|
ppProj->ttProjection.x = ttProjection.x;
|
|
ppProj->ttProjection.y = ttProjection.y;
|
|
ppProj->ttPerpProjection.x = ttOrthogonal.x;
|
|
ppProj->ttPerpProjection.y = ttOrthogonal.y;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
vDistFromPointToLine
|
|
|
|
The function vDistFromPointToLine computes the distance from the point
|
|
ptTest to the line defined by endpoints pt0 and pt1. This is done by
|
|
resolving the the vector from pt0 to ptTest into its components. The
|
|
length of the component vector that is attached to the head of the
|
|
vector from pt0 to ptTest is the distance of ptTest from the line.
|
|
|
|
Parameters
|
|
|
|
pt0 A pointer to a POINT structure containing the first endpoint of the
|
|
line.
|
|
pt1 A pointer to a POINT structure containing the second endpoint of the
|
|
line.
|
|
ptTest A pointer to a POINT structure containing the point for which the
|
|
distance from the line is to be computed.
|
|
|
|
Return value
|
|
|
|
A double value that contains the distance of ptTest to the line defined
|
|
by the endpoints pt0 and pt1.
|
|
|
|
HISTORY : - created - denniscr
|
|
************************************************************************/
|
|
|
|
double vDistFromPointToLine(LPPOINT pt0, LPPOINT pt1, LPPOINT ptTest)
|
|
{
|
|
VECTOR2D ttLine, ttTest;
|
|
PROJECTION pProjection;
|
|
|
|
POINTS2VECTOR2D(*pt0, *pt1, ttLine);
|
|
POINTS2VECTOR2D(*pt0, *ptTest, ttTest);
|
|
|
|
vProjectAndResolve(&ttTest, &ttLine, &pProjection);
|
|
|
|
return(pProjection.LenPerpProjection);
|
|
}
|
|
|
|
|
|
BOOL
|
|
FileRead (
|
|
HANDLE hFile,
|
|
void* lpMemory,
|
|
DWORD nAmtToRead)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
DWORD nAmtRead = 0;
|
|
|
|
assert ( NULL != hFile );
|
|
assert ( NULL != lpMemory );
|
|
|
|
if ( NULL != hFile
|
|
&& NULL != lpMemory ) {
|
|
bSuccess = ReadFile (hFile, lpMemory, nAmtToRead, &nAmtRead, NULL) ;
|
|
}
|
|
return (bSuccess && (nAmtRead == nAmtToRead)) ;
|
|
} // FileRead
|
|
|
|
|
|
BOOL
|
|
FileWrite (
|
|
HANDLE hFile,
|
|
void* lpMemory,
|
|
DWORD nAmtToWrite)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
DWORD nAmtWritten = 0;
|
|
DWORD dwFileSizeLow, dwFileSizeHigh;
|
|
LONGLONG llResultSize;
|
|
|
|
if ( NULL != hFile
|
|
&& NULL != lpMemory ) {
|
|
|
|
dwFileSizeLow = GetFileSize (hFile, &dwFileSizeHigh);
|
|
// limit file size to 2GB
|
|
|
|
if (dwFileSizeHigh > 0) {
|
|
SetLastError (ERROR_WRITE_FAULT);
|
|
bSuccess = FALSE;
|
|
} else {
|
|
// note that the error return of this function is 0xFFFFFFFF
|
|
// since that is > the file size limit, this will be interpreted
|
|
// as an error (a size error) so it's accounted for in the following
|
|
// test.
|
|
llResultSize = dwFileSizeLow + nAmtToWrite;
|
|
if (llResultSize >= 0x80000000) {
|
|
SetLastError (ERROR_WRITE_FAULT);
|
|
bSuccess = FALSE;
|
|
} else {
|
|
// write buffer to file
|
|
bSuccess = WriteFile (hFile, lpMemory, nAmtToWrite, &nAmtWritten, NULL) ;
|
|
if (bSuccess)
|
|
bSuccess = (nAmtWritten == nAmtToWrite ? TRUE : FALSE);
|
|
if ( !bSuccess ) {
|
|
SetLastError (ERROR_WRITE_FAULT);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
assert ( FALSE );
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return (bSuccess) ;
|
|
|
|
} // FileWrite
|
|
|
|
// This routine extract the filename portion from a given full-path filename
|
|
LPTSTR
|
|
ExtractFileName ( LPTSTR pFileSpec )
|
|
{
|
|
LPTSTR pFileName = NULL ;
|
|
TCHAR DIRECTORY_DELIMITER1 = TEXT('\\') ;
|
|
TCHAR DIRECTORY_DELIMITER2 = TEXT(':') ;
|
|
|
|
assert ( NULL != pFileSpec );
|
|
if ( pFileSpec ) {
|
|
pFileName = pFileSpec + lstrlen (pFileSpec) ;
|
|
|
|
while (*pFileName != DIRECTORY_DELIMITER1 &&
|
|
*pFileName != DIRECTORY_DELIMITER2) {
|
|
if (pFileName == pFileSpec) {
|
|
// done when no directory delimiter is found
|
|
break ;
|
|
}
|
|
pFileName-- ;
|
|
}
|
|
|
|
if (*pFileName == DIRECTORY_DELIMITER1
|
|
|| *pFileName == DIRECTORY_DELIMITER2) {
|
|
|
|
// directory delimiter found, point the
|
|
// filename right after it
|
|
pFileName++ ;
|
|
}
|
|
}
|
|
return pFileName ;
|
|
} // ExtractFileName
|
|
|
|
// CWaitCursor class
|
|
|
|
CWaitCursor::CWaitCursor()
|
|
: m_hcurWaitCursorRestore ( NULL )
|
|
{
|
|
DoWaitCursor(1);
|
|
}
|
|
|
|
CWaitCursor::~CWaitCursor()
|
|
{
|
|
DoWaitCursor(-1);
|
|
}
|
|
|
|
void
|
|
CWaitCursor::DoWaitCursor(INT nCode)
|
|
{
|
|
// 1=> begin, -1=> end
|
|
assert(nCode == 1 || nCode == -1);
|
|
|
|
if ( 1 == nCode )
|
|
{
|
|
m_hcurWaitCursorRestore = SetHourglassCursor();
|
|
} else {
|
|
if ( NULL != m_hcurWaitCursorRestore ) {
|
|
SetCursor(m_hcurWaitCursorRestore);
|
|
} else {
|
|
SetArrowCursor();
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
LoadDefaultLogFileFolder(
|
|
LPTSTR szFolder,
|
|
INT* piBufLen )
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
HKEY hKey = NULL;
|
|
DWORD dwDataType;
|
|
DWORD dwBufferSize = 0;
|
|
TCHAR* szNewStringBuffer = NULL;
|
|
|
|
assert ( NULL != szFolder );
|
|
assert ( NULL != piBufLen );
|
|
|
|
if ( NULL != szFolder
|
|
&& NULL != piBufLen ) {
|
|
|
|
dwStatus = RegOpenKey (
|
|
HKEY_LOCAL_MACHINE,
|
|
_T("System\\CurrentControlSet\\Services\\SysmonLog"),
|
|
&hKey );
|
|
|
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|
|
|
dwDataType = 0;
|
|
|
|
// Determine the size of the required buffer.
|
|
dwStatus = RegQueryValueExW (
|
|
hKey,
|
|
_T("DefaultLogFileFolder"),
|
|
NULL,
|
|
&dwDataType,
|
|
NULL,
|
|
&dwBufferSize);
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
if (dwBufferSize > 0) {
|
|
|
|
szNewStringBuffer = new TCHAR[dwBufferSize / sizeof(WCHAR)];
|
|
if ( NULL != szNewStringBuffer ) {
|
|
*szNewStringBuffer = _T ('\0');
|
|
|
|
dwStatus = RegQueryValueEx(
|
|
hKey,
|
|
_T("DefaultLogFileFolder"),
|
|
NULL,
|
|
&dwDataType,
|
|
(LPBYTE) szNewStringBuffer,
|
|
(LPDWORD) &dwBufferSize );
|
|
|
|
} else {
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
}
|
|
} else {
|
|
dwStatus = ERROR_NO_DATA;
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
if ( *piBufLen >= (INT)(dwBufferSize / sizeof(WCHAR)) ) {
|
|
lstrcpy ( szFolder, szNewStringBuffer );
|
|
} else {
|
|
dwStatus = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
*piBufLen = dwBufferSize / sizeof(WCHAR);
|
|
}
|
|
if ( NULL != szNewStringBuffer )
|
|
delete szNewStringBuffer;
|
|
} else {
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AreSameCounterPath (
|
|
PPDH_COUNTER_PATH_ELEMENTS pFirst,
|
|
PPDH_COUNTER_PATH_ELEMENTS pSecond )
|
|
{
|
|
BOOL bSame = FALSE;
|
|
|
|
assert ( NULL != pFirst && NULL != pSecond );
|
|
|
|
if ( NULL != pFirst && NULL != pSecond ) {
|
|
|
|
if ( 0 == lstrcmpi ( pFirst->szMachineName, pSecond->szMachineName ) ) {
|
|
if ( 0 == lstrcmpi ( pFirst->szObjectName, pSecond->szObjectName ) ) {
|
|
if ( 0 == lstrcmpi ( pFirst->szInstanceName, pSecond->szInstanceName ) ) {
|
|
if ( 0 == lstrcmpi ( pFirst->szParentInstance, pSecond->szParentInstance ) ) {
|
|
if ( pFirst->dwInstanceIndex == pSecond->dwInstanceIndex ) {
|
|
if ( 0 == lstrcmpi ( pFirst->szCounterName, pSecond->szCounterName ) ) {
|
|
bSame = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return bSame;
|
|
};
|
|
|
|
BOOL
|
|
DisplaySingleLogSampleValue ( void )
|
|
{
|
|
long nErr;
|
|
HKEY hKey = NULL;
|
|
DWORD dwRegValue;
|
|
DWORD dwDataType;
|
|
DWORD dwDataSize;
|
|
DWORD dwDisposition;
|
|
|
|
static INT siInitialized; // Initialized to 0
|
|
static BOOL sbSingleValue; // Initialized to 0 ( FALSE )
|
|
|
|
// check registry setting to see if thousands separator is enabled
|
|
if ( 0 == siInitialized ) {
|
|
nErr = RegOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
_T("Software\\Microsoft\\SystemMonitor"),
|
|
&hKey );
|
|
|
|
if( ERROR_SUCCESS != nErr ) {
|
|
nErr = RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
_T("Software\\Microsoft\\SystemMonitor"),
|
|
0,
|
|
_T("REG_DWORD"),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition );
|
|
}
|
|
|
|
dwRegValue = 0;
|
|
if ( ERROR_SUCCESS == nErr ) {
|
|
|
|
dwDataSize = sizeof(DWORD);
|
|
nErr = RegQueryValueExW (
|
|
hKey,
|
|
_T("DisplaySingleLogSampleValue"),
|
|
NULL,
|
|
&dwDataType,
|
|
(LPBYTE) &dwRegValue,
|
|
(LPDWORD) &dwDataSize );
|
|
|
|
if ( ERROR_SUCCESS == nErr
|
|
&& REG_DWORD == dwDataType
|
|
&& sizeof(DWORD) == dwDataSize )
|
|
{
|
|
if ( 0 != dwRegValue ) {
|
|
sbSingleValue = TRUE;
|
|
}
|
|
}
|
|
siInitialized = 1;
|
|
}
|
|
|
|
if ( NULL != hKey ) {
|
|
nErr = RegCloseKey( hKey );
|
|
}
|
|
}
|
|
|
|
return sbSingleValue;
|
|
}
|
|
|
|
DWORD
|
|
FormatSqlDataSourceName (
|
|
LPCWSTR szSqlDsn,
|
|
LPCWSTR szSqlLogSetName,
|
|
LPWSTR szSqlDataSourceName,
|
|
ULONG* pulBufLen )
|
|
{
|
|
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
ULONG ulNameLen;
|
|
|
|
if ( NULL != pulBufLen ) {
|
|
ulNameLen =
|
|
lstrlen (szSqlDsn)
|
|
+ lstrlen(szSqlLogSetName)
|
|
+ 5 // SQL:<DSN>!<LOGSET>
|
|
+ 2; // 2 NULL characters at the end;
|
|
|
|
if ( ulNameLen <= *pulBufLen ) {
|
|
if ( NULL != szSqlDataSourceName ) {
|
|
ZeroMemory(szSqlDataSourceName, (ulNameLen * sizeof(WCHAR)));
|
|
swprintf (
|
|
szSqlDataSourceName,
|
|
cszSqlDataSourceFormat,
|
|
szSqlDsn,
|
|
szSqlLogSetName );
|
|
}
|
|
} else if ( NULL != szSqlDataSourceName ) {
|
|
dwStatus = ERROR_MORE_DATA;
|
|
}
|
|
*pulBufLen = ulNameLen;
|
|
} else {
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
assert ( FALSE );
|
|
}
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DisplayDataSourceError (
|
|
HWND hwndOwner,
|
|
DWORD dwErrorStatus,
|
|
INT iDataSourceType,
|
|
LPCWSTR szLogFileName,
|
|
LPCWSTR szSqlDsn,
|
|
LPCWSTR szSqlLogSetName )
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
LPWSTR szMessage = NULL;
|
|
LPWSTR szDataSource = NULL;
|
|
ULONG ulMsgBufLen = 0;
|
|
TCHAR szSystemMessage[MAX_PATH];
|
|
|
|
// todo: Alloc message buffers
|
|
|
|
if ( sysmonLogFiles == iDataSourceType ) {
|
|
if ( NULL != szLogFileName ) {
|
|
ulMsgBufLen = lstrlen ( szLogFileName ) +1;
|
|
szDataSource = new WCHAR [ulMsgBufLen];
|
|
if ( NULL != szDataSource ) {
|
|
lstrcpy ( szDataSource, szLogFileName );
|
|
} else {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
assert ( FALSE );
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} else if ( sysmonSqlLog == iDataSourceType ){
|
|
if ( NULL != szSqlDsn && NULL != szSqlLogSetName ) {
|
|
|
|
FormatSqlDataSourceName (
|
|
szSqlDsn,
|
|
szSqlLogSetName,
|
|
NULL,
|
|
&ulMsgBufLen );
|
|
szDataSource = new WCHAR [ulMsgBufLen];
|
|
if ( NULL != szDataSource ) {
|
|
FormatSqlDataSourceName (
|
|
szSqlDsn,
|
|
szSqlLogSetName,
|
|
(LPWSTR)szDataSource,
|
|
&ulMsgBufLen );
|
|
|
|
// todo: check status
|
|
} else {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
assert ( FALSE );
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
assert ( FALSE );
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == dwStatus ) {
|
|
ulMsgBufLen += RESOURCE_STRING_BUF_LEN;
|
|
ulMsgBufLen += MAX_PATH;
|
|
szMessage = new WCHAR [ulMsgBufLen];
|
|
if ( NULL != szMessage ) {
|
|
if ( SMON_STATUS_TOO_FEW_SAMPLES == dwErrorStatus ) {
|
|
_stprintf ( szMessage, ResourceString(IDS_TOO_FEW_SAMPLES_ERR), szDataSource );
|
|
} else if ( SMON_STATUS_LOG_FILE_SIZE_LIMIT == dwErrorStatus ) {
|
|
_stprintf ( szMessage, ResourceString(IDS_LOG_FILE_TOO_LARGE_ERR), szDataSource );
|
|
} else {
|
|
_stprintf ( szMessage, ResourceString(IDS_BADDATASOURCE_ERR), szDataSource );
|
|
FormatSystemMessage ( dwErrorStatus, szSystemMessage, MAX_PATH - 1 );
|
|
lstrcat ( szMessage, szSystemMessage );
|
|
}
|
|
|
|
MessageBox(
|
|
hwndOwner,
|
|
szMessage,
|
|
ResourceString(IDS_APP_NAME),
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
|
|
if ( NULL != szDataSource ) {
|
|
delete szDataSource;
|
|
}
|
|
|
|
if ( NULL != szMessage ) {
|
|
delete szMessage;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|