gecko-dev/cmd/winfe/fegrid.cpp
1998-03-28 02:44:41 +00:00

2804 lines
79 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "stdafx.h"
#include "gridedge.h"
#include "netsvw.h"
#include "template.h"
#define VIEW_SOURCE_TARGET_WINDOW_NAME "%ViewSourceWindow" /* from ns/lib/libnet/cvcolor.c */
MWContext *FE_MakeGridWindow(MWContext *pOldContext, void *hist_list, void *pHistory,
int32 lX, int32 lY,
int32 lWidth, int32 lHeight, char *pUrlStr, char *pWindowName, int8 iScrollType,
NET_ReloadMethod eReloadThis, Bool no_edge) {
// First, ensure that the context we're going into is of an appropriate type.
if(pOldContext == NULL || ABSTRACTCX(pOldContext)->IsFrameContext() == FALSE) {
// Only let this happen to window contexts for now.
return(NULL);
}
else {
// The goal here is to create a new, fabulous, grid that is a child of the
// other window context's frame.
CWinCX *pParentCX = VOID2CX(pOldContext->fe.cx, CWinCX);
// Safety dance.
if(pParentCX->GetPane() == NULL) {
return(NULL);
}
HWND hParentWnd = pParentCX->GetPane();
// Bring up a create context, so that the Create call won't complain on
// 16 bit windows.
// Since we create the context here, and the document, along with the view,
// the view takes care of destroying the docuemnt on close, so we don't
// need to worry about it.
CCreateContext cccGrid;
cccGrid.m_pNewViewClass = RUNTIME_CLASS(CNetscapeView);
cccGrid.m_pCurrentDoc = new CGenericDoc();
// Create the view.
DWORD dwGridStyle = WS_HSCROLL | WS_VSCROLL;
CNetscapeView *pNewView = new CNetscapeView();
pNewView->Create(NULL,
pWindowName,
dwGridStyle,
CRect(0, 0, 1, 1),
CWnd::FromHandle(hParentWnd),
0,
&cccGrid);
CWinCX *pWinCX = new CWinCX((CGenericDoc *)cccGrid.m_pCurrentDoc, pParentCX->GetFrame(), pNewView);
// Set the context's name.
// Set its parent.
pWinCX->SetContextName(pWindowName);
pWinCX->SetParentContext(pOldContext);
RECT rect;
rect.left = CASTINT(pParentCX->Twips2PixX(lX));
rect.top = CASTINT(pParentCX->Twips2PixY(lY));
rect.right = CASTINT(pParentCX->Twips2PixX(lX) + pParentCX->Twips2PixX(lWidth));
rect.bottom = CASTINT(pParentCX->Twips2PixY(lY) + pParentCX->Twips2PixY(lHeight));
// Initialize the context.
pWinCX->Initialize(pWinCX->CDCCX::IsOwnDC(), &rect);
// Tell it wether or not it will have an edge (border in the
// non client area).
pWinCX->SetBorder(!no_edge);
// Size the window to final coords.
// This causes the non client calc to happen which is needed
// now that it knows it's a grid cell.
pNewView->MoveWindow(
CRect(CASTINT(pParentCX->Twips2PixX(lX)),
CASTINT(pParentCX->Twips2PixY(lY)),
CASTINT(pParentCX->Twips2PixX(lX) + pParentCX->Twips2PixX(lWidth)),
CASTINT(pParentCX->Twips2PixY(lY) + pParentCX->Twips2PixY(lHeight))),
FALSE);
// Decide what we're doing about scroll bars.
switch(iScrollType) {
case LO_SCROLL_NO:
// Shouldn't ever have scrollbars.
// Get rid of them.
pWinCX->SetDynamicScrollBars(FALSE);
pWinCX->ShowScrollBars(SB_BOTH, FALSE);
pWinCX->SetAlwaysShowScrollBars(FALSE);
break;
case LO_SCROLL_AUTO:
// Aha, the hard case.
// Set a flag so that when the load is complete in the context, such
// that we will hide the scroll bars if there is already enough room.
// This means that the entire document fits on the screen (not much data),
// and that doing a load from resize at that point will be minimal
// overhead.
pWinCX->SetDynamicScrollBars(TRUE);
pWinCX->SetAlwaysShowScrollBars(FALSE);
break;
case LO_SCROLL_YES:
// Have the scroll bars show.
pWinCX->SetDynamicScrollBars(FALSE);
pWinCX->SetAlwaysShowScrollBars(TRUE);
pWinCX->ShowScrollBars(SB_BOTH, TRUE);
break;
default:
ASSERT(0); // user mush pass in invalid value.
}
// If we have a history list, we need to stick it in the context.
History_entry *pHistEnt = (History_entry *)pHistory;
XP_List *pHistList = (XP_List *)hist_list;
if(pHistList != NULL) {
pWinCX->GetContext()->hist.list_ptr = pHistList;
}
else {
// If we have a history entry, we need to add it to the session.
if(pHistEnt != NULL) {
SHIST_AddDocument(pWinCX->GetContext(), pHistEnt);
}
}
// Have it load the url in question.
// This could be from the history entry.
if(pHistEnt == NULL) {
URL_Struct *pUrl = NET_CreateURLStruct(pUrlStr, NET_DONT_RELOAD);
pUrl->force_reload = eReloadThis;
// Be sure to add the referrer field of the top level context.
MWContext *mwRefer = pOldContext;
while(mwRefer->grid_parent) {
mwRefer = mwRefer->grid_parent;
}
History_entry *he = SHIST_GetCurrent (&mwRefer->hist);
if(he && he->referer) {
pUrl->referer = XP_STRDUP(he->referer);
}
pWinCX->GetUrl(pUrl, FO_CACHE_AND_PRESENT);
}
else {
URL_Struct *pUrl = SHIST_CreateURLStructFromHistoryEntry(pWinCX->GetContext(), pHistEnt);
pUrl->force_reload = eReloadThis;
pWinCX->GetUrl(pUrl, FO_CACHE_AND_PRESENT);
}
// Grid parents have WS_CLIPCHILDREN turned on. This allows them
// to draw (backgrounds for example) into their windows without
// worrying about their children.
CFrameGlue *pGlue = pWinCX->GetFrame();
if(pGlue) {
pGlue->ClipChildren(pNewView, TRUE);
}
// Show the window, but don't activate it.
pNewView->ShowWindow(SW_SHOWNA);
return(pWinCX->GetContext());
}
}
void FE_LoadGridCellFromHistory(MWContext *pContext, void *hist, NET_ReloadMethod netReloadMethod) {
History_entry *pHist = (History_entry *)hist;
if (pHist != NULL) {
URL_Struct *pUrl = SHIST_CreateURLStructFromHistoryEntry(pContext, pHist);
if(pUrl) {
pUrl->force_reload = netReloadMethod;
ABSTRACTCX(pContext)->GetUrl(pUrl, FO_CACHE_AND_PRESENT, TRUE);
}
}
}
void *FE_FreeGridWindow(MWContext *pContext, XP_Bool bSaveHistory) {
ASSERT(ABSTRACTCX(pContext)->IsWindowContext());
void *pRetval = NULL;
// Destroy the view then the doc/it in turn destroys the context.
// We have to clean up the doc, since we passed it in....
CWinCX *pWinCX = VOID2CX(pContext->fe.cx, CWinCX);
CWinCX *pParentCX = WINCX(pWinCX->GetParentContext());
// We may want to return the history entry.
if(bSaveHistory == TRUE) {
// Reset to top of document
SHIST_SetPositionOfCurrentDoc(&(pWinCX->GetContext()->hist), 0);
if(pWinCX->GetOriginX() || pWinCX->GetOriginY()) {
#ifdef LAYERS
LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(pWinCX->GetContext(), pWinCX->GetOriginX(), pWinCX->GetOriginY(), NULL);
#else
LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(pWinCX->GetContext(), pWinCX->GetOriginX(), pWinCX->GetOriginY());
#endif
// Save the location of the current document.
if(pAny != NULL) {
SHIST_SetPositionOfCurrentDoc(&(pWinCX->GetContext()->hist), pAny->ele_id);
}
}
LO_DiscardDocument(pWinCX->GetContext());
XP_List *hist_list = pWinCX->GetContext()->hist.list_ptr;
pWinCX->GetContext()->hist.list_ptr = NULL;
pRetval = (void *)hist_list;
}
CFrameGlue *frame = pWinCX->GetFrame();
// Make sure child grid cell going away doesn't hold onto frame
// which may also be going down.
pWinCX->ClearFrame();
ASSERT(pWinCX->GetPane());
if(pWinCX->GetPane()) {
CGenericView *pView = pWinCX->GetView();
ASSERT(pView);
if(pView) {
// Tell our parent(s) that they don't need to clip children
// anymore just for our sake.
if(frame) {
frame->ClipChildren(pView, FALSE);
}
pView->FrameClosing();
pView->SendMessage(WM_CLOSE);
}
}
return(pRetval);
}
void FE_GetFullWindowSize(MWContext *pContext, int32 *plWidth, int32 *plHeight) {
// Only do this on windows.
if(ABSTRACTCX(pContext)->IsWindowContext() == TRUE && ABSTRACTCX(pContext)->IsDestroyed() == FALSE) {
CPaneCX *pWindow = PANECX(pContext);
RECT crDimensions;
// Get the full size of the window.
::GetClientRect(pWindow->GetPane(), &crDimensions);
// Convert the dimensions to twips.
HDC hDC = pWindow->GetContextDC();
::DPtoLP(hDC, (POINT *)&crDimensions, 2);
pWindow->ReleaseContextDC(hDC);
*plWidth = crDimensions.right - crDimensions.left;
*plHeight = crDimensions.bottom - crDimensions.top;
// Adjust to not include scroll bars.
if(pWindow->IsVScrollBarOn()) {
*plWidth += sysInfo.m_iScrollWidth;
}
if(pWindow->IsHScrollBarOn()) {
*plHeight += sysInfo.m_iScrollHeight;
}
}
else {
// No window here....
// Set to 1 to avoid divide by zero errors in Back end.
*plHeight = *plWidth = 1;
}
}
void FE_RestructureGridWindow(MWContext *pContext, int32 lX, int32 lY, int32 lWidth, int32 lHeight) {
TRACE("FE_RestructureGridWindow(%p, %ld, %ld, %ld, %ld)\n", pContext, lX, lY, lWidth, lHeight);
// Safety dance.
if(pContext == NULL) {
return;
}
// We're under the immediate assumption that the context is a window.
ASSERT(ABSTRACTCX(pContext)->IsWindowContext());
CWinCX *pWinCX = WINCX(pContext);
// We need to move the window.
// It will automagically redraw itself.
::MoveWindow(pWinCX->GetPane(), CASTINT(pWinCX->Twips2PixX(lX)),
CASTINT(pWinCX->Twips2PixY(lY)),
CASTINT(pWinCX->Twips2PixX(lWidth)),
CASTINT(pWinCX->Twips2PixY(lHeight)),
TRUE);
// Dynamic scroll bars are handled internally, as is resize.
}
void FE_SetWindowLoading(MWContext *pContext, URL_Struct *pUrl, Net_GetUrlExitFunc **ppExitRoutine) {
// A url load is changing context.
// Telling the exit routine that we'd like to be called.
*ppExitRoutine = CFE_GetUrlExitRoutine;
// Now, call the GetUrl routine, but don't really load.
// This bootstraps the normal loading procedure.
// DON'T REALLY CARE WHAT WE PASS IN AS THE PRESENTATION TYPE, yet.
ABSTRACTCX(pContext)->GetUrl(pUrl, FO_CACHE_AND_PRESENT, FALSE);
}
void FE_GetEdgeMinSize(MWContext *pContext, int32 *pSize, Bool no_edge) {
TRACE("FE_GetEdgeMinSize(%p, %p)\n", pContext, pSize);
// Don't care anymore.
*pSize = 5;
if(!no_edge) {
*pSize = 5;
}
}
MWContext *FE_MakeBlankWindow(MWContext *pOldContext, URL_Struct *pUrl, char *pContextName) {
// TRACE("FE_MakeBlankWindow(%p, %p, %s)\n", pOldContext, pUrl, pContextName);
// Create a new top level blank window.
// Only don't load anything. Leave it blank.
// HACK ALERT:
// In order to better do this, we need to have the CreateNewDocWindow
// function not load what's in the history. It only does this with
// other browser windows. Anyhow, switch our context type temporarily
// in order to get the effect.
MWContextType OldType = pOldContext->type;
pOldContext->type = (MWContextType)-1;
MWContext *pRetval = pOldContext->funcs->CreateNewDocWindow(pOldContext, NULL);
pOldContext->type = OldType;
if(pRetval != NULL) {
ABSTRACTCX(pRetval)->SetContextName(pContextName);
}
return(pRetval);
}
// Create a new window.
// If pChrome is NULL, do a FE_MakeBlankWindow....
// pChrome specifies the attributes of a window.
// If you use this call, Toolbar information will not be saved in the preferences.
MWContext *FE_MakeNewWindow(MWContext *pOldContext, URL_Struct *pUrl, char *pContextName, Chrome *pChrome)
{
BOOL bNetHelpWnd = FALSE;
// Decide which type of context this will be (we use this to possible access some templates).
MWContextType cxType = MWContextAny;
if(pChrome != NULL) {
switch(pChrome->type) {
case MWContextHTMLHelp:
pChrome->type = MWContextBrowser;
#ifndef _WIN32
pChrome->allow_resize = FALSE;
#endif
bNetHelpWnd = TRUE;
// Fall through...
case MWContextBrowser:
cxType = MWContextBrowser;
break;
case MWContextDialog:
cxType = MWContextDialog;
break;
}
}
else {
// Default to MWContextBrowser;
cxType = MWContextBrowser;
}
// A type came in that we're not ready to handle.
// Seems more code needs to be written....
ASSERT(cxType != MWContextAny);
if(cxType == MWContextAny) {
return(NULL);
}
// Decide now wether or not to make the window initially visible.
// We decide by detecting wether or not we'll be enforcing a resize.
// We'll make the window visible after we're done sizing.
// Only works with 32 bits right now.
BOOL bMakeVisible = TRUE;
if(pChrome && ((pChrome->outw_hint && pChrome->outh_hint) ||
(pChrome->w_hint && pChrome->h_hint) ||
pChrome->location_is_chrome ||
pChrome->topmost || pChrome->bottommost)) {
bMakeVisible = FALSE;
}
// Must check if user wants a titlebar now since it affects the type of
// window used during window creation. If no titlebar, use popup type.
BOOL bHideTitlebar = FALSE;
BOOL bBorder = TRUE;
if (pChrome && pChrome->hide_title_bar){
bHideTitlebar = TRUE;
}
BOOL bDependent = FALSE;
if (pOldContext && pChrome && pChrome->dependent) {
bDependent = TRUE;
}
// Take the template of the appropriate window type, and pull it up.
CAbstractCX *pCX = NULL;
// If there is a parent, get its hwnd
CWinCX *pOldWinCX = NULL;
if(pOldContext)
pOldWinCX = WINCX(pOldContext);
HWND hParentHwnd = NULL;
if(pOldWinCX && pOldWinCX->GetFrame() && pOldWinCX->GetFrame()->GetFrameWnd())
hParentHwnd = pOldWinCX->GetFrame()->GetFrameWnd()->GetSafeHwnd();
switch(cxType) {
case MWContextBrowser:
case MWContextDialog: {
BOOL bPopup = FALSE;
HWND hPopupParent = NULL;
// if we are creating a modal window then we need to become a child of
// the calling frame and of type WS_POPUP. The values below are set to
// tell the frame to create itself this way.
if(hParentHwnd && pChrome && pChrome->is_modal)
{
bPopup = TRUE;
hPopupParent = ::GetLastActivePopup(hParentHwnd);
}
CGenericDoc *pDoc =
(CGenericDoc *)theApp.m_ViewTmplate->OpenDocumentFile(NULL, bMakeVisible,
bHideTitlebar, bDependent, bPopup, hPopupParent);
if(pDoc != NULL) {
pCX = pDoc->GetContext();
}
}
break;
default:
// Please add your case statement.
ASSERT(0);
break;
}
// If the context wasn't created, we can not continue.
if(pCX == NULL) {
return(NULL);
}
// Hack to identify a NetHelp window
pCX->m_bNetHelpWnd = bNetHelpWnd;
// JavaScript can create windows which are lifetime-linked to their parent.
// This is set here instead of in JS to avoid threading problems.
if (bDependent) {
if (pOldContext->js_dependent_list == NULL)
pOldContext->js_dependent_list = XP_ListNew();
if (pOldContext->js_dependent_list == NULL)
return(NULL);
XP_ListAddObject(pOldContext->js_dependent_list, pCX->GetContext());
pCX->GetContext()->js_parent = pOldContext;
}
// Get the context, and manually assign its type.
// The XP context that is.
pCX->GetContext()->type = cxType;
// Assign the context name, if provided.
if(pContextName != NULL) {
pCX->SetContextName(pContextName);
}
// Copy over the same char set ID as the old context if we're a window.
if(pCX->IsFrameContext() == TRUE && pOldContext != NULL) {
CWinCX *pWinCX = VOID2CX(pCX, CWinCX);
if(cxType != MWContextDialog && !bNetHelpWnd) {
pWinCX->GetFrame()->m_iCSID = INTL_DefaultDocCharSetID(pOldContext);
} else {
// use the client's default encoding for HTML dialogs (fix for #78838)
pWinCX->GetFrame()->m_iCSID = INTL_CharSetNameToID(INTL_ResourceCharSet());
if (pContextName != NULL) {
if(strncmp(pContextName, VIEW_SOURCE_TARGET_WINDOW_NAME,
strlen(VIEW_SOURCE_TARGET_WINDOW_NAME)) == 0) {
// but not for View Source which gets the old context char set ID
// (fix for #79072)
pWinCX->GetFrame()->m_iCSID = INTL_DefaultDocCharSetID(pOldContext);
}
if(strncmp(pContextName, "%DocInfoWindow", 14) == 0) {
// %DocInfoWindow is from ns/lib/libnet/mkgeturl.c net_output_about_url()
// Document Info gets the user-selectable default encoding
pWinCX->GetFrame()->m_iCSID = INTL_DefaultWinCharSetID(NULL);
}
}
}
}
#ifdef _WIN32
if(sysInfo.m_bWin4 && bNetHelpWnd && pCX->IsFrameContext()) {
CWinCX *pWinCX = VOID2CX(pCX, CWinCX);
CFrameWnd *pFrame = pWinCX->GetFrame()->GetFrameWnd();
if( pFrame ) {
HICON hIcon = theApp.LoadIcon( "IDR_NETHELP_ICON" );
pFrame->SetIcon( hIcon, TRUE );
hIcon = (HICON)::LoadImage( AfxFindResourceHandle( "IDR_NETHELP_ICON", RT_GROUP_ICON ), "IDR_NETHELP_ICON", IMAGE_ICON,
GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), LR_SHARED );
pFrame->SetIcon( hIcon, FALSE );
}
}
#endif // _WIN32
// Pay special attention to the chrome attributes specified, if specified.
// If they aren't, attempt to use attributes from the old context passed in.
if(pChrome != NULL && pCX->IsFrameContext() == TRUE) {
CWinCX *pWinCX = VOID2CX(pCX, CWinCX);
LPCHROME pIChrome = pWinCX->GetFrame()->GetChrome();
if(pIChrome) {
// Url bar and directory buttons.
// make it so that we don't save toolbar information
pIChrome->SetSaveToolbarInfo(FALSE);
pIChrome->ShowToolbar(ID_LOCATION_TOOLBAR, pChrome->show_url_bar);
pIChrome->ShowToolbar(ID_PERSONAL_TOOLBAR, pChrome->show_directory_buttons);
pIChrome->ShowToolbar(ID_NAVIGATION_TOOLBAR, pChrome->show_button_bar);
// Status bar!
LPNSSTATUSBAR pIStatusBar = NULL;
pIChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
if ( pIStatusBar ) {
pIStatusBar->Show( pChrome->show_bottom_status_bar );
pIStatusBar->Release();
}
}
// Show the menu?
if(pChrome->show_menu == FALSE) {
CMenu *pMenu = pWinCX->GetFrame()->GetFrameWnd()->GetMenu();
HMENU hMenu = pMenu ? pMenu->m_hMenu : NULL;
pWinCX->GetFrame()->GetFrameWnd()->SetMenu(NULL);
if( hMenu && (theApp.m_ViewTmplate->m_hMenuShared != hMenu) )
{
pMenu->DestroyMenu();
}
}
// Need to recalc.
pWinCX->GetFrame()->GetFrameWnd()->RecalcLayout();
// Size, of all things, of the viewing area only....
// Doesn't account for menu wrap or unwrap when getting smaller/bigger.
if((pChrome->outw_hint && pChrome->outh_hint) ||
(pChrome->w_hint &&pChrome->h_hint) ||
pChrome->location_is_chrome ||
pChrome->topmost || pChrome->bottommost) {
int32 lLeft=0;
int32 lTop=0;
int32 lWidth=0;
int32 lHeight=0;
CRect crFrame;
pWinCX->GetFrame()->GetFrameWnd()->GetWindowRect(crFrame);
CRect crView;
::GetWindowRect(pWinCX->GetPane(), crView);
// Acount for the view border style.
crView.InflateRect(-1 * sysInfo.m_iBorderWidth, -1 * sysInfo.m_iBorderHeight);
int32 lWAdjust = pChrome->w_hint - (int32)crView.Width();
int32 lHAdjust = pChrome->h_hint - (int32)crView.Height();
if (pChrome->outw_hint>0 && pChrome->outh_hint>0) {
lWidth = pChrome->outw_hint;
lHeight = pChrome->outh_hint;
}
else if (pChrome->w_hint>0 && pChrome->h_hint>0) {
lWidth = (int32)crFrame.Width() + lWAdjust;
lHeight = (int32)crFrame.Height() + lHAdjust;
}
else {
lWidth = (int32)crFrame.Width();
lHeight = (int32)crFrame.Height();
}
if (pChrome->location_is_chrome) {
lLeft = pChrome->l_hint;
lTop = pChrome->t_hint;
}
else {
lLeft = (int32)crFrame.left;
lTop = (int32)crFrame.top;
}
//There is a security problem where the window size buffer can be
//overridden on Win95. Using arbitrary max window size of 10000
lWidth = lWidth > 10000 ? 10000 : lWidth;
lHeight = lHeight > 10000 ? 10000 : lHeight;
if (pChrome->topmost)
pWinCX->GetFrame()->GetFrameWnd()->SetWindowPos(&CWnd::wndTopMost, CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight), NULL);
else if (pChrome->bottommost)
pWinCX->GetFrame()->GetFrameWnd()->SetWindowPos(&CWnd::wndBottom, CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight), NULL);
else
pWinCX->GetFrame()->GetFrameWnd()->MoveWindow(CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight));
// Specific width and height information means that we should not save the sizes when closing down, regardless of context type.
pWinCX->m_bSizeIsChrome = TRUE;
}
// Set windows always on bottom.
pWinCX->SetZOrder(pChrome->z_lock, pChrome->bottommost);
// Modality.
if(pChrome->is_modal) {
// Inform the context of its special status.
pWinCX->GoModal(pOldContext);
}
// Scroll bars.
if(pChrome->show_scrollbar == FALSE) {
// Turn them off.
pWinCX->SetDynamicScrollBars(FALSE);
pWinCX->ShowScrollBars(SB_BOTH, FALSE);
pWinCX->SetAlwaysShowScrollBars(FALSE);
}
// Resize.
if(pChrome->allow_resize == FALSE) {
// Disable resize....
// This is a truly gross and unholy option.
pWinCX->EnableResize(FALSE);
}
// Hotkeys
if (pChrome->disable_commands) {
// Disable hotkeys
pWinCX->DisableHotkeys(TRUE);
}
// Close.
if(pChrome->allow_close == FALSE) {
// Disable closing....
// This is a truly gross and unholy option.
// This is reenabled in FE_DestroyContext regardless (i.e.
// can't be closed unless someone calls that API).
pWinCX->EnableClose(FALSE);
}
// Don't allow restricted target windows to be targeted
// by mail links and other functions which just grab
// the nearest Browser context.
if(pChrome->restricted_target)
pCX->GetContext()->restricted_target = TRUE;
// Close callback.
// Callback when the context is destroyed.
pWinCX->CloseCallback(pChrome->close_callback, pChrome->close_arg);
// History copy.
if(pChrome->copy_history && pOldContext != NULL) {
// Copy the old context's history.
SHIST_CopySession(pWinCX->GetContext(), pOldContext);
}
}
else if(cxType == MWContextBrowser && pCX->IsFrameContext() == TRUE) {
CWinCX *pWinCX = VOID2CX(pCX, CWinCX);
// See if the calling context is a window context, and if so, emulate its
// settings.
// Otherwise, just take what we have up....
if(pOldContext != NULL && pOldContext->type == MWContextBrowser) {
CWinCX *pOldCX = WINCX(pOldContext);
LPCHROME pIChrome = pWinCX->GetFrame()->GetChrome();
if(pIChrome) {
// Directory buttons, location box and all
// make it so that we don't save toolbar information
pIChrome->SetSaveToolbarInfo(FALSE);
pIChrome->SetToolbarStyle( theApp.m_pToolbarStyle );
pIChrome->ShowToolbar( ID_LOCATION_TOOLBAR, pOldCX->GetFrame()->m_bLocationBar );
pIChrome->ShowToolbar(ID_PERSONAL_TOOLBAR, pOldCX->GetFrame()->m_bStarter);
pIChrome->ShowToolbar(ID_NAVIGATION_TOOLBAR, pOldCX->GetFrame()->m_bShowToolbar);
}
}
}
// If a URL struct was passed in, load it as the last thing to do.
if(pUrl != NULL) {
int iFormatOut = FO_CACHE_AND_PRESENT;
switch(cxType) {
case MWContextBrowser:
case MWContextDialog:
iFormatOut = FO_CACHE_AND_PRESENT;
break;
default:
// May be a different format out depending on context type.
// Please set as appropriate!
ASSERT(0);
break;
}
pCX->GetUrl(pUrl, iFormatOut);
}
// If we hid the window earlier due to sizing information, time to make it come back.
if(pCX->IsFrameContext() == TRUE && !bMakeVisible) {
VOID2CX(pCX, CWinCX)->GetFrame()->GetFrameWnd()->ShowWindow(SW_SHOW);
}
// Return the XP context.
return(pCX->GetContext());
}
// Update current chrome in a context.
void FE_UpdateChrome(MWContext *pContext, Chrome *pChrome)
{
TRACE("FE_UpdateChrome(%p, %p)\n", pContext, pChrome);
// API fulfillments.
if(!pContext || !pChrome || !ABSTRACTCX(pContext) || !ABSTRACTCX(pContext)->IsFrameContext()) {
return;
}
CWinCX *pWinCX = WINCX(pContext);
if(!pWinCX->GetPane() || !pWinCX->GetFrame() || !pWinCX->GetFrame()->GetFrameWnd()) {
// Context isn't anatomically correct.
return;
}
LPCHROME pIChrome = pWinCX->GetFrame()->GetChrome();
if(pIChrome) {
// Url bar and directory buttons.
pIChrome->SetSaveToolbarInfo(FALSE);
pIChrome->ShowToolbar(ID_LOCATION_TOOLBAR, pChrome->show_url_bar );
pIChrome->ShowToolbar(ID_PERSONAL_TOOLBAR, pChrome->show_directory_buttons );
pIChrome->ShowToolbar(ID_NAVIGATION_TOOLBAR, pChrome->show_button_bar);
// Status bar!
LPNSSTATUSBAR pIStatusBar = NULL;
pIChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
if ( pIStatusBar ) {
pIStatusBar->Show( pChrome->show_bottom_status_bar );
pIStatusBar->Release();
}
}
// Show the menu?
if(pChrome->show_menu == FALSE) {
CMenu *pMenu = pWinCX->GetFrame()->GetFrameWnd()->GetMenu();
HMENU hMenu = pMenu ? pMenu->m_hMenu : NULL;
pWinCX->GetFrame()->GetFrameWnd()->SetMenu(NULL);
if( hMenu && (theApp.m_ViewTmplate->m_hMenuShared != hMenu) )
{
pMenu->DestroyMenu();
}
}
else {
// Get the menu back out of the template.
CMenu *pMenu = pWinCX->GetFrame()->GetFrameWnd()->GetMenu();
HMENU hMenu = pMenu ? pMenu->m_hMenu : NULL;
::SetMenu(pWinCX->GetFrame()->GetFrameWnd()->GetSafeHwnd(), theApp.m_ViewTmplate->m_hMenuShared);
if( hMenu && (theApp.m_ViewTmplate->m_hMenuShared != hMenu) )
{
pMenu->DestroyMenu();
}
}
// Need to recalc.
pWinCX->GetFrame()->GetFrameWnd()->RecalcLayout();
// Size, of all things, of the viewing area only....
// Doesn't account for menu wrap or unwrap when getting smaller/bigger.
if((pChrome->outw_hint && pChrome->outh_hint) ||
(pChrome->w_hint &&pChrome->h_hint) ||
pChrome->location_is_chrome ||
pChrome->topmost || pChrome->bottommost) {
int32 lLeft=0;
int32 lTop=0;
int32 lWidth=0;
int32 lHeight=0;
CRect crFrame;
pWinCX->GetFrame()->GetFrameWnd()->GetWindowRect(crFrame);
CRect crView;
::GetWindowRect(pWinCX->GetPane(), crView);
// Acount for the view border style.
crView.InflateRect(-1 * sysInfo.m_iBorderWidth, -1 * sysInfo.m_iBorderHeight);
int32 lWAdjust = pChrome->w_hint - (int32)crView.Width();
int32 lHAdjust = pChrome->h_hint - (int32)crView.Height();
if (pChrome->outw_hint>0 && pChrome->outh_hint>0) {
lWidth = pChrome->outw_hint;
lHeight = pChrome->outh_hint;
}
else if (pChrome->w_hint>0 && pChrome->h_hint>0) {
lWidth = (int32)crFrame.Width() + lWAdjust;
lHeight = (int32)crFrame.Height() + lHAdjust;
}
else {
lWidth = (int32)crFrame.Width();
lHeight = (int32)crFrame.Height();
}
if (pChrome->location_is_chrome) {
lLeft = pChrome->l_hint;
lTop = pChrome->t_hint;
}
else {
lLeft = (int32)crFrame.left;
lTop = (int32)crFrame.top;
}
//There is a security problem where the window size buffer can be
//overridden on Win95. Using arbitrary max window size of 10000
lWidth = lWidth > 10000 ? 10000 : lWidth;
lHeight = lHeight > 10000 ? 10000 : lHeight;
if (pChrome->topmost)
pWinCX->GetFrame()->GetFrameWnd()->SetWindowPos(&CWnd::wndTopMost, CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight), NULL);
else if (pChrome->bottommost)
pWinCX->GetFrame()->GetFrameWnd()->SetWindowPos(&CWnd::wndBottom, CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight), NULL);
else
pWinCX->GetFrame()->GetFrameWnd()->MoveWindow(CASTINT(lLeft), CASTINT(lTop), CASTINT(lWidth), CASTINT(lHeight));
// Specific width and height information means that we should not save the sizes when closing down, regardless of context type.
pWinCX->m_bSizeIsChrome = TRUE;
}
// Set windows always on bottom.
pWinCX->SetZOrder(pChrome->z_lock, pChrome->bottommost);
// Hotkeys
pWinCX->DisableHotkeys(pChrome->disable_commands);
// Scroll bars.
if(pChrome->show_scrollbar == FALSE) {
// Turn them off.
pWinCX->SetDynamicScrollBars(FALSE);
pWinCX->ShowScrollBars(SB_BOTH, FALSE);
pWinCX->SetAlwaysShowScrollBars(FALSE);
}
else {
pWinCX->SetDynamicScrollBars(TRUE);
pWinCX->RealizeScrollBars();
}
// Resize.
// This is a truly gross and unholy option.
pWinCX->EnableResize(pChrome->allow_resize);
// Close.
// This is a truly gross and unholy option.
// This is reenabled in FE_DestroyContext regardless (i.e.
// can't be closed unless someone calls that API).
// This also sets the closing attributes of all child contexts.
pWinCX->EnableClose(pChrome->allow_close);
// Close callback.
// Callback when the context is destroyed.
pWinCX->CloseCallback(pChrome->close_callback, pChrome->close_arg);
// We don't handle modality, as there is no parent context passed in.
}
// Query current chrome in a context.
void FE_QueryChrome(MWContext *pContext, Chrome *pChrome)
{
TRACE("FE_QueryChrome(%p, %p)\n", pContext, pChrome);
// API fulfillments.
if(!pContext || !pChrome || !ABSTRACTCX(pContext) || !ABSTRACTCX(pContext)->IsFrameContext()) {
return;
}
CWinCX *pWinCX = WINCX(pContext);
if(!pWinCX->GetPane() || !pWinCX->GetDocument() || !pWinCX->GetFrame() || !pWinCX->GetFrame()->GetFrameWnd()) {
// Context isn't anatomically correct.
return;
}
// Clear the chrome struct, we'll refill in the relevant parts.
memset((void *)pChrome, 0, sizeof(Chrome));
LPCHROME pIChrome = pWinCX->GetFrame()->GetChrome();
if(pIChrome) {
// Toolbar on or off?
pChrome->show_button_bar = pIChrome->GetToolbarVisible(ID_NAVIGATION_TOOLBAR);
// Url bar and directory buttons.
pChrome->show_url_bar = pIChrome->GetToolbarVisible(ID_LOCATION_TOOLBAR);
pChrome->show_directory_buttons = pIChrome->GetToolbarVisible(ID_PERSONAL_TOOLBAR);
// The security bar?
// TODO: Fix me!
pChrome->show_security_bar = TRUE;
// Status bar!
LPNSSTATUSBAR pIStatusBar = NULL;
pIChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
if ( pIStatusBar ) {
HWND hWnd = pIStatusBar->GetHWnd();
pIStatusBar->Release();
pChrome->show_bottom_status_bar = IsWindowVisible( hWnd );
}
}
// Show the menu?
pChrome->show_menu = pWinCX->GetFrame()->GetFrameWnd()->GetMenu() == NULL ? FALSE : TRUE;
// Size, of all things, of the viewing area only....
// Acount for the view border style, too.
CRect crView;
::GetWindowRect(pWinCX->GetPane(), crView);
CRect crFrame;
pWinCX->GetFrame()->GetFrameWnd()->GetWindowRect(crFrame);
crView.InflateRect(-1 * sysInfo.m_iBorderWidth, -1 * sysInfo.m_iBorderHeight);
pChrome->outw_hint = (int32)crFrame.Width();
pChrome->outh_hint = (int32)crFrame.Height();
pChrome->w_hint = (int32)crView.Width();
pChrome->h_hint = (int32)crView.Height();
pChrome->l_hint = (int32)crFrame.left;
pChrome->t_hint = (int32)crFrame.top;
//Set to make sure the coords given are used.
pChrome->location_is_chrome= TRUE;
// Scroll bars.
pChrome->show_scrollbar = pWinCX->DynamicScrollBars();
// Resize.
// This is a truly gross and unholy option.
pChrome->allow_resize = ((CGenericFrame *)pWinCX->GetFrame()->GetFrameWnd())->CanResize();
// Hotkeys.
pChrome->disable_commands = ((CGenericFrame *)pWinCX->GetFrame()->GetFrameWnd())->HotkeysDisabled();
// ZLocked.
pChrome->z_lock = ((CGenericFrame *)pWinCX->GetFrame()->GetFrameWnd())->IsZOrderLocked();
// Bottommost.
pChrome->bottommost = ((CGenericFrame *)pWinCX->GetFrame()->GetFrameWnd())->IsBottommost();
// Close.
// This is a truly gross and unholy option.
// This will only report if the current context and its children can close, not if
// the actual frame can close if this context has a parent.
pChrome->allow_close = pWinCX->GetDocument()->CanClose();
// Close callback is not handled correctly, as there may be multiples.
// We don't handle modality, as there is no parent context passed in to check against.
}
// Destroy a window/context.
void FE_DestroyWindow(MWContext *pContext)
{
TRACE("FE_DestroyWindow(%p)\n", pContext);
ASSERT(pContext);
if(pContext != NULL) {
// Make sure that this is a CWinCX.
ASSERT(ABSTRACTCX(pContext)->IsFrameContext());
if(ABSTRACTCX(pContext)->IsWindowContext()) {
CWinCX *pCX = WINCX(pContext);
// Make sure there's a frame to close.
if(pCX->GetFrame()->GetFrameWnd()) {
// Reenable closing.
pCX->EnableClose(TRUE);
// Send it a close message.
pCX->GetFrame()->GetFrameWnd()->SendMessage(WM_CLOSE);
}
}
}
}
// Fill in left top position of frame.
// Breaks down on the minimized maximized scenario.
void FE_GetWindowPosition(MWContext *pContext, int32 *pX, int32 *pY)
{
TRACE("FE_GetWindowPosition(%p, %p, %p)\n", pContext, pX, pY);
// Initialize.
if(pX) {
*pX = 0;
}
if(pY) {
*pY = 0;
}
if(pContext && ABSTRACTCX(pContext) && ABSTRACTCX(pContext)->IsFrameContext() && (pX || pY)) {
// Make sure there's a frame.
CWinCX *pCX = WINCX(pContext);
if(pCX->GetFrame() && pCX->GetFrame()->GetFrameWnd()) {
CRect cr;
pCX->GetFrame()->GetFrameWnd()->GetWindowRect(cr);
if(pX) {
*pX = cr.left;
}
if(pY) {
*pY = cr.top;
}
}
}
}
// Set left top position of frame.
// Breaks down on the minimized maximized scenario.
void FE_SetWindowPosition(MWContext *pContext, int32 lX, int32 lY)
{
TRACE("FE_SetWindowPosition(%p, %ld, %ld)\n", pContext, lX, lY);
if(pContext && ABSTRACTCX(pContext) &&
ABSTRACTCX(pContext)->IsFrameContext()) {
// Make sure there's a frame.
CWinCX *pCX = WINCX(pContext);
if(pCX->GetFrame() && pCX->GetFrame()->GetFrameWnd()) {
pCX->GetFrame()->GetFrameWnd()->SetWindowPos(NULL, CASTINT(lX),
CASTINT(lY), 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}
}
}
// Return screen dimensions.
void FE_GetScreenSize(MWContext *pContext, int32 *pX, int32 *pY)
{
// Initialize
if(pX) {
*pX = sysInfo.m_iScreenWidth;
}
if(pY) {
*pY = sysInfo.m_iScreenHeight;
}
}
// Return available screen rectangle.
void FE_GetAvailScreenRect(MWContext *pContext, int32 *pX, int32 *pY,
int32 *pLeft, int32 *pTop)
{
RECT *pRect = NULL;
#ifdef WIN32
APPBARDATA abd;
UINT state;
XP_BZERO(&abd, sizeof abd);
abd.cbSize = sizeof(abd);
abd.hWnd = NULL;
state = SHAppBarMessage(ABM_GETSTATE, &abd);
if ((state & ABS_ALWAYSONTOP) && !(state & ABS_AUTOHIDE))
if (!SHAppBarMessage(ABM_GETTASKBARPOS, &abd))
ASSERT(0);
pRect = &abd.rc;
#endif
// Initialize
if(pX) {
*pX = sysInfo.m_iScreenWidth;
if (pRect != NULL) {
if (pRect->top < 0 && pRect->bottom > sysInfo.m_iScreenHeight) {
//Docked left
if (pRect->left < 0)
*pX -= pRect->right;
//Docked right
if (pRect->right > sysInfo.m_iScreenWidth)
*pX = pRect->left;
}
}
}
if(pY) {
*pY = sysInfo.m_iScreenHeight;
if (pRect != NULL) {
if (pRect->left < 0 && pRect->right > sysInfo.m_iScreenWidth) {
//Docked top
if (pRect->top < 0);
*pY -= pRect->bottom;
//Docked bottom
if (pRect->bottom > sysInfo.m_iScreenHeight)
*pY = pRect->top;
}
}
}
if(pLeft) {
*pLeft = 0;
if (pRect != NULL) {
if (pRect->top < 0 && pRect->left < 0) {
//Docked left
if (pRect->bottom > sysInfo.m_iScreenHeight)
*pLeft = pRect->right;
}
}
}
if(pTop) {
*pTop = 0;
if (pRect != NULL) {
if (pRect->top < 0 && pRect->left < 0) {
//Docked top
if (pRect->right > sysInfo.m_iScreenWidth)
*pTop = pRect->bottom;
}
}
}
}
// Return color depth.
void FE_GetPixelAndColorDepth(MWContext *pContext, int32 *pixel, int32 *pallette)
{
TRACE("FE_GetPixelAndColorDepth(%p, %p)\n", pixel, pallette);
*pixel = *pallette = 0;
if(ABSTRACTCX(pContext)->IsDestroyed() == FALSE) {
CWinCX *pWinCX = WINCX(pContext);
HDC pDC = pWinCX->GetContextDC();
// Figure out the depth of the CDC.
*pixel = ::GetDeviceCaps(pDC, BITSPIXEL);
// Check for pallette existence
if ((::GetDeviceCaps(pDC, RASTERCAPS) & RC_PALETTE) != 0)
*pallette = ::GetDeviceCaps(pDC, COLORRES);
else
*pallette = *pixel;
pWinCX->ReleaseContextDC(pDC);
}
}
BOOL GetIntelCPUSpeed(int32 &processorSpeed );
BOOL GetIntelCPUInfoViaCPUID(char *systemArchitecture,
int32 &processorType, int32 &processorFamily,
int32 &processorModel, int32 &processorStepping, int32 &processorFeatures,
CString &vendor);
#ifndef _WIN32
unsigned short GetBaseMemC();
unsigned short GetExpMemC();
#endif
CString csUNKNOWN = "Unknown";
CString csINTEL = "Intel";
CString csMIPS = "Mips";
CString csALPHA = "Alpha";
CString csPPC = "PowerPC";
CString csARCHITECTURE = "ARCHITECTURE";
CString csFAMILY = "FAMILY";
CString csMODEL = "MODEL";
CString csSTEPPING = "STEPPING";
CString csTYPE = "TYPE";
CString csFEATURES = "FEATURES";
CString csPASS = "PASS";
CString csREVISION = "REVISION";
CString csVERSION = "VERSION";
CString csVENDOR = "VENDOR";
// VARIABLE STRUCTURE DEFINITIONS //////////////////////////////
struct FREQ_INFO
{
unsigned long in_cycles; // Internal clock cycles during
// test
unsigned long ex_ticks; // Microseconds elapsed during
// test
unsigned long raw_freq; // Raw frequency of CPU in MHz
unsigned long norm_freq; // Normalized frequency of CPU
// in MHz.
};
struct FREQ_INFO cpuspeed(int clocks);
// Function Prototypes /////////////////////////////////////////
/***************************************************************
* WORD wincpuidsupport()
* =================================
* Wincpuidsupport() tells the caller whether the host processor
* supports the CPUID opcode or not.
*
* Inputs: none
*
* Returns:
* 1 = CPUID opcode is supported
* 0 = CPUID opcode is not supported
***************************************************************/
WORD wincpuidsupport();
/***************************************************************
* WORD wincpuid()
* ===============
* This routine uses the standard Intel assembly code to
* determine what type of processor is in the computer, as
* described in application note AP-485 (Intel Order #241618).
* Wincpuid() returns the CPU type as an integer (that is,
* 2 bytes, a WORD) in the AX register.
*
* Returns:
* 0 = 8086/88
* 2 = 80286
* 3 = 80386
* 4 = 80486
* 5 = Pentium(R) Processor
* 6 = PentiumPro(R) Processor
* 7 or higher = Processor beyond the PentiumPro6(R) Processor
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
WORD wincpuid();
/***************************************************************
* WORD wincpuidext()
* ==================
* Similar to wincpuid(), but returns more data, in the order
* reflecting the actual output of a CPUID instruction execution:
*
* Returns:
* AX(15:14) = Reserved (mask these off in the calling code
* before using)
* AX(13:12) = Processor type (00=Standard OEM CPU, 01=OverDrive,
* 10=Dual CPU, 11=Reserved)
* AX(11:8) = CPU Family (the same 4-bit quantity as wincpuid())
* AX(7:4) = CPU Model, if the processor supports the CPUID
* opcode; zero otherwise
* AX(3:0) = Stepping #, if the processor supports the CPUID
* opcode; zero otherwise
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
WORD wincpuidext(CString &vendorName);
/***************************************************************
* DWORD wincpufeatures()
* ======================
* Wincpufeatures() returns the CPU features flags as a DWORD
* (that is, 32 bits).
*
* Inputs: none
*
* Returns:
* 0 = Processor which does not execute the CPUID instruction.
* This includes 8086, 8088, 80286, 80386, and some
* older 80486 processors.
*
* Else
* Feature Flags (refer to App Note AP-485 for description).
* This DWORD was put into EDX by the CPUID instruction.
*
* Current flag assignment is as follows:
*
* bit31..10 reserved (=0)
* bit9=1 CPU contains a local APIC (iPentium-3V)
* bit8=1 CMPXCHG8B instruction supported
* bit7=1 machine check exception supported
* bit6=0 reserved (36bit-addressing & 2MB-paging)
* bit5=1 iPentium-style MSRs supported
* bit4=1 time stamp counter TSC supported
* bit3=1 page size extensions supported
* bit2=1 I/O breakpoints supported
* bit1=1 enhanced virtual 8086 mode supported
* bit0=1 CPU contains a floating-point unit (FPU)
*
* Note: New bits will be assigned on future processors... see
* processor data books for updated information
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
DWORD wincpufeatures(CString &vendorName);
#ifndef _WIN32
unsigned short GetBaseMemC()
{
// get memory below 1-MB boundary
// using run-time library functions
unsigned short base;
outp( 0x70, 0x15 );
base = inp( 0x71 ); //retrieve low byte
outp( 0x70, 0x16 );
base += inp(0x71) << 8; //retieve high byte,
//shift and add to base
return base; // return K's of base memory
}
unsigned short GetExpMemC()
{
// get memory above 1-MB boundary
// using run-time library functions
unsigned short extend;
outp( 0x70, 0x17 );
base = inp( 0x71 ); //retrieve low byte
outp( 0x70, 0x18 );
base += inp(0x71) << 8; //retieve high byte,
//shift and add to extend
return extend; // return K's of expansion memory
}
#endif
int32 FE_SystemRAM( void )
{
int32 systemRAM = -1;
#ifdef _WIN32
MEMORYSTATUS MemoryStatus;
memset( &MemoryStatus, 0, sizeof(MEMORYSTATUS));
MemoryStatus.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus( &MemoryStatus );
//return physical memory size in K
systemRAM = MemoryStatus.dwTotalPhys / 1024 ;
#else
//return physical memory size in K
int32 expansionMem = GetExpMemC();
int32 baseMem = GetBaseMemC();
systemRAM = expansionMem + baseMem;
#endif
return systemRAM;
}
int32 FE_SystemClockSpeed( void )
{
int32 clockSpeed = -1;
#ifdef _WIN32
OSVERSIONINFO OSVersionInfo;
memset( &OSVersionInfo, 0, sizeof(OSVERSIONINFO));
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(GetVersionEx( &OSVersionInfo ))
{
if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ||
OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) //Windows 9x
{
SYSTEM_INFO SystemInfo;
GetSystemInfo( &SystemInfo );
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
{
if(!GetIntelCPUSpeed(clockSpeed))
clockSpeed = -1;
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA )
{
return -1;
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS )
{
return -1;
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC )
{
return -1;
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_UNKNOWN )
return -1;
else
{
ASSERT(FALSE);
return -1;
}
}
else //if Win32s we must be running on Win3.x so Intel architecture
if( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32s )
{
if(!GetIntelCPUSpeed(clockSpeed))
clockSpeed = -1;
}
else
{
ASSERT(FALSE);
return -1;
}
}
#else
if(!GetIntelCPUSpeed(clockSpeed))
clockSpeed = -1;
#endif
return clockSpeed;
}
BOOL GetIntelCPUSpeed(int32 &processorSpeed )
{
BOOL bRet = FALSE;
// VARIABLE STRUCTURE DEFINITIONS //////////////////////////////
struct FREQ_INFO cpu_speed; // Return variable
// structure for
// cpuspeed
// routine
cpu_speed = cpuspeed(0);
if ( cpu_speed.in_cycles == 0 && cpu_speed.ex_ticks == 0 )
{
/*
sprintf(buf,
"This processor cannot be accurately "
"timed with this program.\n The "
"processor could be"
"below 80386 level.");
MessageBox(NULL,buf,"error", MB_ICONINFORMATION );
*/
bRet = FALSE;
}
else
{
/*
sprintf(buf,
"Clock Cycles: %lu cycles\n"
"Elapsed Time: %luus\n"
"Raw Clock Frequency: %luMHz\n"
"Normalized Frequency: %luMHz",
cpu_speed.in_cycles,
cpu_speed.ex_ticks,
cpu_speed.raw_freq,
cpu_speed.norm_freq);
MessageBox(NULL,buf,"32-bit cpuspeed",
MB_ICONINFORMATION );
*/
processorSpeed = cpu_speed.norm_freq;
bRet = TRUE;
}
return bRet;
}
BOOL GetIntelCPUInfoViaCPUID(CString &systemArchitecture,
int32 &processorType, int32 &processorFamily,
int32 &processorModel, int32 &processorStepping, int32 &processorFeatures,
CString &vendor)
{
//Intel Only!!!
systemArchitecture = csINTEL;
int32 processorExtensions = 0;
processorExtensions = wincpuidext(vendor);
processorStepping = processorExtensions & 0x0f;
processorModel = (processorExtensions & 0x0f0) >> 4;
processorFamily = (processorExtensions & 0x0f00) >> 8;
processorType = (processorExtensions & 0x03000) >> 12;
processorFeatures = wincpufeatures(vendor);
return TRUE;
}
char *CreateNonIntelCPUInfoString(CString &systemArchitecture,
int32 &processorModel, int32 &processorStepping)
{
CString tmpStr;
CString CPUInfoString;
ASSERT( !systemArchitecture.IsEmpty() );
if( !systemArchitecture.IsEmpty() )
{
CPUInfoString = csARCHITECTURE + "=";
CPUInfoString += systemArchitecture;
}
if( systemArchitecture == csALPHA )
{
if( processorModel > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csMODEL + "=A";
tmpStr.Format("%.2X", processorModel );
CPUInfoString += tmpStr;
}
if( processorStepping > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csPASS + "=";
tmpStr.Format("%.2X", processorStepping);
CPUInfoString += tmpStr;
}
}
else
if( systemArchitecture == csMIPS )
{
if( processorModel > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csREVISION + "=";
tmpStr.Format("%.2X", processorModel);
CPUInfoString += tmpStr;
}
}
else
if( systemArchitecture == csPPC )
{
if( processorModel > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csVERSION + "=";
tmpStr.Format("%.2X", processorModel);
CPUInfoString += tmpStr;
}
if( processorStepping > -1 )
{
CPUInfoString += ".";
tmpStr.Format("%.2X", processorStepping);
CPUInfoString += tmpStr;
}
}
char * pstr = NULL;
int len = CPUInfoString.GetLength();
if(len > 0 )
{
pstr = new char[ len + 1];
if( pstr != NULL )
strcpy( pstr, CPUInfoString );
}
return pstr;
}
char *CreateIntelCPUInfoString(CString &systemArchitecture,
int32 processorType, int32 processorFamily,
int32 processorModel, int32 processorStepping, int32 processorFeatures,
CString &vendor)
{
CString tmpStr;
CString CPUInfoString;
ASSERT( !systemArchitecture.IsEmpty() );
if( !systemArchitecture.IsEmpty() )
{
CPUInfoString = csARCHITECTURE + "=";
CPUInfoString += systemArchitecture;
}
if( processorType > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csTYPE + "=";
tmpStr.Format("%d", processorType);
CPUInfoString += tmpStr;
}
if( processorFamily > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csFAMILY + "=";
tmpStr.Format("%d", processorFamily);
CPUInfoString += tmpStr;
}
if( processorModel > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csMODEL + "=";
tmpStr.Format("%d", processorModel);
CPUInfoString += tmpStr;
}
if( processorStepping > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csSTEPPING + "=";
tmpStr.Format("%d", processorStepping);
CPUInfoString += tmpStr;
}
if( processorFeatures > -1 )
{
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csFEATURES + "=";
tmpStr.Format("0x%x", processorFeatures);
CPUInfoString += tmpStr;
}
if( !CPUInfoString.IsEmpty() )
CPUInfoString += ";";
CPUInfoString += csVENDOR + "=";
if( !vendor.IsEmpty() )
CPUInfoString += vendor;
else
CPUInfoString += csUNKNOWN;
char * pstr = NULL;
int len = CPUInfoString.GetLength();
if(len > 0 )
{
pstr = new char[ len + 1];
if( pstr != NULL )
strcpy( pstr, CPUInfoString );
}
return pstr;
}
char *FE_SystemCPUInfo(void)
{
CString systemArchitecture;
int32 processorType = -1;
int32 processorFamily = -1;
int32 processorModel = -1;
int32 processorStepping = -1;
int32 processorFeatures = -1;
CString vendor;
#ifdef _WIN32
OSVERSIONINFO OSVersionInfo;
memset( &OSVersionInfo, 0, sizeof(OSVERSIONINFO));
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(GetVersionEx( &OSVersionInfo ))
{
//if Win32s is the platform
if( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32s )
{
if(GetIntelCPUInfoViaCPUID(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor ))
return CreateIntelCPUInfoString(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor );
else
return NULL;
}
else
if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ||
OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) //Windows 9x
{
SYSTEM_INFO SystemInfo;
GetSystemInfo( &SystemInfo );
processorFamily = SystemInfo.wProcessorLevel;
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
{
if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
{ //Windows 9x
if(GetIntelCPUInfoViaCPUID(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor ))
return CreateIntelCPUInfoString(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor );
else
return NULL;
}
else //Windows NT on Intel
{
//Might as well use CPUID; it provides a little more information
if(GetIntelCPUInfoViaCPUID(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor ))
return CreateIntelCPUInfoString(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor );
else
return NULL;
// strcpy(systemArchitecture, INTEL);
// if( SystemInfo.dwProcessorType == PROCESSOR_INTEL_386 ||
// SystemInfo.dwProcessorType == PROCESSOR_INTEL_486 )
// {
// //wProcessor type of form xxyz; if xx != 0xFF
// if( ((SystemInfo.wProcessorRevision >> 8) & 0xff ) != 0xff )
// {
// //then xx + 'A' is the stepping letter
// processorStepping = ((SystemInfo.wProcessorRevision >> 8) & 0xff) + 'A';
// //this is actually the minor stepping
// processorModel = (SystemInfo.wProcessorRevision & 0x0ff);
// }
// else
// if( ((SystemInfo.wProcessorRevision >> 8) & 0xff ) == 0xff )
// {
// processorModel = (SystemInfo.wProcessorRevision & 0x0f0) >> 4;
// processorStepping = (SystemInfo.wProcessorRevision & 0x0f);
// }
// }
// else //processor must be > x486
// {
// processorModel = (SystemInfo.wProcessorRevision & 0x0ff00) >> 8;
// processorStepping = (SystemInfo.wProcessorRevision & 0x0ff);
// }
}
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA )
{
systemArchitecture = csALPHA;
processorModel = (SystemInfo.wProcessorRevision & 0x0ff00) >> 8;
//"Pass" on Alpha; display as "Model 'A'+xx, Pass yy"
processorStepping = (SystemInfo.wProcessorRevision & 0x0ff);
return CreateNonIntelCPUInfoString(systemArchitecture,
processorModel, processorStepping);
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS )
{
systemArchitecture = csMIPS;
//"Revision Number" on MIPS
processorModel = (SystemInfo.wProcessorRevision & 0x0ff);
return CreateNonIntelCPUInfoString(systemArchitecture,
processorModel, processorStepping);
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC )
{
systemArchitecture = csPPC;
//display as xx.yy on PPC
processorModel = (SystemInfo.wProcessorRevision & 0x0ff00) >> 8;
processorStepping = (SystemInfo.wProcessorRevision & 0x0ff);
return CreateNonIntelCPUInfoString(systemArchitecture,
processorModel, processorStepping);
}
else
if( SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_UNKNOWN )
{
systemArchitecture = csUNKNOWN;
return CreateNonIntelCPUInfoString(systemArchitecture,
processorModel, processorStepping);
}
else
{
ASSERT(FALSE);
systemArchitecture = csUNKNOWN;
return CreateNonIntelCPUInfoString(systemArchitecture,
processorModel, processorStepping);
}
}
ASSERT(FALSE); //Unknown operating system
}
return NULL;
#else //WIN16
if(GetIntelCPUInfoViaCPUID(systemArchitecture, processorType,
processorFamily, processorModel, processorStepping,
processorFeatures, vendor ))
return CreateIntelCPUInfoString(systemArchitecture,
processorType, processorFamily, processorModel,
processorStepping, processorFeatures, vendor );
else
return NULL;
#endif
}
// CONSTANT DEFINITIONS ////////////////////////////////////////
#define CLONE_MASK 0x8000 // Mask to be 'OR'ed with proc-
#define MAXCLOCKS 150 // Maximum number of cycles per
// BSF instruction
// ACCURACY AFFECTING CONSTANTS ////////////////////////////
#define ITERATIONS 4000 // Number of times to repeat BSF
// instruction in samplings.
// Initially set to 4000.
#define MAX_TRIES 20 // Maximum number of samplings
// to allow before giving up
// and returning current
// average. Initially set to
// 20.
#define TOLERANCE 1 // Number of MHz to allow
// samplings to deviate from
// average of samplings.
// Initially set to 2.
#define SAMPLINGS 10 // Number of BSF sequence
// samplings to make.
// Initially set to 10.
typedef unsigned short ushort;
typedef unsigned long ulong;
// Global Variable /////////////////////////////////////////////
int clone_flag; // Flag to show whether processor
// is non-Intel
// OPCODE DEFINITIONS //////////////////////////////////////////
#define CPU_ID _asm _emit 0x0f _asm _emit 0xa2
// CPUID instruction
#define RDTSC _asm _emit 0x0f _asm _emit 0x31
// RDTSC instruction
// Private Function Declarations ///////////////////////////////
/***************************************************************
* static WORD check_clone()
*
* Inputs: none
*
* Returns:
* 1 if processor is clone (limited detection ability)
* 0 otherwise
***************************************************************/
static WORD check_clone();
/***************************************************************
* static WORD check_8086()
*
* Inputs: none
*
* Returns:
* 0 if processor 8086
* 0xffff otherwise
***************************************************************/
static WORD check_8086();
/***************************************************************
* static WORD check_80286()
*
* Inputs: none
*
* Returns:
* 2 if processor 80286
* 0xffff otherwise
***************************************************************/
static WORD check_80286();
/***************************************************************
* static WORD check_80386()
*
* Inputs: none
*
* Returns:
* 3 if processor 80386
* 0xffff otherwise
***************************************************************/
static WORD check_80386();
/***************************************************************
* static WORD check_IDProc()
* ==========================
* Check_IDProc() uses the CPUID opcode to find the family type
* of the host processor.
*
* Inputs: none
*
* Returns:
* CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
static WORD check_IDProc();
//end of prototypes //////////////////////////////////////////////
#define ROUND_THRESHOLD 6
// Tabs set at 4
static struct FREQ_INFO GetRDTSCCpuSpeed();
static struct FREQ_INFO GetBSFCpuSpeed(ulong cycles);
// Number of cycles needed to execute a single BSF instruction.
// Note that processors below i386(tm) are not supported.
static ulong processor_cycles[] = {
00, 00, 00, 115, 47, 43,
38, 38, 38, 38, 38, 38,
};
/***************************************************************
* wincpuidsupport()
*
* Inputs: none
*
* Returns:
* 1 = CPUID opcode is supported
* 0 = CPUID opcode is not supported
***************************************************************/
WORD wincpuidsupport() {
int cpuid_support = 1;
_asm {
pushfd // Get original EFLAGS
pop eax
mov ecx, eax
xor eax, 200000h // Flip ID bit in EFLAGS
push eax // Save new EFLAGS value on
// stack
popfd // Replace current EFLAGS value
pushfd // Get new EFLAGS
pop eax // Store new EFLAGS in EAX
xor eax, ecx // Can not toggle ID bit,
jnz support // Processor=80486
mov cpuid_support,0 // Clear support flag
support:
}
return cpuid_support;
} // wincpuidsupport()
/***************************************************************
* wincpuid()
*
* Inputs: none
*
* Returns:
* 0 = 8086/88
* 2 = 80286
* 3 = 80386
* 4 = 80486
* 5 = Pentium(R) Processor
* 6 = PentiumPro(R) Processor
* 7 or higher = Processor beyond the PentiumPro6(R) Processor
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
WORD wincpuid() {
WORD cpuid;
if ( wincpuidsupport() ) // Determine whether CPUID
// opcode is supported
cpuid=check_IDProc();
else {
clone_flag=check_clone();
cpuid=check_8086(); // Will return FFFFh or 0
if (cpuid == 0) goto end;
cpuid=check_80286(); // Will return FFFFh or 2
if (cpuid == 2) goto end;
cpuid=check_80386(); // Will return FFFFh or 3
if (cpuid == 3) goto end; // temporarily commented out.
cpuid=4; // If the processor does not support CPUID,
// is not an 8086, 80286, or 80386, assign
// processor to be an 80486
}
end:
if (clone_flag)
cpuid = cpuid | CLONE_MASK; // Signify that a clone has been
// detected by setting MSB high
return cpuid;
} // wincpuid ()
/***************************************************************
* wincpufeatures()
*
* Inputs: none
*
* Returns:
* 0 = Processor which does not execute the CPUID instruction.
* This includes 8086, 8088, 80286, 80386, and some
* older 80486 processors.
*
* Else
* Feature Flags (refer to App Note AP-485 for description).
* This DWORD was put into EDX by the CPUID instruction.
*
* Current flag assignment is as follows:
*
* bit31..10 reserved (=0)
* bit9=1 CPU contains a local APIC (iPentium-3V)
* bit8=1 CMPXCHG8B instruction supported
* bit7=1 machine check exception supported
* bit6=0 reserved (36bit-addressing & 2MB-paging)
* bit5=1 iPentium-style MSRs supported
* bit4=1 time stamp counter TSC supported
* bit3=1 page size extensions supported
* bit2=1 I/O breakpoints supported
* bit1=1 enhanced virtual 8086 mode supported
* bit0=1 CPU contains a floating-point unit (FPU)
*
* Note: New bits will be assigned on future processors... see
* processor data books for updated information
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
DWORD wincpufeatures(CString &vendorName) {
int i=0;
DWORD cpuff=0x00000000;
BYTE vendor_id[]="------------";
BYTE intel_id[]="GenuineIntel";
if ( wincpuidsupport() ) {
_asm {
xor eax, eax // Set up for CPUID instruction
CPU_ID // Get and save vendor ID
mov dword ptr vendor_id, ebx
mov dword ptr vendor_id[+4], edx
mov dword ptr vendor_id[+8], ecx
}
vendorName = vendor_id;
for (i=0;i<12;i++)
{
if (!(vendor_id[i]==intel_id[i]))
clone_flag = 1;
}
_asm {
cmp eax, 1 // Make sure 1 is valid input
// for CPUID
jl end_cpuff // If not, jump to end
xor eax, eax
inc eax
CPU_ID // Get family/model/stepping/
// features
mov cpuff, edx
end_cpuff:
mov eax, cpuff
}
}
return cpuff;
} // wincpufeatures()
/***************************************************************
* wincpuidext()
*
* Inputs: none
*
* Returns:
* AX(15:14) = Reserved (mask these off in the calling code
* before using)
* AX(13:12) = Processor type (00=Standard OEM CPU, 01=OverDrive,
* 10=Dual CPU, 11=Reserved)
* AX(11:8) = CPU Family (the same 4-bit quantity as wincpuid())
* AX(7:4) = CPU Model, if the processor supports the CPUID
* opcode; zero otherwise
* AX(3:0) = Stepping #, if the processor supports the CPUID
* opcode; zero otherwise
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
WORD wincpuidext(CString &vendorName) {
int i=0;
WORD cpu_type=0x0000;
WORD cpuidext=0x0000;
BYTE vendor_id[]="------------";
BYTE intel_id[]="GenuineIntel";
if ( wincpuidsupport() ) {
_asm {
xor eax, eax // Set up for CPUID instruction
CPU_ID // Get and save vendor ID
mov dword ptr vendor_id, ebx
mov dword ptr vendor_id[+4], edx
mov dword ptr vendor_id[+8], ecx
}
vendorName = vendor_id;
for (i=0;i<12;i++)
{
if (!(vendor_id[i]==intel_id[i]))
clone_flag = 1;
}
_asm {
cmp eax, 1 // Make sure 1 is valid input
// for CPUID
jl end_cpuidext // If not, jump to end
xor eax, eax
inc eax
CPU_ID // Get family/model/stepping/
// features
mov cpuidext, ax
end_cpuidext:
mov ax, cpuidext
}
}
else {
cpu_type = wincpuid(); // If CPUID opcode is not
cpuidext = cpu_type << 8; // supported, put family
// value in extensions and
} // return
return cpuidext;
} // wincpuidext()
static struct FREQ_INFO GetBSFCpuSpeed(ulong cycles)
{
// If processor does not support time
// stamp reading, but is at least a
// 386 or above, utilize method of
// timing a loop of BSF instructions
// which take a known number of cycles
// to run on i386(tm), i486(tm), and
// Pentium(R) processors.
LARGE_INTEGER t0,t1; // Variables for High-
// Resolution Performance
// Counter reads
ulong freq =0; // Most current frequ. calculation
ulong ticks; // Microseconds elapsed
// during test
LARGE_INTEGER count_freq; // High Resolution
// Performance Counter
// frequency
int i; // Temporary Variable
ulong current = 0; // Variable to store time
// elapsed during loop of
// of BSF instructions
ulong lowest = ULONG_MAX; // Since algorithm finds
// the lowest value out of
// a set of samplings,
// this variable is set
// intially to the max
// unsigned long value).
// This guarantees that
// the initialized value
// is not later used as
// the least time through
// the loop.
struct FREQ_INFO cpu_speed;
memset(&cpu_speed, 0x00, sizeof(cpu_speed));
if ( !QueryPerformanceFrequency ( &count_freq ) )
return cpu_speed;
for ( i = 0; i < SAMPLINGS; i++ ) { // Sample Ten times. Can
// be increased or
// decreased depending
// on accuracy vs. time
// requirements
QueryPerformanceCounter(&t0); // Get start time
_asm
{
mov eax, 80000000h
mov bx, ITERATIONS
// Number of consecutive BSF
// instructions to execute.
// Set identical to
// nIterations constant in
// speed.h
loop1: bsf ecx,eax
dec bx
jnz loop1
}
QueryPerformanceCounter(&t1); // Get end time
current = (ulong) t1.LowPart - (ulong) t0.LowPart;
// Number of external ticks is
// difference between two
// hi-res counter reads.
if ( current < lowest ) // Take lowest elapsed
lowest = current; // time to account
} // for some samplings
// being interrupted
// by other operations
ticks = lowest;
// Note that some seemingly arbitrary mulitplies and
// divides are done below. This is to maintain a
// high level of precision without truncating the
// most significant data. According to what value
// ITERATIIONS is set to, these multiplies and
// divides might need to be shifted for optimal
// precision.
ticks = ticks * 100000;
// Convert ticks to hundred
// thousandths of a tick
ticks = ticks / ( count_freq.LowPart/10 );
// Hundred Thousandths of a
// Ticks / ( 10 ticks/second )
// = microseconds (us)
if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )
ticks++; // Round up if necessary
freq = cycles/ticks; // Cycles / us = MHz
cpu_speed.raw_freq = freq;
if ( cycles%ticks > ticks/2 )
freq++; // Round up if necessary
cpu_speed.in_cycles = cycles; // Return variable structure
cpu_speed.ex_ticks = ticks; // determined by one of
cpu_speed.norm_freq = freq;
return cpu_speed;
}
static struct FREQ_INFO GetRDTSCCpuSpeed()
{
struct FREQ_INFO cpu_speed;
LARGE_INTEGER t0,t1; // Variables for High-
// Resolution Performance
// Counter reads
ulong freq =0; // Most current frequ. calculation
ulong freq2 =0; // 2nd most current frequ. calc.
ulong freq3 =0; // 3rd most current frequ. calc.
ulong total; // Sum of previous three frequency
// calculations
int tries=0; // Number of times a calculation has
// been made on this call to
// cpuspeed
ulong total_cycles=0, cycles; // Clock cycles elapsed
// during test
ulong stamp0, stamp1; // Time Stamp Variable
// for beginning and end
// of test
ulong total_ticks=0, ticks; // Microseconds elapsed
// during test
LARGE_INTEGER count_freq; // High Resolution
// Performance Counter
// frequency
#ifdef WIN32
int iPriority;
HANDLE hThread = GetCurrentThread();
#endif // WIN32;
memset(&cpu_speed, 0x00, sizeof(cpu_speed));
if ( !QueryPerformanceFrequency ( &count_freq ) )
return cpu_speed;
// On processors supporting the Read
// Time Stamp opcode, compare elapsed
// time on the High-Resolution Counter
// with elapsed cycles on the Time
// Stamp Register.
do { // This do loop runs up to 20 times or
// until the average of the previous
// three calculated frequencies is
// within 1 MHz of each of the
// individual calculated frequencies.
// This resampling increases the
// accuracy of the results since
// outside factors could affect this
// calculation
tries++; // Increment number of times sampled
// on this call to cpuspeed
freq3 = freq2; // Shift frequencies back to make
freq2 = freq; // room for new frequency
// measurement
QueryPerformanceCounter(&t0);
// Get high-resolution performance
// counter time
t1.LowPart = t0.LowPart; // Set Initial time
t1.HighPart = t0.HighPart;
#ifdef WIN32
iPriority = GetThreadPriority(hThread);
if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
{
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
}
#endif // WIN32
while ( (ulong)t1.LowPart - (ulong)t0.LowPart<50) {
// Loop until 50 ticks have
// passed since last read of hi-
// res counter. This accounts for
// overhead later.
QueryPerformanceCounter(&t1);
RDTSC; // Read Time Stamp
_asm {
MOV stamp0, EAX
}
}
t0.LowPart = t1.LowPart; // Reset Initial
t0.HighPart = t1.HighPart; // Time
while ((ulong)t1.LowPart-(ulong)t0.LowPart<1000 ) {
// Loop until 1000 ticks have
// passed since last read of hi-
// res counter. This allows for
// elapsed time for sampling.
QueryPerformanceCounter(&t1);
RDTSC; // Read Time Stamp
__asm {
MOV stamp1, EAX
}
}
#ifdef WIN32
// Reset priority
if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
{
SetThreadPriority(hThread, iPriority);
}
#endif // WIN32
cycles = stamp1 - stamp0; // Number of internal
// clock cycles is
// difference between
// two time stamp
// readings.
ticks = (ulong) t1.LowPart - (ulong) t0.LowPart;
// Number of external ticks is
// difference between two
// hi-res counter reads.
// Note that some seemingly arbitrary multiplies and
// divides are done below. This is to maintain a
// high level of precision without truncating the
// most significant data. According to what value
// ITERATIONS is set to, these multiplies and
// divides might need to be shifted for optimal
// precision.
ticks = ticks * 100000;
// Convert ticks to hundred
// thousandths of a tick
ticks = ticks / ( count_freq.LowPart/10 );
// Hundred Thousandths of a
// Ticks / ( 10 ticks/second )
// = microseconds (us)
total_ticks += ticks;
total_cycles += cycles;
if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )
ticks++; // Round up if necessary
freq = cycles/ticks; // Cycles / us = MHz
if ( cycles%ticks > ticks/2 )
freq++; // Round up if necessary
total = ( freq + freq2 + freq3 );
// Total last three frequency
// calculations
} while ( (tries < 3 ) ||
(tries < 20)&&
((abs(int(3 * freq -total)) > 3*TOLERANCE )||
(abs(int(3 * freq2-total)) > 3*TOLERANCE )||
(abs(int(3 * freq3-total)) > 3*TOLERANCE )));
// Compare last three calculations to
// average of last three calculations.
// Try one more significant digit.
freq3 = ( total_cycles * 10 ) / total_ticks;
freq2 = ( total_cycles * 100 ) / total_ticks;
if ( freq2 - (freq3 * 10) >= ROUND_THRESHOLD )
freq3++;
cpu_speed.raw_freq = total_cycles / total_ticks;
cpu_speed.norm_freq = cpu_speed.raw_freq;
freq = cpu_speed.raw_freq * 10;
if( (freq3 - freq) >= ROUND_THRESHOLD )
cpu_speed.norm_freq++;
cpu_speed.ex_ticks = total_ticks;
cpu_speed.in_cycles = total_cycles;
return cpu_speed;
}
//CPU Speed functions
/***************************************************************
* CpuSpeed() -- Return the raw clock rate of the host CPU.
*
* Inputs:
* clocks: 0: Use default value for number of cycles
* per BSF instruction.
* -1: Use CMos timer to get cpu speed.
* Positive Integer: Use clocks value for number
* of cycles per BSF instruction.
*
* Returns:
* If error then return all zeroes in FREQ_INFO structure
* Else return FREQ_INFO structure containing calculated
* clock frequency, normalized clock frequency, number of
* clock cycles during test sampling, and the number of
* microseconds elapsed during the sampling.
***************************************************************/
struct FREQ_INFO cpuspeed(int clocks)
{
ulong cycles; // Clock cycles elapsed
// during test
ushort processor = wincpuid(); // Family of processor
CString vendor;
DWORD features = wincpufeatures(vendor); // Features of Processor
int manual=0; // Specifies whether the user
// manually entered the number of
// cycles for the BSF instruction.
struct FREQ_INFO cpu_speed; // Return structure for
// cpuspeed
memset(&cpu_speed, 0x00, sizeof(cpu_speed));
// Check for manual BSF instruction clock count
if (clocks <= 0) {
cycles = ITERATIONS * processor_cycles[processor];
}
else if (0 < clocks && clocks <= MAXCLOCKS) {
cycles = ITERATIONS * clocks;
manual = 1; // Toggle manual control flag.
// Note that this mode will not
// work properly with processors
// which can process multiple
// BSF instructions at a time.
// For example, manual mode
// will not work on a
// PentiumPro(R)
}
if ( ( features&0x00000010 ) && !(manual) ) {
// On processors supporting the Read
// Time Stamp opcode, compare elapsed
// time on the High-Resolution Counter
// with elapsed cycles on the Time
// Stamp Register.
if ( clocks == 0 )
return GetRDTSCCpuSpeed();
else
return cpu_speed;
}
else if ( processor >= 3 ) {
return GetBSFCpuSpeed(cycles);
}
return cpu_speed;
} // cpuspeed()
// Internal Private Functions //////////////////////////////////
/***************************************************************
* check_clone()
*
* Inputs: none
*
* Returns:
* 1 if processor is clone (limited detection ability)
* 0 otherwise
***************************************************************/
static WORD check_clone()
{
short cpu_type=0;
_asm
{
MOV AX,5555h // Check to make sure this
XOR DX,DX // is a 32-bit processor
MOV CX,2h
DIV CX // Perform Division
CLC
JNZ no_clone
JMP clone
no_clone: STC
clone: PUSHF
POP AX // Get the flags
AND AL,1
XOR AL,1 // AL=0 is probably Intel,
// AL=1 is a Clone
MOV cpu_type, ax
}
cpu_type = cpu_type & 0x0001;
return cpu_type;
} // check_clone()
/***************************************************************
* check_8086()
*
* Inputs: none
*
* Returns:
* 0 if processor 8086
* 0xffff otherwise
***************************************************************/
static WORD check_8086()
{
WORD cpu_type=0xffff;
_asm {
pushf // Push original FLAGS
pop ax // Get original FLAGS
mov cx, ax // Save original FLAGS
and ax, 0fffh // Clear bits 12-15 in FLAGS
push ax // Save new FLAGS value on stack
popf // Replace current FLAGS value
pushf // Get new FLAGS
pop ax // Store new FLAGS in AX
and ax, 0f000h // If bits 12-15 are set, then
cmp ax, 0f000h // processor is an 8086/8088
mov cpu_type, 0 // Turn on 8086/8088 flag
je end_8086 // Jump if processor is 8086/
// 8088
mov cpu_type, 0ffffh
end_8086:
push cx
popf
mov ax, cpu_type
}
return cpu_type;
} // check_8086()
/***************************************************************
* check_80286()
*
* Inputs: none
*
* Returns:
* 2 if processor 80286
* 0xffff otherwise
***************************************************************/
static WORD check_80286()
{
WORD cpu_type=0xffff;
_asm {
pushf
pop cx
mov bx, cx
or cx, 0f000h // Try to set bits 12-15
push cx // Save new FLAGS value on stack
popf // Replace current FLAGS value
pushf // Get new FLAGS
pop ax // Store new FLAGS in AX
and ax, 0f000h // If bits 12-15 are clear
mov cpu_type, 2 // Processor=80286, turn on
// 80286 flag
jz end_80286 // If no bits set, processor is
// 80286
mov cpu_type, 0ffffh
end_80286:
push bx
popf
mov ax, cpu_type
}
return cpu_type;
} // check_80286()
/***************************************************************
* check_80386()
*
* Inputs: none
*
* Returns:
* 3 if processor 80386
* 0xffff otherwise
***************************************************************/
static WORD check_80386()
{
WORD cpu_type=0xffff;
_asm {
mov bx, sp
and sp, not 3
pushfd // Push original EFLAGS
pop eax // Get original EFLAGS
mov ecx, eax // Save original EFLAGS
xor eax, 40000h // Flip AC bit in EFLAGS
push eax // Save new EFLAGS value on
// stack
popfd // Replace current EFLAGS value
pushfd // Get new EFLAGS
pop eax // Store new EFLAGS in EAX
xor eax, ecx // Can't toggle AC bit,
// processor=80386
mov cpu_type, 3 // Turn on 80386 processor flag
jz end_80386 // Jump if 80386 processor
mov cpu_type, 0ffffh
end_80386:
push ecx
popfd
mov sp, bx
mov ax, cpu_type
and eax, 0000ffffh
}
return cpu_type;
} // check_80386()
/***************************************************************
* check_IDProc()
*
* Inputs: none
*
* Returns:
* CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
*
* Note: This function also sets the global variable clone_flag
***************************************************************/
static WORD check_IDProc() {
int i=0;
WORD cpu_type=0xffff;
BYTE stepping=0;
BYTE model=0;
BYTE vendor_id[]="------------";
BYTE intel_id[]="GenuineIntel";
_asm {
xor eax, eax // Set up for CPUID instruction
CPU_ID // Get and save vendor ID
mov dword ptr vendor_id, ebx
mov dword ptr vendor_id[+4], edx
mov dword ptr vendor_id[+8], ecx
}
for (i=0;i<12;i++)
{
if (!(vendor_id[i]==intel_id[i]))
clone_flag = 1;
}
_asm {
cmp eax, 1 // Make sure 1 is valid input
// for CPUID
jl end_IDProc // If not, jump to end
xor eax, eax
inc eax
CPU_ID // Get family/model/stepping/
// features
mov stepping, al
and stepping, 0x0f //0fh
and al, 0f0h
shr al, 4
mov model, al
and eax, 0f00h
shr eax, 8 // Isolate family
and eax, 0fh
mov cpu_type, ax // Set _cpu_type with family
end_IDProc:
mov ax, cpu_type
}
return cpu_type;
} // Check_IDProc()