Related
After an outfile data is processed, I want to take in that data back in again using an fstream variable called infile. Can an operation like the one below be possible after the outfile is complete? My main goal is to read back in what was randomly put out to the file so I can process it into a linked list eventually. I have tested a code similar to this but I get zeroes as a result. Thanks.
ifstream infile;
string FileName = "Numbers.txt";
infile.open(FileName);
while (infile)
{
infile >> RandomNumber;
cout << RandomNumber << endl;
}
infile.close();
This should work if ( infile ) will check if the file is opened and while ( infile >> RandomNumber ) will get all the numbers in the file:
ifstream infile;
string FileName = "Numbers.txt";
infile.open(FileName);
if ( infile ) {
while ( infile >> RandomNumber ) {
cout << RandomNumber << endl;
}
}
infile.close();
This is not an answer to the OPs question but rather it is provided towards a small conversation within a series of comments about reading files and parsing data. This is directed towards Tony and any who would wish to use this class setup. There are some things with in this class that pertain to other classes within my library, some of these include my Logger which would log messages to either a file or the console, and the message types are either Info, Warning, Error or Console. My Logger is derived from a Singleton class since I would only need one logger per solution to handle all messages. I have a Utility Class that hands a majority of string manipulation functions where the constructor is private and all functions or members are declared as static. This class also relies on an ExceptionHandler class that will accept either std::strings or std::ostringstream objects. My Logger accepts the same. Also some of my classes also rely on a BlockThread class that allows to work with multithreading which upon construction it will Create and Initialize a CriticalSection then Enter the Critical Section and then upon Destruction it will Leave and then Destroy the CriticalSection. Now as for this demonstration I will only be showing my FileHandler Classes along with 2 of its derived types, TextFileReader and TextFileWriter. I have more derived FileHandlers that work with reading in texture files, custom data structures etc, that work on binary files as opposed to text file, but for the purpose of this only the Text File Handlers will be shown.
FileHandler.h
#ifndef FILE_HANDLER_H
#define FILE_HANDLER_H
namespace util {
//class AssetStorage;
class FileHandler {
protected:
//static AssetStorage* m_pAssetStorage;
std::fstream m_fileStream;
std::string m_strFilePath;
std::string m_strFilenameWithPath;
private:
bool m_bSaveExceptionInLog;
public:
virtual ~FileHandler();
protected:
FileHandler( const std::string& strFilename, bool bSaveExceptionInLog );
void throwError( const std::string& strMessage ) const;
void throwError( const std::ostringstream& strStreamMessage ) const;
bool getString( std::string& str, bool appendPath );
private:
FileHandler( const FileHandler& c ); // Not Implemented
FileHandler& operator=( const FileHandler& c ); // Not Implemented
}; // FileHandler
} // namespace util
FileHandler.cpp
#include "stdafx.h"
#include "FileHandler.h"
namespace util {
// ----------------------------------------------------------------------------
// FileHandler()
FileHandler::FileHandler( const std::string& strFilename, bool bSaveExceptionInLog ) :
m_bSaveExceptionInLog( bSaveExceptionInLog ),
m_strFilenameWithPath( strFilename ) {
// Extract Path Info If It Exists
std::string::size_type lastIndex = strFilename.find_last_of( "/\\" );
if ( lastIndex != std::string::npos ) {
m_strFilePath = strFilename.substr( 0, lastIndex );
}
if ( strFilename.empty() ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " missing filename", m_bSaveExceptionInLog ) );
}
} // FileHandler
// ----------------------------------------------------------------------------
// ~FileHandler
FileHandler::~FileHandler() {
if ( m_fileStream.is_open() ) {
m_fileStream.close();
}
} // ~FileHandler
// ----------------------------------------------------------------------------
// throwError()
void FileHandler::throwError( const std::string& strMessage ) const {
throw ExceptionHandler( "File [" + m_strFilenameWithPath + "] " + strMessage, m_bSaveExceptionInLog );
} // throwError( const std::string )
// ----------------------------------------------------------------------------
// throwError()
void FileHandler::throwError( const std::ostringstream& strStreamMessage ) const {
throwError( strStreamMessage.str() );
} // throwError( const std::ostringstream )
// ----------------------------------------------------------------------------
// getString()
bool FileHandler::getString( std::string& str, bool appendPath ) {
m_fileStream.read( &str[0], str.size() );
if ( m_fileStream.fail() ) {
return false;
}
// Trim Right
str.erase( str.find_first_of( char(0) ) );
if ( appendPath && !m_strFilePath.empty() ) {
// Add Path If One Exixsts
str = m_strFilePath + "/" + str;
}
return true;
} // getString
} // namespace util
TextFileReader.h
#ifndef TEXT_FILE_READER_H
#define TEXT_FILE_READER_H
#include "FileHandler.h"
namespace util {
class TextFileReader : public FileHandler {
private:
public:
explicit TextFileReader( const std::string& strFilename );
// virtual ~TextFileReader(); // Default OK
std::string readAll() const;
bool readLine( std::string& strLine );
private:
TextFileReader( const TextFileReader& c ); // Not Implemented
TextFileReader& operator=( const TextFileReader& c ); // Not Implemented
}; // TextFileReader
} // namespace util
#endif // TEXT_FILE_READER_H
TextFileReader.cpp
#include "stdafx.h"
#include "TextFileReader.h"
namespace util {
// ----------------------------------------------------------------------------
// TextFileReader()
TextFileReader::TextFileReader( const std::string& strFilename ) :
FileHandler( strFilename, true ) {
m_fileStream.open( m_strFilenameWithPath.c_str(), std::ios_base::in );
if ( !m_fileStream.is_open() ) {
throwError( __FUNCTION__ + std::string( " can not open file for reading" ) );
}
} // TextFileReader
// ----------------------------------------------------------------------------
// readAll()
std::string TextFileReader::readAll() const {
std::ostringstream strStream;
strStream << m_fileStream.rdbuf();
return strStream.str();
} // readAll
// ----------------------------------------------------------------------------
// readLine()
// Returns A String Containing The Next Line Of Text Stored In The File
bool TextFileReader::readLine( std::string& strLine ) {
if ( m_fileStream.eof() ) {
return false;
}
std::getline( m_fileStream, strLine );
return true;
} // readLine
} // namespace util
TextFileWriter.h
#ifndef TEXT_FILE_WRITER_H
#define TEXT_FILE_WRITER_H
#include "FileHandler.h"
namespace util {
class TextFileWriter : public FileHandler {
private:
public:
TextFileWriter( const std::string& strFilename, bool bAppendToFile, bool bSaveExceptionInLog = true );
// virtual ~TextFileWriter(); // Default OK
void write( const std::string& str );
private:
TextFileWriter( const TextFileWriter& c ); // Not Implemented
TextFileWriter& operator=( const TextFileWriter& c ); // Not Implemented
}; // TextFileWriter
} // namespace util
#endif // TextFileWriter
TextFileWriter.cpp
#include "stdafx.h"
#include "TextFileWriter.h"
namespace util {
// ----------------------------------------------------------------------------
// TextFileWriter()
TextFileWriter::TextFileWriter( const std::string& strFilename, bool bAppendToFile, bool bSaveExceptionInLog ) :
FileHandler( strFilename, bSaveExceptionInLog ) {
m_fileStream.open( m_strFilenameWithPath.c_str(),
std::ios_base::out | (bAppendToFile ? std::ios_base::app : std::ios_base::trunc) );
if ( !m_fileStream.is_open() ) {
throwError( __FUNCTION__ + std::string( " can not open file for writing" ) );
}
} // TextFileWriter
// ----------------------------------------------------------------------------
// write()
void TextFileWriter::write( const std::string& str ) {
m_fileStream << str;
} // write
} // namespace util
And Here is some code fragments of a class that used the FileHandlers.
Here is the class header that uses the FileHandler It reads in a text file and parses it to determine which GUI objects to create, load into memory and how they are to be displayed on the screen, it will also nest one GUI type as a child to another. I will not be showing the full implementation of this class but only a few functions where it concerns the use of using the FileHandlers.
GuiLoader.h
#ifndef GUI_LOADER_H
#define GUI_LOADER_H
#include "Engine.h"
#include "CommonStructs.h"
#include "Property.h"
#include "TextFileReader.h"
namespace vmk {
class AssetStorage;
class GuiCompositeElement;
class GuiElement;
class GuiLayout;
class GuiRenderable;
class GuiText;
class VisualMko;
class GuiLoader sealed {
friend GuiElement* Engine::loadGui( const std::string& strFilename ) const;
private:
std::string m_strFilename;
util::TextFileReader m_file;
bool m_inBlockComment;
unsigned m_uNumBracesOpened;
unsigned m_uLineNumber; // Keep Track OfLine Number For Error Messages
GuiElement* m_pLastGuiRoot;
std::vector<GuiCompositeElement*> m_vpParents;
std::string m_strLine;
std::unordered_map<std::string, TextureInfo> m_mTextureInfos;
std::unordered_map<std::string, FontFace> m_mFontFace;
FontManager* m_pFontManager;
AssetStorage* m_pAssetStorage;
public:
// virtual ~GuiLoader(); // Default Ok
GuiElement* getRoot() const;
private:
GuiLoader( const std::string& strFilename );
GuiLoader( const GuiLoader& c ); // Not Implemented
GuiLoader& operator=( const GuiLoader& c ); // Not Implemented
bool getNextLine();
std::string getFailedLocation() const;
void removeComments();
void parseGui();
bool handleOpenBrace( unsigned uStartLocation, GuiCompositeElement* pGui );
void addToParent( GuiRenderable* pRenderable ) const;
bool getParameter( std::string strParam, unsigned uStartLocation, std::string& strValue, bool isRequired = true, char endCharacter = ' ' ) const;
void setOptionalParameters( unsigned uStartLocation, GuiElement* pGui ) const;
void getOptionalLayoutParameters( unsigned uStartLocation, glm::ivec2& offsetFromParent, Gui::Alignment& eAlignChildren, glm::uvec2& size, std::string& strId ) const;
void setLayoutParameters( unsigned uStartLocation, GuiLayout* pLayout ) const;
bool getOptionalBackgroundParameters( unsigned uStartLocation, TextureInfo& textureInfo, glm::uvec2& origin ) const;
bool getOptionalBackgroundParameters( unsigned uStartLocation, TextureInfo& textureInfo, glm::uvec2& origin, glm::uvec2& size, bool isRequired = true ) const;
void getRequiredTextParameters( unsigned uStartLocation, FontFace& fontFace, std::string& strText ) const;
void setTextShadowParameters( unsigned uStartLocation, GuiText* pGui ) const;
void setVisualMkoParameters( unsigned uStartLocation, VisualMko* pVisualMko ) const;
}; // GuiLoader
} // namespace vmk
#endif // GUI_LOADER_H
GuiLoader.cpp - Only A Few Portions Are Shown
#include "stdafx.h"
#include "GuiLoader.h"
#include "AssetStorage.h"
#include "FontManager.h"
#include "Gui.h"
#include "Image2d.h"
#include "Logger.h"
#include "TextureFileReader.h"
#include "Utility.h"
using namespace util;
namespace vmk {
// ----------------------------------------------------------------------------
// GuiLoader()
GuiLoader::GuiLoader( const std::string& strFilename ) :
m_strFilename( strFilename ),
m_file( strFilename ),
m_inBlockComment( false ),
m_uNumBracesOpened( 0 ),
m_uLineNumber( 0 ),
m_pLastGuiRoot( nullptr ),
m_pFontManager( FontManager::get() ),
m_pAssetStorage( AssetStorage::get() ) {
while ( getNextLine() ) {
parseGui();
}
if ( m_uNumBracesOpened > 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << getFailedLocation() << ". Missing " << m_uNumBracesOpened << " closing brace" << ( m_uNumBracesOpened > 1 ? "s" : "" ) << ".";
throw ExceptionHandler( strStream );
}
if ( m_inBlockComment ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << getFailedLocation() << ". Missing closing block comment */.";
}
} // GuiLoader
// ----------------------------------------------------------------------------
// getRoot()
GuiElement* GuiLoader::getRoot() const {
return m_pLastGuiRoot;
} // getRoot
// ----------------------------------------------------------------------------
// getNextLine()
// Returns True If Got A Line Of Text (Could Be Blank If It Is All Commented
// Out Or If It Truly Was A Blank Line). False is Returned When There Is
// No More Data In The File
bool GuiLoader::getNextLine() {
if ( !m_file.readLine( m_strLine ) ) {
return false;
}
++m_uLineNumber;
m_strLine = Utility::trim( m_strLine );
//std::cout << m_uLineNumber << ": " << m_strLine << std::endl; // Use This For Debugging The GuiLoader
removeComments();
return true;
} // getNextLine
// ... Other Functions Here
} // namespace vmk
This was presented to show the robustness of my file handling classes. There are many other classes not shown here. My library is a part of a 3D Graphics Rendering Library that uses Modern OpenGL. There are several hundred class objects and 100,000s of lines of code for doing 3D graphics rendering, sprite loading, physics simulation, animation, audio playback, audio stream playback, and much more. Not all of this source code is of my own design for this code is copy right protected by Marek A. Krzeminski, MASc and his works can be found at www.MarekKnows.com
All code shown here was not copied and pasted from his site, it was all hand typed while following along with his video tutorials. It was compiled and debug manually. This project has been in the works for a couple of years, and still to this day more is being added. I have been a proud member of his website and community since 2007-2008.
int number = 0;
string filename( "Numbers.txt" );
std::ofstream out;
std::ifstream in;
std::cout << "enter a number: << std::endl;
std::cin >> number;
out.open( filename.c_str(), std::ios_base::out );
if ( !out.is_open() ){
// Print, Log Error, Throw Error, Return Etc.
}
for ( int i = 0; i < number; i++ ) {
out << rand() % 100 << std::endl;
}
out.close();
in.open( filename.c_str(), std::ios_base::in );
if ( !in.is_open() ) {
// Error Case Here
}
while ( !in.eof() ) { // Usually bad practice; but my file handling classes are parser objects are too large to show here.
in >> RandomNumber;
std::cout << RandomNumber << endl;
}
infile.close();
In my C++ application, a CHTMLView is used to load some HTML into a web page. It works by writing the HTML to a temporary file, and then calling Navigate2() on the CHTMLView to navigate to the file location.
What we are finding happens is that the navigation occurs, the file is written, the completely correct contents of the page appears, but then it quickly disappears and becomes blank. But it's a visual thing; right-clicking and saying "View Source" shows the correct source, and hovering over elements on the page that react to hovering make them appear again (but everything else stays white). Resizing the window or scrolling is the only way to make everything appear.
I have tried navigating first to about:blank and then triggering a navigation to the correct place with a OnDocumentComplete() event. I have even tried navigating first to blank dummy page and then going from there. Nothing changes.
Any advice?!
The derived class is ScriptViewer.
ScriptViewer.h
class CScriptViewer : public CHtmlView
{
protected:
CScriptViewer(); // protected constructor used by dynamic creation
DECLARE_DYNCREATE(CScriptViewer)
// html Data
public:
//{{AFX_DATA(CScriptViewer)
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Attributes
public:
CAMAgentDesktopDoc* m_pDoc;
CScriptDlg* m_pDlg;
CString strScriptLocation;
BOOL m_bInitialLoad;
// Operations
public:
void GetAllValues( map<CString,CString>& mValues );
void GetValuesIn( IHTMLDocument2* pHTMLDoc, map<CString,CString>& mValues );
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScriptViewer)
public:
virtual void OnInitialUpdate();
virtual void OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel);
virtual void OnDocumentComplete(LPCTSTR lpszURL);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
virtual ~CScriptViewer();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
CAMTrace m_trace;
// Generated message map functions
//{{AFX_MSG(CScriptViewer)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
ScriptViewer.cpp
CScriptViewer::CScriptViewer()
{
//{{AFX_DATA_INIT(CScriptViewer)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_trace.SetEXEName( _T("CScriptViewer") );
m_trace.Trace( _T("constructor"), FALSE, 0 );
strScriptLocation = _T("");
m_bInitialLoad = FALSE;
m_pDoc = NULL;
m_pDlg = NULL;
}
CScriptViewer::~CScriptViewer()
{
/*
map<CString,CString> mValues;
GetAllValues( mValues );
m_pDlg->UpdateUserEnteredValues( mValues );
*/
m_trace.Trace( _T("destructor"), FALSE, 0 );
}
void CScriptViewer::DoDataExchange(CDataExchange* pDX)
{
CHtmlView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScriptViewer)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CScriptViewer, CHtmlView)
//{{AFX_MSG_MAP(CScriptViewer)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScriptViewer diagnostics
#ifdef _DEBUG
void CScriptViewer::AssertValid() const
{
CHtmlView::AssertValid();
}
void CScriptViewer::Dump(CDumpContext& dc) const
{
CHtmlView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScriptViewer message handlers
void CScriptViewer::OnInitialUpdate()
{
try
{
m_trace.Trace( _T("OnInitialUpdate") );
ASSERT( m_pDoc );
ASSERT( m_pDlg );
}
catch(...)
{
}
}
void CScriptViewer::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
{
try
{
map<CString,CString> mValues;
GetAllValues( mValues );
ASSERT( m_pDlg );
// GJS
if (!m_pDlg) return;
m_pDlg->UpdateUserEnteredValues( mValues );
CString strURL = lpszURL;
int nPosClose = strURL.Find( URL_INSTRUCTION_TO_ADAPTIVE_DESKTOP );
if ( nPosClose > 0 )
{
*pbCancel = TRUE;
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
m_pDlg->OnScriptInstructionToDesktop( strURL.Mid( nPosClose + _tcslen(URL_INSTRUCTION_TO_ADAPTIVE_DESKTOP) ), mValues );
}
else
{
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
}
}
catch(...)
{
}
}
void CScriptViewer::OnDocumentComplete(LPCTSTR lpszURL) {
if (!m_bInitialLoad) {
//Navigate2(strScriptLocation);
//m_bInitialLoad = TRUE;
}
}
///////////////////////////////////////////////////////////////////////////////////
// accessing data values from the HTML pages, after the user has fiddled with them
void CScriptViewer::GetValuesIn( IHTMLDocument2* pHTMLDoc, map<CString,CString>& mValues )
{
try
{
if ( pHTMLDoc != NULL )
{
BSTR bsURL;
VERIFY( SUCCEEDED( pHTMLDoc->get_URL( &bsURL ) ) );
// TRACE( _T("GetValuesIn(%s)\r\n"), CString(bsURL) );
IHTMLFramesCollection2* pFrames = NULL;
if ( SUCCEEDED( pHTMLDoc->get_frames( &pFrames ) ) )
{
long lNumFrames = 0;
VERIFY( SUCCEEDED( pFrames->get_length( &lNumFrames ) ) );
for( long l = 0; l < lNumFrames; l++ )
{
COleVariant v1(l);
VARIANT vDispFrame;
if ( SUCCEEDED( pFrames->item( v1, &vDispFrame ) ) )
{
if ( vDispFrame.vt == VT_DISPATCH )
{
IHTMLWindow2* pWindow = NULL;
VERIFY( SUCCEEDED( (vDispFrame.pdispVal)->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&pWindow ) ) );
ASSERT( pWindow );
IHTMLDocument2* pSubDoc = NULL;
if ( SUCCEEDED( pWindow->get_document( &pSubDoc ) ) )
{
GetValuesIn( pSubDoc, mValues );
pSubDoc->Release();
}
pWindow->Release();
}
}
}
pFrames->Release();
}
IHTMLElementCollection* pElemColl = NULL;
HRESULT hr = pHTMLDoc->get_all(&pElemColl);
if (SUCCEEDED(hr) && pElemColl)
{
long lNumElements = 0;
VERIFY( SUCCEEDED( pElemColl->get_length( &lNumElements ) ) );
for( long l = 0; l < lNumElements; l++ )
{
COleVariant v1(l);
COleVariant vzero((long)0);
LPDISPATCH pDispTemp = NULL;
VERIFY( SUCCEEDED( pElemColl->item( v1, vzero, &pDispTemp ) ) );
ASSERT( pDispTemp != NULL );
IHTMLElement* pel = NULL;
VERIFY( SUCCEEDED( pDispTemp->QueryInterface( IID_IHTMLElement, (LPVOID*)&pel ) ) );
CString str;
BSTR bsid;
pel->get_id( &bsid );
VARIANT vValue;
pel->getAttribute( CString("value").AllocSysString(), 0, &vValue );
CString strID = CString(bsid);
if ( !strID.IsEmpty() )
{
CString strValue = _T("");
if ( vValue.vt == VT_BSTR ) {
strValue = CString(vValue.bstrVal);
} else if ( vValue.vt == VT_I2 || vValue.vt == VT_I4 ) {
strValue.Format( _T("%d"), vValue.intVal );
}
mValues[strID] = strValue;
// str.Format( _T("ID %s, value %s\r\n"),
// strID, strValue );
// strRetval += str;
}
pel->Release();
}
pElemColl->Release();
}
else
ASSERT(FALSE);
}
else
ASSERT(FALSE); // passed null object doc
}
catch(...)
{
}
}
void CScriptViewer::GetAllValues( map<CString,CString>& mValues )
{
try
{
mValues.clear();
LPDISPATCH pDisp = GetHtmlDocument();
if ( pDisp )
{
IHTMLDocument2* p = NULL;
if ( SUCCEEDED( pDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&p ) ) && p != NULL )
{
GetValuesIn( p, mValues );
p->Release();
}
else
ASSERT(FALSE); // unable to QI for IHTMLDocument2?
pDisp->Release();
}
}
catch(...)
{
}
}
Here is the code that handles the navigation:
CString strFilePath = CAMMiscSharedFilePaths::GetFullPathToWindowsTempDir() + _T("\\") + m_call->m_camCampaignSettings.m_scriptView.m_strName+_T("_temp.htm");
HRESULT hr = WriteStringToTextFile( strFilePath, strRedirect ); //intentionally left for html settings, as it stores data in windows temp
if ( SUCCEEDED(hr) ) {
pView->strScriptLocation = strFilePath;
CString str = strFilePath;
pView->Navigate2(str);
}
Here is my derived class of a CHTMLView. I load the HTML directly into the browser. Works for me, maybe you can use it:
#include "stdafx.h"
#include "GMHtmlView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CGMHtmlView, CHtmlView)
CGMHtmlView::CGMHtmlView(IHtmlEventNotifier* pHEN)
{
EnableToolTips(FALSE);
m_pBrowser = NULL;
m_pBrowserDispatch = NULL;
m_pHEN = pHEN;
m_strPrefix = "http://";
}
void CGMHtmlView::DoDataExchange(CDataExchange* pDX)
{
CHtmlView::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CGMHtmlView, CHtmlView)
END_MESSAGE_MAP()
BOOL CGMHtmlView::Create(const RECT &rect,CWnd* pParentWnd)
{
BOOL bRet = CHtmlView::Create(NULL,NULL,WS_VISIBLE,rect,pParentWnd,AFX_IDW_PANE_FIRST);
// Pointer auf Browser herausfinden
if(bRet)
{
LPUNKNOWN unknown = GetDlgItem(0)->GetControlUnknown();
HRESULT hr = unknown->QueryInterface(IID_IWebBrowser2,(void **)&m_pBrowser);
if (SUCCEEDED(hr))
hr = unknown->QueryInterface(IID_IDispatch,(void **)&m_pBrowserDispatch);
}
return bRet;
}
void CGMHtmlView::SetPrefix(const CString& prefix)
{
m_strPrefix = prefix;
}
void CGMHtmlView::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
{
CString url(lpszURL);
url.MakeLower();
// Sperre: alles andere als die leere Seite
// und unser Inhalt wird gesperrt
if(url == "about:blank")
{
CHtmlView::OnBeforeNavigate2(lpszURL,nFlags,lpszTargetFrameName,baPostedData,lpszHeaders,pbCancel);
return;
}
if(url.Find(m_strPrefix) != 0)
{
*pbCancel = TRUE;
return;
}
// jetzt die Adresse nach aussen weiterleiten
if(m_pHEN)
{
url = url.Right(url.GetLength() - m_strPrefix.GetLength());
m_pHEN->UrlNotify(url);
}
}
void CGMHtmlView::Clear()
{
if(!IsWindow(m_hWnd))
return;
IHTMLDocument2* pDoc = GetDocument();
if(!pDoc)
{
Navigate2("about:blank");
return;
}
pDoc->close();
VARIANT open_name;
VARIANT open_features;
VARIANT open_replace;
IDispatch *open_window = NULL;
::VariantInit(&open_name);
open_name.vt = VT_BSTR;
open_name.bstrVal = ::SysAllocString(L"_self");
::VariantInit(&open_features);
::VariantInit(&open_replace);
HRESULT hr = pDoc->open(::SysAllocString(L"text/html"),open_name,open_features,
open_replace,&open_window);
if (hr == S_OK)
Refresh();
if (open_window != NULL)
open_window->Release();
}
void CGMHtmlView::LoadHTML(const CString& html)
{
if(!IsWindow(m_hWnd))
return;
Clear();
IHTMLDocument2* pDoc = GetDocument();
if(!pDoc)
return;
SAFEARRAY* sa = SafeArrayCreateVector(VT_VARIANT,0,1);
VARIANT* var;
SafeArrayAccessData(sa,(LPVOID*) &var);
var->vt = VT_BSTR;
var->bstrVal = html.AllocSysString();
SafeArrayUnaccessData(sa);
pDoc->write(sa);
pDoc->Release();
}
IHTMLDocument2* CGMHtmlView::GetDocument()
{
IHTMLDocument2* document = NULL;
if (m_pBrowser != NULL)
{
IDispatch *document_dispatch = NULL;
HRESULT hr = m_pBrowser->get_Document(&document_dispatch);
if (SUCCEEDED(hr) && (document_dispatch != NULL))
{
hr = document_dispatch->QueryInterface(IID_IHTMLDocument2,(void **)&document);
document_dispatch->Release();
}
}
return document;
}
void CGMHtmlView::AssertValid() const
{
//CHtmlView::AssertValid();
}
void CGMHtmlView::PostNcDestroy()
{
//CHtmlView::PostNcDestroy();
}
I want to create a RAII wrapper around a file descriptor. As the object might be passed around threads, it really is a shared resource: this is why I made a first implementation by using a shared_ptr with a custom destructor.
struct file_descriptor
{
file_descriptor( const std::string & pathname, int flags )
:m_fd( initialize( pathname, flags ) )
{
}
file_descriptor( const int opened_fd )
:m_fd( initialize( opened_fd ) )
{
}
operator int() const { return *m_fd; }
private:
std::shared_ptr<int> initialize( const int opened_fd )
{
std::shared_ptr<int> ptr_to_fd;
try
{
int * shared_fd = new int;
ptr_to_fd = std::shared_ptr<int>( shared_fd, file_descriptor_closer() );
*shared_fd = opened_fd;
}
catch( std::bad_alloc & )
{
close( opened_fd );
throw;
}
return ptr_to_fd;
}
std::shared_ptr<int> initialize( const std::string & pathname, int flags )
{
const int fd = open( pathname.c_str(), flags );
if (fd < 0)
throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );
return initialize( fd );
}
std::shared_ptr<int> m_fd;
};
The custom destructor, is pretty simple:
struct file_descriptor_closer
{
void operator()(int * const fd) noexcept { if (fd) close(*fd); delete fd; }
};
Now I find the design horrible, namely because of the "new int". I thought about making a custom allocator to point to an already-allocated block, but that seems overkill. Do you guys have suggestion to simplify this?
IMHO, you're mixing responsibilities. Let your RAII class deal with the opening and closing of the file descriptor. Let some other class deal with the lifetime question of your RAII class. As you have it now, the user of your file_descriptor class would need to know that it is using a shared_ptr internally. On first glance, if I were to share a file_descriptor between threads, I'd be making a shared_ptr<file_descriptor> of my own to counter the problem that I don't really know that internally it's already doing one.
use some gentle violence:
struct file_descriptor_closer
{
void operator()(void* fd) noexcept { if (fd) close(reinterpret_cast< int >(fd)); }
};
struct file_descriptor
{
file_descriptor( const std::string & pathname, int flags )
:m_fd( initialize( pathname, flags ) )
{
}
file_descriptor( const int opened_fd )
:m_fd( initialize( opened_fd ) )
{
}
operator int() const { return reinterpret_cast< int >(m_fd.get()); }
private:
std::shared_ptr<void> initialize( const int opened_fd )
{
try
{
return std::shared_ptr< void >( reinterpret_cast< void* >( opened_fd ), file_descriptor_closer() );
}
catch( std::bad_alloc & )
{
close( opened_fd );
throw;
}
}
std::shared_ptr<void> initialize( const std::string & pathname, int flags )
{
const int fd = open( pathname.c_str(), flags );
if (fd < 0)
throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );
return initialize( fd );
}
std::shared_ptr<void> m_fd;
};
Why not create your own container? What about something like: http://ideone.com/m3kmaJ or with static counter: http://ideone.com/Gs4Kb7
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <thread>
#include <memory>
#include <unistd.h>
#include <atomic>
class FD
{
private:
int fd;
static int count;
public:
FD(const char* FilePath, int flags) : fd(open(FilePath, flags)) {++FD::count;}
FD(const FD& other) : fd(other.fd) {++FD::count;}
FD(FD&& other) : fd(other.fd) { other.fd = -1; }
~FD()
{
FD::count -= 1;
if (FD::count == 0)
{
std::cout<<"Destroyed\n";
if (is_open())
close(fd);
}
}
bool is_open() {return fd != -1;}
FD* operator &() {return nullptr;}
operator int() {return fd;}
FD& operator = (FD other)
{
fd = other.fd;
FD::count += 1;
return *this;
}
FD& operator = (FD&& other)
{
fd = other.fd;
other.fd = -1;
return *this;
}
};
int FD::count = 0;
int main()
{
FD fd = FD("Unicode.cpp", O_RDONLY);
FD copy = fd;
FD cpy = FD(copy);
return 0;
}
I've written code to patch the "Sleep" function for example from Kernel32.dll. The patching works perfectly fine. The removal of the patch works perfectly fine. However, calling the original function does not work at all. It crashes badly.
#include <windows.h>
#include <iostream>
std::uint8_t* Patch(std::uint8_t* OrigFunc, std::uint8_t* HookFunc)
{
DWORD dwProtect = 0;
const static std::uint8_t jmp[] = {0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
const static std::int8_t jmp_size = sizeof(jmp) / sizeof(std::uint8_t);
static std::uint8_t HookJump[jmp_size + 1] = {jmp_size};
VirtualProtect(OrigFunc, jmp_size, PAGE_EXECUTE_READWRITE, &dwProtect);
memcpy(&HookJump[1], OrigFunc, jmp_size);
memcpy(OrigFunc, jmp, jmp_size);
memcpy(OrigFunc + 1, &HookFunc, sizeof(void*));
VirtualProtect(OrigFunc, jmp_size, dwProtect, &dwProtect);
return HookJump;
}
void RemovePatch(std::uint8_t* OrigFunc, std::uint8_t* HookJump)
{
DWORD dwProtect = 0;
VirtualProtect(OrigFunc, HookJump[0], PAGE_EXECUTE_READWRITE, &dwProtect);
memcpy(OrigFunc, &HookJump[1], HookJump[0]);
VirtualProtect(OrigFunc, HookJump[0], dwProtect, &dwProtect);
}
typedef void (__stdcall *pSleep)(DWORD);
pSleep oSleep;
void __stdcall hSleep(DWORD MS)
{
std::cout<<"HERE";
oSleep(MS); //Crashes Here.
}
int main()
{
std::uint8_t* OrigFunc = (std::uint8_t*)GetProcAddress(GetModuleHandle("kernel32.dll"), "Sleep");
std::uint8_t* HookFunc = (std::uint8_t*)hSleep;
std::uint8_t* HookJump = Patch(OrigFunc, HookFunc); //Works fine.
oSleep = (pSleep)&HookJump[1];
Sleep(1000); //Prints Here then crashes immediately.
RemovePatch(OrigFunc, HookJump); //Works fine.
Sleep(1000); //Works fine.
}
Any ideas what my code is missing?
In the given code it appears that you store original bytes in a static array called HookJump, return a pointer to that array, then jump to the start of it as if it were valid machine code. It's not followed by the rest of the original function.
A better way to hook functions in Windows is to use Microsoft Detours.
Here's my (working sketch of a) Hook class, using Detours:
[Hook.h]
#pragma once
// Copyright (c) 2013 Alf P. Steinbach
#include <rfc/cppx/core/Non_copyable.h> // cppx::Non_copyable
#include <rfc/cppx/core/macros/ASSERT.h> // CPPX_ASSERT
#include <rfc/detours/Transaction.h> // detours::Transaction
namespace detours {
using cppx::Non_copyable;
template< class Func >
class Hook_
: public Non_copyable
{
private:
Func* original_;
Func* replacement_;
public:
auto original_func() const
-> Func*
{ return original_; }
~Hook_()
{
if( original_ != nullptr )
{
Transaction().detach( original_, replacement_ ).commit();
}
}
Hook_( Func* const original, Func* const replacement )
: original_( original )
, replacement_( replacement )
{
CPPX_ASSERT( original_ != nullptr );
CPPX_ASSERT( replacement_ != nullptr );
Transaction().attach( original_, replacement_ ).commit();
}
Hook_( Hook_&& other )
: original_( other.original_ )
, replacement_( other.replacement_ )
{ other.original_ = nullptr; other.replacement_ = nullptr; }
};
template< class Func >
inline auto hook( Func* const original, Func* const replacement )
-> Hook_<Func>
{ return Hook_<Func>( original, replacement ); }
} // namespace detours
And here's the Transaction class that it uses, which in turn calls the Detours API:
[Transaction.h]
#pragma once
// Copyright (c) 2013 Alf P. Steinbach
#include <rfc/cppx/core/utility/If_.h> // cppx::If
#include <rfc/cppx/core/Non_copyable.h> // cppx::Non_copyable
#include <rfc/cppx/core/Type_.h> // cppx::Type_
#include <thread> // std::thread
#include <type_traits> // std::is_function, std::enable_if
namespace detours {
using cppx::If_;
using cppx::Non_copyable;
using cppx::Type_;
using std::is_function;
using std::thread;
typedef thread::native_handle_type Thread_handle;
class Basic_transaction
: public Non_copyable
{
private:
typedef Type_<void(*)()> Proc;
bool is_committed_;
void raw_attach( Proc& original, Proc const replacement );
void raw_detach( Proc& original, Proc const replacement );
public:
auto is_committed() const
-> bool;
void commit();
auto update_thread( Thread_handle const h )
-> Basic_transaction&;
auto update_this_thread()
-> Basic_transaction&;
template< class Func, class Enabled = If_<is_function<Func>> >
auto attach( Func*& original, Func* const replacement )
-> Basic_transaction&
{
raw_attach(
reinterpret_cast<Proc&>( original ),
reinterpret_cast<Proc>( replacement )
);
return *this;
}
template< class Func, class Enabled = If_<is_function<Func>> >
auto detach( Func*& original, Func* const replacement )
-> Basic_transaction&
{
raw_detach(
reinterpret_cast<Proc&>( original ),
reinterpret_cast<Proc>( replacement )
);
return *this;
}
~Basic_transaction();
Basic_transaction();
};
class Transaction
: public Basic_transaction
{
public:
Transaction()
{ update_this_thread(); }
};
} // namespace detours
[Transaction.cpp]
#include "Transaction.h"
#include <rfc/cppx/core/throwing.h>
#include <rfc/cppx/core/macros/ASSERT.h> // CPPX_ASSERT
#include <rfc/detours_wrappers/detours_h.h>
using cppx::hopefully;
using cppx::fail;
typedef long Error_code;
namespace detours{
auto Basic_transaction::is_committed() const
-> bool
{ return is_committed_; }
void Basic_transaction::commit()
{
CPPX_ASSERT( !is_committed_ );
Error_code const code = ::DetourTransactionCommit();
hopefully( code == 0 )
|| fail( "Basic_transaction::commit: DetourTransactionCommit failed", code );
is_committed_ = true;
}
auto Basic_transaction::update_thread( Thread_handle const h )
-> Basic_transaction&
{
Error_code const code = ::DetourUpdateThread( reinterpret_cast<HANDLE>( h ) );
hopefully(code == 0)
|| fail("Transaction::update_thread: DetourUpdateThread failed", code);
return *this;
}
auto Basic_transaction::update_this_thread()
-> Basic_transaction&
{
return update_thread( Thread_handle( ::GetCurrentThread() ) );
}
void Basic_transaction::raw_attach( Proc& original, Proc const replacement )
{
Error_code const code = ::DetourAttach(
reinterpret_cast<void**>( &original ),
reinterpret_cast<void*>( replacement )
);
hopefully(code == 0)
|| fail("Transaction::attach: DetourAttach failed", code);
}
void Basic_transaction::raw_detach( Proc& original, Proc const replacement )
{
Error_code const code = ::DetourDetach(
reinterpret_cast<void**>( &original ),
reinterpret_cast<void*>( replacement )
);
hopefully(code == 0)
|| fail("Transaction::attach: DetourAttach failed", code);
}
Basic_transaction::~Basic_transaction()
{
if (!is_committed_)
{
Error_code const code = ::DetourTransactionAbort();
hopefully( code == 0 )
|| fail( "Basic_transaction::<destroy>: DetourTransactionAbort failed", code );
}
}
Basic_transaction::Basic_transaction()
: is_committed_( false )
{
Error_code const code = ::DetourTransactionBegin();
hopefully( code == 0 )
|| fail( "Basic_transaction::<init>: DetourTransactionBegin failed", code );
}
} // namespace detours
The Detours wrapper header:
[detours.h]
#pragma once
#include <rfc/winapi_wrappers/windows_h.h>
#include <microsoft_detours/detours.h>
I then use a cpp file to bring in a specific Detours implementation, e.g. for x86:
[detours_cpp.x86-32.cpp]
// Copyright (c) 2013 Alf P. Steinbach
#define DETOURS_INTERNAL // Necessary for DETOUR_TRACE
#include <rfc/detours_wrappers/detours_h.h>
#define DETOURS_X86
#define DETOURS_32BIT
#include <microsoft_detours/detours.cpp> // Source
#include <microsoft_detours/disasm.cpp> // More source, e.g. DetourCopyInstruction
I'm using the function SetupGetLineText ( http://msdn.microsoft.com/en-us/library/aa377388(v=VS.85).aspx ) from the Setup API to read a line from a section in an inf file.
Lines are in the format:
key=value
SetupGetLineText appears to return the value part. That's fine, but I also want to know what the key is for the current context I'm reading. There doesn't seem to be a function in the Setup API for reading the key.
Any help in working out how to retrieve the key would be appreciated.
Here is a class I use to handle inf files using SetupAPI.
#ifndef SETUP_INF_PARSER_H_INC_
#define SETUP_INF_PARSER_H_INC_
#include <string>
#include <vector>
namespace win32
{
namespace inf
{
class line
{
public:
line() { ZeroMemory( &_ctx, sizeof( _ctx ) ); }
line( const INFCONTEXT& ctx ) : _ctx( ctx ) {}
bool operator==( const line& op2 ) const
{
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) == 0;
}
bool operator!=( const line& op2 ) const
{
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) != 0;
}
bool operator<( const line& op2 ) const
{
std::wstring str0, str1;
if( string_at( 0, str0 ) && op2.string_at( 0, str1 ) )
return str0 < str1;
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) < 0;
}
bool isValid() const
{
return *this != line();
}
bool string_at( unsigned int idx, std::wstring& str ) const
{
wchar_t buf[4096];
DWORD size_needed = 0;
if( SetupGetStringField( (PINFCONTEXT) &_ctx, idx, buf, sizeof( buf ), &size_needed ) )
{
str = buf;
return true;
}
return false;
}
std::vector<std::wstring> contents()
{
std::vector<std::wstring> lst;
for( unsigned int idx = 0; true; ++idx )
{
std::wstring str;
if( !string_at( idx, str ) )
{
break;
}
lst.push_back( str );
}
return lst;
}
operator INFCONTEXT*() { return &_ctx; }
private:
INFCONTEXT _ctx;
};
class section
{
public:
section()
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
}
section( HINF hInf, const std::wstring& section_name )
: _Name( section_name )
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
SetupFindFirstLine( hInf, section_name.c_str(), 0, &_ctx );
}
~section()
{
}
class iterator : public std::iterator<std::forward_iterator_tag,line>
{
friend section;
public:
iterator()
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
}
iterator& operator++()
{
INFCONTEXT tmpCtx;
if( SetupFindNextLine( _ctx, &tmpCtx ) )
{
_ctx = tmpCtx;
}
else
{
_ctx = line();
}
return *this;
}
line operator*()
{
return _ctx;
}
line* operator->()
{
return &_ctx;
}
bool operator==( const iterator& op2 ) const
{
return _ctx == op2._ctx;
}
bool operator!=( const iterator& op2 ) const
{
return _ctx != op2._ctx;
}
private:
iterator( INFCONTEXT& ctx )
: _ctx( ctx )
{}
line _ctx;
};
bool operator<( const section& op2 ) const
{
return _Name < op2._Name;
}
iterator begin()
{
return iterator( _ctx );
}
iterator end()
{
return iterator();
}
private:
std::wstring _Name;
INFCONTEXT _ctx;
};
class inf_file
{
public:
inf_file( const std::wstring& str )
{
UINT err_line = 0;
_inf = SetupOpenInfFile( str.c_str(), 0, INF_STYLE_WIN4, &err_line );
if( _inf == INVALID_HANDLE_VALUE )
{
DWORD err = GetLastError();
// do something ..
throw std::invalid_argument( "failed to open inf file" );
}
}
~inf_file()
{
SetupCloseInfFile( _inf );
}
section get_section( const std::wstring& section_name )
{
return section( _inf, section_name );
}
class iterator : public std::iterator<std::forward_iterator_tag,section>
{
friend inf_file;
public:
iterator() : _hInf( 0 ), _idx( 0 ) {}
iterator& operator++()
{
if( _idx < 0 )
_idx = 0;
else
++_idx;
init_at( _idx );
return *this;
}
const section& operator*() const
{
return _Section;
}
section* operator->()
{
return &_Section;
}
bool operator==( const iterator& op2 ) const
{
return _idx == op2._idx;
}
bool operator!=( const iterator& op2 ) const
{
return !(*this == op2);
}
private:
void init_at( int idx )
{
if( _hInf != 0 && _hInf != INVALID_HANDLE_VALUE )
{
wchar_t buf[128] = { 0 };
UINT sizeNeeded = 0;
if( SetupEnumInfSectionsW( _hInf, _idx, buf, ARRAYSIZE( buf ), &sizeNeeded ) )
{
_Section = section( _hInf, buf );
return;
}
}
_Section = section();
}
iterator( HINF& ctx )
: _idx( 0 ), _hInf( ctx )
{}
section _Section;
HINF _hInf;
int _idx;
};
iterator begin()
{
return iterator( _inf );
}
iterator end()
{
return iterator();
}
struct VersionInfo
{
std::wstring signature;
std::wstring class_name;
GUID class_guid;
std::wstring provider;
std::wstring date;
std::wstring version;
};
bool parseVersionInfo( VersionInfo& info )
{
section s( _inf, L"Version" );
for( section::iterator i = s.begin(); i != s.end(); ++i )
{
std::vector<std::wstring> str_list = i->contents();
if( str_list.size() > 1 )
{
std::wstring& entry = str_list[0];
std::wstring& entry1 = str_list[1];
if( entry == L"Signature" )
{
info.signature = entry1;
}
else if( entry == L"Class" )
{
info.class_name = entry1;
}
else if( entry == L"ClassGUID" )
{
IIDFromString( const_cast<wchar_t*>( entry1.c_str() ), &info.class_guid );
}
else if( entry == L"Provider" )
{
info.provider = entry1;
}
else if( entry == L"DriverVer" )
{
info.date = entry1;
info.version = str_list[2];
}
}
}
return true;
}
private:
inf_file( const inf_file& );
inf_file& operator=( const inf_file& );
HINF _inf;
};
};
};
#endif // SETUP_INF_PARSER_H_INC_
A long shot:
BOOL SetupGetStringField(
__in PINFCONTEXT Context,
__in DWORD FieldIndex,
__inout PTSTR ReturnBuffer,
__in DWORD ReturnBufferSize,
__out PDWORD RequiredSize
);
with
FieldIndex [in]
The 1-based index of
the field within the specified line
from which the string should be
retrieved. Use a FieldIndex of 0 to
retrieve a string key, if present.