Fabio Galuppo's profileThe House of Software En...PhotosBlogListsMore ![]() | Help |
Public folders
|
The House of Software EngineerThe new house is here. The old is there: http://fabiogaluppo.blogspot.com/
June 10 Combination TreeThis sample generates a set of combined numbers. These numbers are grouped inside a tree structure, which I called combination tree.
It was built with Visual C++ 2010, using C++0x features (TR1 and lambdas).
#include <array>
using std::array; using std::get; #include <memory> using std::shared_ptr; #include <algorithm>
using std::for_each; using std::transform; #include <string> using std::string; #include <list> using std::list; #include <iostream> using std::cout; using std::endl; template<typename T, size_t N> struct Leaf { typedef shared_ptr<Leaf<T, N>> LeafType; typedef shared_ptr<array<LeafType, N>> LeavesType; explicit Leaf(const T& value) : Value(value){} LeavesType Leaves; T Value; }; template<typename T, size_t N> struct CombinationTree { typedef typename Leaf<T, N>::LeavesType LeavesType; typedef typename Leaf<T, N>::LeafType LeafType; explicit CombinationTree() : Root_(make_Leaves()){} void add( array<T, N>& value ) { if( get<0>(*Root_) ) assign_Leaves( Root_, value ); else assign_Values( Root_, value ); } const LeavesType& get_Root() const { return Root_; } private: LeafType make_Leaf( const T& v ) const { return LeafType( new Leaf<T, N>(v) ); } LeavesType make_Leaves() const { return LeavesType( new array<LeafType, N> ); } void add_Leaf(LeafType& leaf, array<T, N>& value) { auto& leaves = leaf->Leaves; if ( leaves.get() ) { assign_Leaves( leaves, value ); return; } leaves = LeavesType( new array<LeafType, N> ); assign_Values( leaves, value ); } void assign_Leaves(LeavesType& leaves, array<T, N>& value) { for_each( leaves->begin(), leaves->end(), [this, &value](LeafType& l){ add_Leaf(l, value); } ); } void assign_Values(LeavesType& leaves, array<T, N>& value) const { transform( value.begin(), value.end(), leaves->begin(), [this](const T& v){ return make_Leaf(v); } ); } private: LeavesType Root_; }; template<size_t N> struct NaiveDumpCombination { const list<string> operator()( const CombinationTree<string, N>& tree ) { auto leaves = tree.get_Root(); list<string> combinations; for_each ( leaves->begin(), leaves->end(), [this, &combinations](shared_ptr<Leaf<string, N>> l){ GetCombinations( l, l->Value, combinations ); } ); return combinations; } private: void GetCombinations( const shared_ptr<Leaf<string, N>>& leaf, string s, list<string>& combinations ) { if( !leaf ) return; auto& leaves = leaf->Leaves; if (!leaves) { combinations.push_back( s ); return; } for_each ( leaves->begin(), leaves->end(), [this, s, &combinations](shared_ptr<Leaf<string, N>> l) { GetCombinations( l, s + " " + l->Value, combinations ); } ); } }; int main() { //combinations with repetition NaiveDumpCombination<5> dump; CombinationTree<string, 5> tree; array<string, 5> a = { "1", "2", "3", "4", "5" }; tree.add(a); tree.add(a); tree.add(a); tree.add(a); tree.add(a); const auto& combination = dump( tree ); for_each( combination.begin(), combination.end(), [](string s){ cout << s << endl; } ); } May 08 Comma Quibbling PuzzleSome days ago (almost one month ago), Eric Lippert post a cool puzzle.
I did some solutions, to be exact, one in C++ and 2 in C#. So, today I had time to compile them here...
C++ Solution:
#include <algorithm>#include <string> #include <sstream> #include <iostream> #include <vector> #include <iterator> using namespace std; namespace Solution { template< class Elem, class TString = basic_string<Elem>, class TSequenceContainter = vector<TString> > class GetSequence { TString Open_, Close_, Separator_, Separator_End_; int min( int lVal, int rVal ){ return lVal < rVal ? lVal : rVal; } public: GetSequence(TString open, TString close, TString separator, TString separator_end) : Open_(open), Close_(close), Separator_(separator), Separator_End_(separator_end){} TString get(const TSequenceContainter& items) { TSequenceContainter::size_type itemsCount = items.size(); typedef ostream_iterator<TString, Elem> iter; basic_stringstream<Elem> ss; ss << Open_; copy( items.begin(), items.end() - min(2, itemsCount), iter( ss, Separator_.c_str() ) ); copy( items.end() - min(2, itemsCount), items.end() - min(1, itemsCount), iter( ss, Separator_End_.c_str() ) ); copy( items.end() - min(1, itemsCount), items.end(), iter( ss ) ); ss << Close_; return ss.str(); } }; GetSequence<char> seq_ASCII(){ return GetSequence<char>("{", "}", ", ", " and "); } GetSequence<wchar_t> seq_Unicode(){ return GetSequence<wchar_t>(L"{", L"}", L", ", L" and "); } } int main() { vector<string> x; x.push_back("A"); x.push_back("B"); x.push_back("C"); x.push_back("D"); cout << Solution::seq_ASCII().get( x ) << "\n"; vector<string> y; y.push_back("A"); y.push_back("B"); cout << Solution::seq_ASCII().get( y ) << "\n"; vector<string> z; z.push_back("A"); cout << Solution::seq_ASCII().get( z ) << "\n"; vector<string> w; cout << Solution::seq_ASCII().get( w ) << "\n"; vector<wstring> ux; ux.push_back(L"A"); ux.push_back(L"B"); ux.push_back(L"C"); ux.push_back(L"D"); wcout << Solution::seq_Unicode().get( ux ) << L"\n"; vector<wstring> uy; uy.push_back(L"A"); uy.push_back(L"B"); wcout << Solution::seq_Unicode().get( uy ) << L"\n"; vector<wstring> uz; uz.push_back(L"A"); wcout << Solution::seq_Unicode().get( uz ) << L"\n"; vector<wstring> uw; wcout << Solution::seq_Unicode().get( uw ) << L"\n"; } C# Solutions:
using System; using System.Collections.Generic; using System.Linq; using System.Text; static class Solution { static StringBuilder Append(this StringBuilder sb, string one, string two) { return sb.Append(one).Append(two); } static string Next(this IEnumerator<string> enumerator) { enumerator.MoveNext(); return enumerator.Current; } public static string GetSequence(IEnumerable<string> items) { const string OPEN = "{", CLOSE = "}"; //(1) If the sequence is empty then the resulting string is "{}" if (null == items) return OPEN + CLOSE; int itemsCount = items.Count(); switch (itemsCount) { //(1) If the sequence is empty then the resulting string is "{}" case 0: return OPEN + CLOSE; //(2) If the sequence is a single item "ABC" then the resulting string is "{ABC}" case 1: return OPEN + items.First() + CLOSE; //(3) If the sequence is the two item sequence "ABC", "DEF" then the resulting string is "{ABC and DEF}". //(4) If the sequence has more than two items, say, "ABC", "DEF", "G", "H" then the resulting string is "{ABC, DEF, G and H}". (Note: no Oxford comma!) default: const int COUNTDOWN = 2, ESTIMATED_STRING_LENGTH = 4; const string SEPARATOR = ",", SEPARATOR_END = "and"; var sb = new StringBuilder(OPEN, ESTIMATED_STRING_LENGTH * itemsCount); var enumerator = items.GetEnumerator(); while (COUNTDOWN < itemsCount--) sb.Append(enumerator.Next(), SEPARATOR).Append(" "); return sb.Append(enumerator.Next(), " ").Append(SEPARATOR_END, " ").Append(enumerator.Next(), CLOSE).ToString(); } } } static class Solution2 { static string Match(this IEnumerable<string> items, params Func<string>[] funcs) { return funcs[null == items ? 0 : Math.Min(items.Count(), funcs.Length - 1)](); } public static string GetSequence(IEnumerable<string> items) { return items.Match ( () => { return "{}"; }, () => { return "{" + items.First() + "}"; }, () => { int count = items.Count() - 2; var sb = new StringBuilder("{"); foreach (var item in items.Take(count)) sb.Append(item).Append(", "); var last = items.Skip(count).ToArray(); sb.Append(last[0]).Append(" and ").Append(last[1]); return sb.Append("}").ToString(); } ); } } class TestProgram { static void Main() { Action<string> print = Console.WriteLine; print( Solution.GetSequence(new string[] { "A", "B", "C", "D" }) ); print( Solution.GetSequence(new string[] { "A", "B" }) ); print( Solution.GetSequence(new string[] { "A" }) ); print( Solution.GetSequence(new string[] {}) ); print( Solution.GetSequence(null) ); print(new string('-',20)); print(Solution2.GetSequence(new string[] { "A", "B", "C", "D" })); print(Solution2.GetSequence(new string[] { "A", "B" })); print(Solution2.GetSequence(new string[] { "A" })); print(Solution2.GetSequence(new string[] { })); print(Solution.GetSequence(null)); } } March 09 The Anagram problem (and a sequential solution)This is a sequential solution using C++ of anagram problem pointed out by Eric Lippert's Fabulous Adventures In Coding
The solution itself is multi-paradigm and platform independent (except in the case of StopWatch which is Windows specific, but could be easily ported).
The file used as dictionary to test is an adapted version of twl06.txt (is the same file only with the words, without the numbers and space). This file could be searched by your preferred search engine.
#include <iostream> #include <fstream> #include <vector> #include <set> #include <algorithm> #include <iterator> #include <functional> #include <cstring> #include <string> using namespace std; #define WIN32_LEAN_AND_MEAN #include <windows.h> string Canonicalize( const string& str_value ) { string canonicalizedValue( str_value ); sort( canonicalizedValue.begin(), canonicalizedValue.end() ); return canonicalizedValue; } void RecursiveReplace( const string& value, set<string>& canonicalizedValues ) { string::size_type idx( value.find_first_of( '?' ) ); if( idx == string::npos ) { canonicalizedValues.insert( Canonicalize( value ) ); return; } string value_( value );
for(char ch = 0x41; ch <= 0x5A; ++ch) { value_[ idx ] = ch; RecursiveReplace( value_, canonicalizedValues ); } } struct CanonicalizedValues { CanonicalizedValues( const string& value ) : OriginalValue_( value ) { RecursiveReplace( value, CanonicalizedValues_ ); } const set<string>& GetValues() const { return CanonicalizedValues_; } const string& GetOriginalValue() const { return OriginalValue_; } private: set<string> CanonicalizedValues_; string OriginalValue_; }; struct FindMatches { FindMatches( const CanonicalizedValues& canonicalizedValues, vector<string>& result ) : CanonicalizedValues_( canonicalizedValues ), Result_( result ), WordLength_( canonicalizedValues.GetOriginalValue().length() ) { } void operator()( const char* line ) { if( WordLength_ == strlen(line) ) { const set<string>& values( CanonicalizedValues_.GetValues() ); const string canonicalizedValue( Canonicalize( line ) ); if( values.end() != find( values.begin(), values.end(), canonicalizedValue ) ) { Result_.push_back( line ); } } } private: const CanonicalizedValues& CanonicalizedValues_; vector<string>& Result_; size_t WordLength_; }; template<class Function> void ReadLines( const char* filename, Function _Func ) { const int MAX_LINE_SIZE = 30; char line[MAX_LINE_SIZE]; ifstream file( filename ); while( file.getline( line, MAX_LINE_SIZE, '\n' ) ) _Func( line ); file.close(); } struct StopWatch { StopWatch() { ::QueryPerformanceFrequency( &Freq_ ); } void Start() { ::QueryPerformanceCounter( &Start_ ); } void End() { ::QueryPerformanceCounter( &End_ ); End_.QuadPart -= Start_.QuadPart; } __int64 ElapsedTicks() { return End_.QuadPart; } double ElapsedTime() { return static_cast<double>(ElapsedTicks()) / Freq_.QuadPart; } private LARGE_INTEGER Freq_, Start_, End_; }; int main() { vector<string> result; StopWatch sw; sw.Start(); //CanonicalizedValues values( "AALNSTI?" ); CanonicalizedValues values( "A????" ); //CanonicalizedValues values( "AALNST?" ); ReadLines ( "C:\\Users\\Fabio Galuppo\\Documents\\twl06_adapted.txt", FindMatches ( values, result ) ); sw.End(); copy( result.begin(), result.end(), ostream_iterator<string>( cout, "\n" ) ); cout << "Count = " << result.size() << "\n" << "Elapsed Time (s) = " << sw.ElapsedTime() << "\n" << "Elapsed Ticks = " << sw.ElapsedTicks() << "\n"; } Next time, I'll (hope to) improve the sample to reading (applying lambdas and others C++0x features) and performance (using concurrency features - probably a boost threads approach and PPL approach). November 18 Watching directory AND Application Restart/RecoveryThis is a sample using Visual C++ and Windows API that works with Windows Vista or later.
The main purpose is to show how to use Standard C++ Library TR1 Extensions Reference, directory change notification and application restart/recovery (ARR) in native code.
#include <windows.h> #include <process.h> #include <iostream> #include <functional> using namespace std; using namespace std::tr1; #ifdef _UNICODE #define _tcout wcout #define _tstring wstring #else #define _tcout cout #define _tstring string #endif class DirectoryWatcher { public: typedef std::tr1::function<void (LPCTSTR)> NotifyChangeHandler; DirectoryWatcher( const wstring& dir, NotifyChangeHandler changeCallback ) : Dir_(dir), Started_(false), ChangeCallback_(changeCallback) { } void Start() { if( !Started_ ) { Started_ = true; unsigned int threadId; HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex( NULL, 0, WatchDirectory, this, NULL, &threadId )); CloseHandle(threadHandle); } } private: static unsigned int WINAPI WatchDirectory( LPVOID pArguments ) { DirectoryWatcher* w = reinterpret_cast<DirectoryWatcher*>(pArguments); w->_WatchDirectory(); return 0; } void _WatchDirectory() { LPCTSTR dir = Dir_.c_str(); HANDLE handleToWatch = FindFirstChangeNotification( dir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME ); if ( INVALID_HANDLE_VALUE == handleToWatch ) ExitProcess(GetLastError()); while (TRUE) { if( WAIT_OBJECT_0 == WaitForSingleObject( handleToWatch, INFINITE ) ) { ChangeCallback_( dir ); if ( !FindNextChangeNotification( handleToWatch ) ) ExitProcess(GetLastError()); } else { ExitProcess(GetLastError()); } } } private: DirectoryWatcher(){} DirectoryWatcher( const DirectoryWatcher& ){} DirectoryWatcher& operator=( const DirectoryWatcher& ){} const wstring Dir_; bool Started_; NotifyChangeHandler ChangeCallback_; }; void OnDirectoryChange( LPCTSTR lpDir ) { _tcout << TEXT("Refresh the directory ") << lpDir << endl; } typedef std::tr1::function<void (void)> DoRecoveryHandler; DWORD WINAPI PrepareToRecover( PVOID pArgument ) { BOOL bCanceled = FALSE; _tcout << TEXT("Preparing recovery...\n"); ApplicationRecoveryInProgress( &bCanceled ); if (!bCanceled) { if( pArgument ) { DoRecoveryHandler* recoveryFun = reinterpret_cast<DoRecoveryHandler*>(pArgument); (*recoveryFun)(); } } else { _tcout << TEXT("Recovery was canceled by the user.\n"); } _tcout << TEXT("Recovery completed...\n"); ApplicationRecoveryFinished((bCanceled) ? FALSE: TRUE); return 0; } void RecoverFromRestart() { _tcout << TEXT("Perform recovery from restart...\n"); } bool IsApplicationRestarting( const _tstring& cmdLine, LPCWSTR restartFlag ) { return _tstring::npos != cmdLine.find( restartFlag ); } void OnDoCustomRecover() { _tcout << TEXT("Custom recovery procedure...\n"); } int main() { _tstring cmdLine( GetCommandLine() ); LPCWSTR restartFlag = TEXT("/restart"); bool isAppRestarting = IsApplicationRestarting( cmdLine, restartFlag ); _tcout << TEXT("Command Line = ") << cmdLine.c_str() << TEXT("\n"); if( isAppRestarting ) RecoverFromRestart(); HRESULT hr = RegisterApplicationRestart( restartFlag, 0 ); if( FAILED( hr ) ) { _tcout << TEXT("Restart registration failed\n"); return 1; } DoRecoveryHandler customRecovery( OnDoCustomRecover ); hr = RegisterApplicationRecoveryCallback( PrepareToRecover, &customRecovery, RECOVERY_DEFAULT_PING_INTERVAL, 0 ); if( FAILED( hr ) ) { _tcout << TEXT("Recovery registration failed\n"); return 2; } DirectoryWatcher dw( TEXT("D:\\Test\\"), OnDirectoryChange ); dw.Start(); if( !isAppRestarting ) { //force restarting... Sleep(60 * 1000 + 1 * 1000); RaiseException( EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_NONCONTINUABLE_EXCEPTION, NULL, NULL ); } else { //continue... Sleep( 60 * 60 * 1000 ); } } According to ARR documentation: "To prevent cyclical restarts, the system will only restart the application if it has been running for a minimum of 60 seconds." June 24 Two versions for Lock-Free StackThe two codes below are implementations of lock-free stack structure.
The purpose is the same, but the first version can be ported easily to other OSes.
Performance benchmark is a lesson to the reader.
The raw C++ implementation. In C++0x we'll change Interlocked APIs to atomic operations:
template <typename T>struct LockFreeStack { LockFreeStack() : Head_( NULL ){} void Push( T& value ) { PNODE node = new NODE( value ); PNODE oldHead; do { node->Next = oldHead = Head_; }while( oldHead != reinterpret_cast<PNODE>( InterlockedCompareExchangePointer( reinterpret_cast<volatile PVOID*>(&Head_), node, oldHead ))); } T Pop() { PNODE node; PNODE oldHead; do { oldHead = Head_; }while( oldHead != (node = reinterpret_cast<PNODE>( InterlockedCompareExchangePointer( reinterpret_cast<volatile PVOID*>(&Head_), Head_->Next, oldHead )))); T temp = node->Data; delete node; return temp; } private: typedef struct NODE_TAG { NODE_TAG( T value ) : Next(NULL), Data(value){} NODE_TAG* Next; T Data; } NODE, *PNODE; PNODE Head_; LockFreeStack( const LockFreeStack& ){} LockFreeStack& operator=( const LockFreeStack& ){} };
template<typename T> Item_->Value = value;
Entry_ = InterlockedPushEntrySList( Head_, &Item_->Entry ); } T Pop() { PSLIST_ENTRY tempEntry = InterlockedPopEntrySList( Head_ ); if( NULL == tempEntry ) throw "stack is empty"; Item_ = reinterpret_cast<PITEM>( tempEntry ); T temp = Item_->Value; _aligned_free( tempEntry ); return temp; } private: typedef struct ITEM_TAG { SLIST_ENTRY Entry; T Value; } ITEM, *PITEM; PSLIST_ENTRY Entry_; PSLIST_HEADER Head_; PITEM Item_; template <class M> M* new_aligned() { return reinterpret_cast<M*>(_aligned_malloc( sizeof(M), MEMORY_ALLOCATION_ALIGNMENT )); } LockFreeStack( const LockFreeStack& ){} LockFreeStack& operator=( const LockFreeStack& ){} }; June 13 Samples from my Concurrency Talk at Seminário TempoReal C++ Portabilidade e PerformanceSamples from my Concurrency Talk at Seminário TempoReal C++ Portabilidade e Performance:
The following code is a C++ port to one of my previous samples: MapReduce with Parallelspace
#include <iostream>#include <fstream> #include <vector> #include <map> #include <string> #include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/filesystem.hpp> #include <boost/function.hpp> #include <boost/algorithm/string.hpp> using namespace std; using namespace boost; using namespace boost::filesystem; void get_files( const path& directory, vector<path>& files ) { directory_iterator end_iter; for( directory_iterator iter( directory ); iter != end_iter; ++iter ) { if( is_directory( iter->status() ) ) continue; files.push_back( iter->path() ); } } int get_ProcessorCount(){ return 2; } class TaskExecutor
{ typedef function2<void, map<string, int>&, const map<string, int>&> ConsolidationFunctionType; typedef function1<map<string, int>, const path&> CountWordsFunctionType; public:
TaskExecutor( vector<path>::const_iterator begin, vector<path>::const_iterator end, const CountWordsFunctionType countWords, const ConsolidationFunctionType consolidation, map<string, int>& result ) : Begin_( begin ), End_( end ), CountWordsFunction_( countWords ), ConsolidationFunction_( consolidation ), Result_( result ){} void operator()() { for( vector<path>::const_iterator iter = Begin_; iter != End_; ++iter ) ConsolidationFunction_( Result_, CountWordsFunction_( *iter ) ); } private: vector<path>::const_iterator Begin_, End_; const ConsolidationFunctionType ConsolidationFunction_; const CountWordsFunctionType CountWordsFunction_; map<string, int>& Result_; }; void key_count( map<string, int>& dictionary, const string& word, int value ) { dictionary[ word ] = dictionary.end() != dictionary.find( word ) ? dictionary[ word ] + value : value; } map<string, int> map_function( const path& filename ) { map<string, int> wordCount; ifstream file; const int MAXLEN = 1024; char line[ MAXLEN ]; file.open( filename.directory_string().c_str() ); while( file.getline( line, MAXLEN ) )
{ vector<string> split_v; split( split_v, string( line ), is_any_of( " " ) ); for( vector<string>::const_iterator iter = split_v.begin(); iter != split_v.end(); ++iter ) key_count( wordCount, *iter, 1 ); } file.close();
return wordCount;
} void reduce_function( map<string, int>& destination, const map<string, int>& source ) { for( map<string, int>::const_iterator iter = source.begin(); iter != source.end(); ++iter ) key_count( destination, iter->first, iter->second ); } void wordcount_mapreduced( const vector<path>& files, map<string, int>& wordCount ) { //data partition int numberOfPartitions = get_ProcessorCount() * 2; //2 threads per core int numberOfFiles = static_cast<int>( files.size() ); if( numberOfFiles < numberOfPartitions ) numberOfPartitions = numberOfFiles; int delta = numberOfFiles / numberOfPartitions; vector< map<string, int> > result( numberOfPartitions ); thread_group tg; //for parallel
for( int step = 0; step < numberOfPartitions; ++step ) { vector<path>::const_iterator begin = files.begin() + delta * step, end = numberOfPartitions - 1 == step ? files.end() : files.begin() + delta * step + delta; //fork tg.create_thread( TaskExecutor( begin, end, map_function, reduce_function, result[step] ) ); } //join tg.join_all(); for( vector< map<string, int> >::const_iterator iter = result.begin(); iter != result.end(); ++iter ) reduce_function( wordCount, *iter ); } int main() { vector<path> files; get_files( "c:\\txttest\\", files ); map<string, int> wordCount; wordcount_mapreduced( files, wordCount ); for( map<string, int>::const_iterator iter = wordCount.begin(); iter != wordCount.end(); ++iter ) cout << iter->first << " = " << iter->second << endl; } February 25 Get the size of directories from all drives with F#This small F# utility uses recursion to inspect all directories from all drives installed (including network drives mapped).
The sizes are printed in the console screen (or could be redirected).
#light
open System.IO open System let ConvertTo (n:int64) (d:float) = n / Convert.ToInt64( d ) //let ConvertToMegabytes (n:int64) = ConvertTo n (1024.0 ** 2.0) let ConvertToKilobytes (n:int64) = ConvertTo n 1024.0 let rec getSizeOfDir (path:string) = let getSizeOfFiles (dir:string) = try DirectoryInfo(dir).GetFiles() |> Seq.sumByInt64( fun file -> file.Length ) with | :? UnauthorizedAccessException -> 0L; try let size = (Directory.GetDirectories( path ) |> Seq.sumByInt64( fun dir -> getSizeOfDir( dir ) )) + getSizeOfFiles( path ) printfn "Path = %s\r\nSize = %d KB (%d bytes)\r\n" path (ConvertToKilobytes size) size size with | :? UnauthorizedAccessException -> 0L | :? IOException -> 0L; let main = let sw = new Diagnostics.Stopwatch() let tm = DateTime.Now sw.Start() DriveInfo.GetDrives() |> Seq.iter( fun drv -> getSizeOfDir drv.Name |> ignore ) sw.Stop() printfn "\r\n\r\nElapsed time = %s" (sw.Elapsed.ToString()) This utility could run better if reworked to support threads. Maybe next time...
February 07 XNA, Visual C++ and Guitar HeroIs it possible to write XNA programs with Visual C++? Yes, it is! Someone show that is possible in F#, too. The XNA Game Studio 2.0 can be installed inside Visual Studio 2005 Professional (the previous version is hosted only in VC# Express). The sample below is a Guitar Hero Panel. You plug-in a guitar on PC, and press Fret buttons, Strum bar and Whammy bar to see the feedback. (This sample doesn´t have sounds, just visual feedback) How can you do to write your own XNA programs with Visual C++?
1. Create a XNA Windows Game (or XNA Xbox 360 Game) project with C#. (C# will be the host of the C++/CLI dll. C# is necessary to compile Game Assets like images, fonts, ...)
2. Add a new project Visual C++ CLR Class Library into the current solution. The XNA program will be coded entirely in C++/CLI, here. Is very important (if you want to port to Xbox 360) to compile this project with /clr:safe switch. This ensure that the generated code is MSIL-only. Add reference to the assemblies: Microsoft.Xna.Framework.dll and Microsoft.Xna.Framework.Game.dll. They are at Microsoft XNA install dir something like: <XNA install dir>\XNA Game Studio\v2.0\References\Windows\x86\
3. Add a reference to the VC++ CLR DLL in the C# project. And call the game class written in C++/CLI, at Main method in C# code. (You even have the ability to debug step-by-step)
The following code is the C++/CLI game program. If you look with attention you see that we have templates and stack semantics:
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics; using namespace Microsoft::Xna::Framework::Input; namespace GuitarHeroControlPanel { ref struct Piece { Piece( Texture2D^ image, Vector2 position, SpriteBatch^ spriteBatch ) : Display_( false ), Image_( image ), Position_( position ), SpriteBatch_( spriteBatch ){} void Update( bool displayStatus ){ Display_ = displayStatus; } void Draw(){ if( Display_ ) SpriteBatch_->Draw( Image_, Position_, Color::White ); } private: bool Display_; Vector2 Position_; Texture2D^ Image_; SpriteBatch^ SpriteBatch_; }; public ref class GuitarHeroControlPanel : Game { public: GuitarHeroControlPanel() { Graphics_ = gcnew GraphicsDeviceManager(this); Graphics_->PreferredBackBufferWidth = 1280; Graphics_->PreferredBackBufferHeight = 416; Window->Title = "Guitar Hero Panel by Fabio Galuppo. Implemented with XNA and Visual C++ 2005. Visit: http://www.gamecultura.com.br/. Blog: http://fabiogaluppo.spaces.live.com/"; Content->RootDirectory = "Content"; } private: template<class T> T^ CntLoad( System::String^ assetName ){ return Content->Load<T^>( assetName ); } template<PlayerIndex P> GamePadButtons GetButtons(){ return GamePad::GetState(P).Buttons; } template<PlayerIndex P> GamePadDPad GetDPad(){ return GamePad::GetState(P).DPad; } template<PlayerIndex P> GamePadThumbSticks GetThumbSticks(){ return GamePad::GetState(P).ThumbSticks; } bool IsPressed( ButtonState bs ){ return bs == ButtonState::Pressed; } protected: virtual void LoadContent() override { SpriteBatch_ = gcnew SpriteBatch(GraphicsDevice); Font_ = CntLoad<SpriteFont>( "Tahoma" ); GuitarTexture_ = CntLoad<Texture2D>( "guitarhero" ); GCLogo_ = CntLoad<Texture2D>( "gclogo" ); VCLogo_ = CntLoad<Texture2D>( "vclogo" ); GreenFret_ = gcnew Piece( CntLoad<Texture2D>( "green" ), Vector2(965.0, 0.0), SpriteBatch_ ); RedFret_ = gcnew Piece( CntLoad<Texture2D>( "red" ), Vector2(930.0, 0.0), SpriteBatch_ ); YellowFret_ = gcnew Piece( CntLoad<Texture2D>( "yellow" ), Vector2(895.0, 0.0), SpriteBatch_ ); BlueFret_ = gcnew Piece( CntLoad<Texture2D>( "blue" ), Vector2(858.0, 0.0), SpriteBatch_ ); OrangeFret_ = gcnew Piece( CntLoad<Texture2D>( "orange" ), Vector2(821.0, 0.0), SpriteBatch_ ); Strum_ = gcnew Piece( CntLoad<Texture2D>( "strum" ), Vector2(269.0, 0.0), SpriteBatch_ ); Whammy_ = gcnew Piece( CntLoad<Texture2D>( "whammy" ), Vector2(0.0, 259.0), SpriteBatch_ ); GCLogoVec_ = Vector2( 895.0 , 0.0 ); VCLogoVecPos_ = Vector2( 250.0, 130.0 ); VCLogoVecOri_ = Vector2( VCLogo_->Width / 2.0f, VCLogo_->Height / 2.0f ); FontVec_ = Vector2( 880.0, 380.0 ); } virtual void Update(GameTime^ gameTime) override { if ( IsPressed( GetButtons<PlayerIndex::One>().Back ) ) Game::Exit(); //Fret Buttons GreenFret_->Update( IsPressed( GetButtons<PlayerIndex::One>().A ) ); RedFret_->Update( IsPressed( GetButtons<PlayerIndex::One>().B ) ); YellowFret_->Update( IsPressed( GetButtons<PlayerIndex::One>().Y ) ); BlueFret_->Update( IsPressed( GetButtons<PlayerIndex::One>().X ) ); OrangeFret_->Update( IsPressed( GetButtons<PlayerIndex::One>().LeftShoulder ) ); //Strum Bar Strum_->Update( IsPressed( GetDPad<PlayerIndex::One>().Up ) || IsPressed( GetDPad<PlayerIndex::One>().Down ) ); //Whammy Bar Whammy_->Update( GetThumbSticks<PlayerIndex::One>().Right.X >= 0.0 ); Game::Update(gameTime); } virtual void Draw(GameTime^ gameTime) override { Graphics_->GraphicsDevice->Clear(Color::CornflowerBlue); Game::Draw(gameTime); SpriteBatch_->Begin(); SpriteBatch_->Draw( GuitarTexture_, Vector2::Zero, Color::White ); GreenFret_->Draw(); RedFret_->Draw(); YellowFret_->Draw(); BlueFret_->Draw(); OrangeFret_->Draw(); Strum_->Draw(); Whammy_->Draw(); SpriteBatch_->Draw( GCLogo_, GCLogoVec_, Color::White ); SpriteBatch_->Draw( VCLogo_, VCLogoVecPos_, NullRect_, Color::White, -45.0, VCLogoVecOri_, 1.0, SpriteEffects::None, 0.0 ); SpriteBatch_->DrawString( Font_, "http://fabiogaluppo.spaces.live.com/", FontVec_, Color::Black ); SpriteBatch_->End(); } private: GraphicsDeviceManager^ Graphics_; SpriteBatch^ SpriteBatch_; Texture2D ^GuitarTexture_, ^GCLogo_, ^VCLogo_; Vector2 GCLogoVec_, VCLogoVecPos_, VCLogoVecOri_, FontVec_; System::Nullable<Rectangle> NullRect_; SpriteFont^ Font_; Piece ^GreenFret_, ^RedFret_, ^YellowFret_, ^BlueFret_, ^OrangeFret_, ^Strum_, ^Whammy_; }; }; The C# host program:
using System;
namespace GuitarHeroControlPanel { static class Program { static void Main() { using (GuitarHeroControlPanel panel = new GuitarHeroControlPanel()) panel.Run(); } } } Do you like games? Stay tuned at GameCultura January 03 TechEd Brasil 2007 - TxF Demo #5How to consume the TxF wrapper with C#:
using System;
using System.Transactions; using System.IO; class Program { static void Main(string[] args) { using (TransactionScope scope = new TransactionScope()) { using (StreamWriter sw = new StreamWriter(NTFS.Transactional.File.OpenTransacted("c:\\ManagedNTFSTx.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) for (int i = 0; i < 1000; ++i) sw.WriteLine("Hello World"); scope.Complete(); //omit this line to rollback transaction } using (TransactionScope scope = new TransactionScope()) { NTFS.Transactional.File.CopyTransacted("c:\\ManagedNTFSTx.txt", "c:\\ManagedNTFSTxClone.txt", true); scope.Complete(); //omit this line to rollback transaction } } } TechEd Brasil 2007 - TxF Demo #4This managed wrapper is inspired/adapted/improved from this article.
It supports some NTFS transactional file operations like copy, delete, create and open.
using System;using System.IO; using System.Security; using System.Runtime.InteropServices; using System.Runtime.ConstrainedExecution; using System.Runtime.CompilerServices; using Microsoft.Win32.SafeHandles; using System.Transactions; namespace NTFS.Transactional { [ComImport, Guid("79427A2B-F895-40e0-BE79-B57DC82ED231"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IKernelTransaction { int GetHandle(out IntPtr pHandle); } [SuppressUnmanagedCodeSecurity] static class WindowsAPI { [DllImport("kernel32.dll", SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static extern SafeFileHandle CreateFileTransacted ( string lpFileName, Constants.FileAccess dwDesiredAccess, Constants.FileShare dwShareMode, IntPtr lpSecurityAttributes, Constants.FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile, IntPtr hTransaction, IntPtr pusMiniVersion, IntPtr pExtendedParameter ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static extern bool CopyFileTransacted ( string lpExistingFileName, string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData, ref bool pbCancel, Constants.CopyFile dwCopyFlags, IntPtr hTransaction ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static extern bool DeleteFileTransacted ( string file, IntPtr transaction ); public static bool SUCCEDDED(int hr) { return hr == Constants.ERROR_SUCCESS; } public static void ThrowsLastError() { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } public static class Constants { public const int ERROR_SUCCESS = 0x0; [Flags] public enum FileAccess { GENERIC_READ = unchecked((int)0x80000000), GENERIC_WRITE = 0x40000000 } [Flags] public enum FileShare { FILE_SHARE_NONE = 0x0, FILE_SHARE_READ = 0x1, FILE_SHARE_WRITE = 0x2, FILE_SHARE_DELETE = 0x4 } public enum FileMode { CREATE_NEW = 0x1, CREATE_ALWAYS = 0x2, OPEN_EXISTING = 0x3, OPEN_ALWAYS = 0x4, TRUNCATE_EXISTING = 0x5 } [Flags] public enum CopyFile { COPY_FILE_FAIL_IF_EXISTS = 0x1, COPY_FILE_RESTARTABLE = 0x2, COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x4, COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x8, COPY_FILE_COPY_SYMLINK = 0x800 } } } public static class File { public static void DeleteTransacted(string path) { using (KernelTransactionHandle transactionHandle = KernelTransactionHandle.Get()) if (!WindowsAPI.DeleteFileTransacted(path, transactionHandle.DangerousGetHandle())) WindowsAPI.ThrowsLastError(); } public static void CopyTransacted(string from, string to, bool overwrite) { using (KernelTransactionHandle transactionHandle = KernelTransactionHandle.Get()) { bool cancel = false; if (!WindowsAPI.CopyFileTransacted ( from, to, IntPtr.Zero, IntPtr.Zero, ref cancel, overwrite ? 0 : WindowsAPI.Constants.CopyFile.COPY_FILE_FAIL_IF_EXISTS, transactionHandle.DangerousGetHandle() ) ) WindowsAPI.ThrowsLastError(); } } public static FileStream OpenTransacted(string path, FileMode mode, FileAccess access, FileShare share) { using (KernelTransactionHandle transactionHandle = KernelTransactionHandle.Get()) { SafeFileHandle fileTransactedHandle = WindowsAPI.CreateFileTransacted ( path, ToNativeFileAccess(access), ToNativeFileShare(share), IntPtr.Zero, ToNativeFileMode(mode), 0, IntPtr.Zero, transactionHandle.DangerousGetHandle(), IntPtr.Zero, IntPtr.Zero ); if (fileTransactedHandle.IsInvalid) WindowsAPI.ThrowsLastError();
return new FileStream(fileTransactedHandle, access); } } static WindowsAPI.Constants.FileAccess ToNativeFileAccess(FileAccess access) { if (FileAccess.Read == access) return WindowsAPI.Constants.FileAccess.GENERIC_READ; else if (FileAccess.Write == access) return WindowsAPI.Constants.FileAccess.GENERIC_WRITE; return WindowsAPI.Constants.FileAccess.GENERIC_READ | WindowsAPI.Constants.FileAccess.GENERIC_WRITE; } static WindowsAPI.Constants.FileMode ToNativeFileMode(FileMode mode) { return (WindowsAPI.Constants.FileMode)(int)(FileMode.Append == mode ? FileMode.OpenOrCreate : mode); } static WindowsAPI.Constants.FileShare ToNativeFileShare(FileShare share) { return (WindowsAPI.Constants.FileShare)(int)share; } } public class KernelTransactionHandle : SafeHandleZeroOrMinusOneIsInvalid { internal KernelTransactionHandle(IntPtr existingHandle) : this(existingHandle, true) { } internal KernelTransactionHandle(IntPtr existingHandle, bool ownsHandle) : base(true) { this.SetHandle(existingHandle); } protected override bool ReleaseHandle() { return WindowsAPI.CloseHandle(handle); } public static KernelTransactionHandle Get() { return Get(Transaction.Current); }
public static KernelTransactionHandle Get(Transaction transaction) { if (null == transaction) throw new NullReferenceException(); IKernelTransaction kernelTransaction = TransactionInterop.GetDtcTransaction(transaction) as IKernelTransaction; KernelTransactionHandle transactionHandler = null; RuntimeHelpers.PrepareConstrainedRegions(); try { } //CER Scope finally
{ IntPtr txHandle; int hr = kernelTransaction.GetHandle(out txHandle); if (!WindowsAPI.SUCCEDDED(hr)) throw new System.ComponentModel.Win32Exception(hr);
transactionHandler = new KernelTransactionHandle(txHandle); } //CER Scope return transactionHandler; } } } |
|||||
|
|