HUD basics using SharpDX: How to Draw over the screen surface?
Asked Answered
A

1

4

Scenario

I'm planning to learn the basics about how to develop a custom HUD for a 3rd party PC-game (free, legal), my intention is to develop an application that will draw/show additional info on the screen (by reading mem addresses).

So I've researched for profesional projects and I've found TurboHUD that uses SharpDX library to draw objects/overlays/text over the screen using that DirectX based library and the results are very good (it does not loose performancy at any moment when drawing multiple objects on the screen), but, since the author of that project does not provide a source to understand how they did it then I'm trying to learn by myself to use the same professional technics.

Question

If I'm on the wrong way or I missed some other better alternatives than SharpDX to develop this, please let me know.

My main question is:

In C# or preferably VB.Net, how I could just draw efficiently a custom string over the screen using SharpDX?.

Note that I could set the Form's oppacity to 0 but I think it should exists a proper way and I'm asking to know that proper way to draw directlly on the "desktop" screen.

My expects are to launch that PC-Game, then launch my custom HUD that will draw over the "desktop" screen surface to add additional info on the game, I hope you understand me.

Research

I should clarify that I'm totally unexperienced whit this kind of DirectX libs, and I'm using the SharpDX samples package to try learn its usage.

Since all the samples are in C# its more difficult to learn its usage under VB.Net.

Inside the SharpDX samples package there is an 'AdvancedTextRenderingApp' C# project, but as its name says it is an advanced example and also it instances a custom Form (a SharpDX.Windows.RenderForm) to draw on that Form.

This is the an VB.Net code translation of that C# project that I mentioned:

http://pastebin.com/KG2c3v09


UPDATE:

Just with the intention to comment about a research I did:

I recentlly discovered this useful GitHub repository, however, it fails to compile in Visual Studio 2015 (because missing namespace usings, that when added they generate more compiler errors), also it is oriented for advanced SharpDX users, and after analyzed the full sample I still don't have any idea of how to write/draw over the surface of a 3rd part process window ...also the C# syntax difficults me the overall understanding of SharpDX usage, because also the author did custom implementations a big variety of SharpDX members, then... I'm more than lost with all those examples.

The official SharpDX samples are another of those things that seems very useful ...maybe for advanced users. Some samples seems that demonstrates how to render a custom window/surface (with 500 tedious and incomprehensible lines of code to do it. And their "Hello world" sample is a nightmare for me.), however, what I would like to acchieve as I explained in my question is to draw on the surface of an existing window of another process, and I'm aware that probablly for that I would need to render a "surface" from scratch with SharpDX, then positionate it in the target window, then make invisible the surface, then draw on it, but I don't know how to do those things.

Aeciospore answered 10/3, 2015 at 10:14 Comment(7)
What sort of reasonable reason could have a person to vote a closure of this question?, really I can't understand it.Aeciospore
You can not draw directly on screen as the game will erase your drawings. You need a transparent window. It says so in your link paint on a transparent Direct2D window. Your goal is easy but unfortunately I haven't use SharpDX, only C, C++. I have however used XNA in the past. If there are no answers with SharpDX, I will give you an example with XNA.Ventral
@γηράσκω δ' αεί πολλά διδασκόμε thanks for comment. I'm reading on wikipedia the XNA description, are you sure this is what I need?, it seems to be a toolkit for video game development (and the extended knowledges that should require), please keep in mind that my app will not be a game, will be a Cheating app, just an app that will "extract" info from the game (memory reading) then draw that info on the screen while I'm playing to the 3rd party game, just a simple HUD application. Anyways, if you consider that XNA is a good approach then as I've said I'm open to suggestions, of course, thanks.Aeciospore
You are correct about the XNA. Maybe it will not do what you want. I will try it though and report.Ventral
@Aeciospore are you still looking for a solution to this?Clere
@Zaggler yes, I started a bounty. Please see the bounty comments on where I describe what I need. Thanks for comment.Aeciospore
I'm starting to lose all the hope to receive help for this bounty/question. If someone is reading this, could you guys please guide me a little bit here via comments at least?. Just not an answer, maybe some kind of suggestions for DX novices like me, or documentation, GitHub samples demonstrating this, or any other thing that could help me to understand how I could start reproducing the XNA's solution of @γηράσκω δ' αεί πολλά διδασκόμε using SharpDX instead (like TurboHUD app does). Thanks.Aeciospore
N
11

It took me a while to find how to load the font in XNA to draw the text but everything works fine.

You need 4 things:

  1. Make form topmost
  2. Extend aero glass style to whole form (for transparency to work)
  3. Initialize XNA, Microsoft XNA Game Studio 4.0
  4. Draw the texture and text

One limitation

The game must not be in fullscreen mode. The same as the TurboHUD limitation

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using System.Runtime.InteropServices;
using System.Drawing;

namespace XNATransparentWindow
{
    public partial class Form1 : Form
    {
        private ContentBuilder contentBuilder;

        public Form1()
        {
            InitializeComponent();

            TopMost = true;

            FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

            MARGINS margins = new MARGINS();

            margins.leftWidth = 0;
            margins.rightWidth = 0;
            margins.topHeight = this.Width;
            margins.bottomHeight = this.Height;

            // Extend aero glass style to whole form
            DwmExtendFrameIntoClientArea(this.Handle, ref margins);

            //Load XNA directX
            this.contentBuilder = new ContentBuilder();

            graphicsDeviceService = GraphicsDeviceService.AddRef(Handle, ClientSize.Width, ClientSize.Height);

            //Register the service, so components like ContentManager can find it.
            services.AddService<IGraphicsDeviceService>(graphicsDeviceService);

            //Get the Graphics device
            dev = graphicsDeviceService.GraphicsDevice;
            if(dev == null){/*error message*/}

            //Load texture
            int bufferSize;
            System.IO.MemoryStream memoryStream;
            Bitmap img;

            using (img  = new Bitmap(@"C:\...\.png"))
            {
                bufferSize = img.Height * img.Width * 4;

                memoryStream = new System.IO.MemoryStream(bufferSize);
                img.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);

                memoryStream.Seek(0, SeekOrigin.Begin);
                texture = Texture2D.FromStream(dev, memoryStream, img.Width, img.Height, false);

                memoryStream.Close();
                if(texture == null){/*error message*/}
            }

            //Create sprite
            s_Batch = new SpriteBatch(dev);
            if(s_Batch == null){/*error message*/}

            FontPos = new Vector2(270.0F, 110.0F);

            //Load font
            contentManager = new ContentManager(services, this.contentBuilder.OutputDirectory);

            this.contentBuilder.Clear();

            this.contentBuilder.Add(@"C:\...\my_font1.spritefont","my_font1", "FontDescriptionImporter", "FontDescriptionProcessor");

            //Build spritefont to get the .xbn file
            string error = this.contentBuilder.Build();

            //If build fail
            if (!String.IsNullOrEmpty(error))
            {
                MessageBox.Show(error);
                return;
            }

            //Load the .xbn file
            Font1 = contentManager.Load<SpriteFont>("my_font1");
            if(Font1 == null){/*error message*/}
        }

        [DllImport("dwmapi.dll")]
        static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margin);

        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);

        [StructLayout(LayoutKind.Sequential)]
        public struct MARGINS
        {
            public int leftWidth;
            public int rightWidth;
            public int topHeight;
            public int bottomHeight;
        }

        public ServiceContainer Services
        {
            get { return services; }
        }

        ServiceContainer services = new ServiceContainer();

        GraphicsDevice dev;
        SpriteFont Font1;
        Vector2 FontPos;
        SpriteBatch s_Batch;
        Texture2D texture;
        ContentManager contentManager;
        GraphicsDeviceService graphicsDeviceService;
        private const UInt32 WM_NCLBUTTONDOWN = 0xA1;
        private const Int32 HTCAPTION = 0x2;

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                this.Close();
            }
            else //to move the form
            {
                this.Capture = false;
                SendMessage(this.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            //There are two buffers. One offscreen-backbuffer and the 
            //frontbuffer which is the actual form in this example. The
            //drawings are done to the backbuffer and in the end the two
            //buffers flip. The backbuffer becomes frontbuffer and the
            //frontbuffer becomes backbuffer.

            //The drawing should start when the last resource is loaded.
            //Since Font1 is the last one in this example I check for this
            if (Font1 == null)
            {
                return;
            }

            //clear the backbuffer with transparent color.
            dev.Clear(Microsoft.Xna.Framework.Color.Transparent);
            //Do all your drawings here

            //draw texture and text with the sprite
            s_Batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);

            s_Batch.Draw(texture, new Microsoft.Xna.Framework.Rectangle(0, 0, this.Width, this.Height), Microsoft.Xna.Framework.Color.White);

            s_Batch.DrawString(Font1, @"XNA FRAMEWORK", FontPos, Microsoft.Xna.Framework.Color.Black);

            s_Batch.End();

            //here the flip is performed
            dev.Present();
        }

        //Release resources
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            graphicsDeviceService.GraphicsDevice.Dispose();
            graphicsDeviceService.Release(true);
            s_Batch.Dispose();
            texture.Dispose();
        }
    }
}

The following classes are just copy-paste from an example XNA 4.0 Content Compiler I found(with minor adjustments). They are used just to load the font for drawing the text:

GraphicsDeviceService.cs

#region File Description
//-----------------------------------------------------------------------------
// GraphicsDeviceService.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
#endregion

// The IGraphicsDeviceService interface requires a DeviceCreated event, but we
// always just create the device inside our constructor, so we have no place to
// raise that event. The C# compiler warns us that the event is never used, but
// we don't care so we just disable this warning.
#pragma warning disable 67

namespace XNATransparentWindow
{
    /// <summary>
    /// Helper class responsible for creating and managing the GraphicsDevice.
    /// All GraphicsDeviceControl instances share the same GraphicsDeviceService,
    /// so even though there can be many controls, there will only ever be a single
    /// underlying GraphicsDevice. This implements the standard IGraphicsDeviceService
    /// interface, which provides notification events for when the device is reset
    /// or disposed.
    /// </summary>
    class GraphicsDeviceService : IGraphicsDeviceService
    {
        #region Fields

        // Singleton device service instance.
        static GraphicsDeviceService singletonInstance;

        // Keep track of how many controls are sharing the singletonInstance.
        static int referenceCount;

        #endregion

        /// <summary>
        /// Constructor is private, because this is a singleton class:
        /// client controls should use the public AddRef method instead.
        /// </summary>
        GraphicsDeviceService(IntPtr windowHandle, int width, int height)
        {
            parameters = new PresentationParameters();
            parameters.BackBufferWidth = Math.Max(width, 1);
            parameters.BackBufferHeight = Math.Max(height, 1);
            parameters.BackBufferFormat = SurfaceFormat.Vector4; // SurfaceFormat.Color;
            parameters.DeviceWindowHandle = windowHandle;
            parameters.PresentationInterval = PresentInterval.Immediate;
            parameters.IsFullScreen = false;

            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, parameters);
        }

        /// <summary>
        /// Gets a reference to the singleton instance.
        /// </summary>
        public static GraphicsDeviceService AddRef(IntPtr windowHandle,
                                                   int width, int height)
        {
            // Increment the "how many controls sharing the device" reference count.
            if (Interlocked.Increment(ref referenceCount) == 1)
            {
                // If this is the first control to start using the
                // device, we must create the singleton instance.
                singletonInstance = new GraphicsDeviceService(windowHandle,
                                                              width, height);
            }

            return singletonInstance;
        }


        /// <summary>
        /// Releases a reference to the singleton instance.
        /// </summary>
        public void Release(bool disposing)
        {
            // Decrement the "how many controls sharing the device" reference count.
            if (Interlocked.Decrement(ref referenceCount) == 0)
            {
                // If this is the last control to finish using the
                // device, we should dispose the singleton instance.
                if (disposing)
                {
                    if (DeviceDisposing != null)
                        DeviceDisposing(this, EventArgs.Empty);

                    graphicsDevice.Dispose();
                }

                graphicsDevice = null;
            }
        }


        /// <summary>
        /// Resets the graphics device to whichever is bigger out of the specified
        /// resolution or its current size. This behavior means the device will
        /// demand-grow to the largest of all its GraphicsDeviceControl clients.
        /// </summary>
        public void ResetDevice(int width, int height)
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);

            parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
            parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);

            graphicsDevice.Reset(parameters);

            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }

        /// <summary>
        /// Gets the current graphics device.
        /// </summary>
        public GraphicsDevice GraphicsDevice
        {
            get { return graphicsDevice; }
        }

        GraphicsDevice graphicsDevice;

        // Store the current device settings.
        PresentationParameters parameters;

        // IGraphicsDeviceService events.
        public event EventHandler<EventArgs> DeviceCreated;
        public event EventHandler<EventArgs> DeviceDisposing;
        public event EventHandler<EventArgs> DeviceReset;
        public event EventHandler<EventArgs> DeviceResetting;
    }
}

ServiceContainer.cs

#region File Description
//-----------------------------------------------------------------------------
// ServiceContainer.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
#endregion

namespace XNATransparentWindow
{
    /// <summary>
    /// Container class implements the IServiceProvider interface. This is used
    /// to pass shared services between different components, for instance the
    /// ContentManager uses it to locate the IGraphicsDeviceService implementation.
    /// </summary>
    public class ServiceContainer : IServiceProvider
    {
        Dictionary<Type, object> services = new Dictionary<Type, object>();


        /// <summary>
        /// Adds a new service to the collection.
        /// </summary>
        public void AddService<T>(T service)
        {
            services.Add(typeof(T), service);
        }

        /// <summary>
        /// Looks up the specified service.
        /// </summary>
        public object GetService(Type serviceType)
        {
            object service;

            services.TryGetValue(serviceType, out service);

            return service;
        }
    }
}

ContentBuilder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;

namespace XNATransparentWindow
{
    public class ContentBuilder : IDisposable
    {
        #region Fields

        // What importers or processors should we load?
        const string xnaVersion = ", Version=4.0.0.0, PublicKeyToken=842cf8be1de50553";

        static string[] pipelineAssemblies =
        {
            "Microsoft.Xna.Framework.Content.Pipeline.FBXImporter" + xnaVersion,
            "Microsoft.Xna.Framework.Content.Pipeline.XImporter" + xnaVersion,
            "Microsoft.Xna.Framework.Content.Pipeline.TextureImporter" + xnaVersion,
            "Microsoft.Xna.Framework.Content.Pipeline.EffectImporter" + xnaVersion,
            "Microsoft.Xna.Framework.Content.Pipeline.AudioImporters" + xnaVersion,
            "Microsoft.Xna.Framework.Content.Pipeline.VideoImporters" + xnaVersion,

            // If you want to use custom importers or processors from
            // a Content Pipeline Extension Library, add them here.
            //
            // If your extension DLL is installed in the GAC, you should refer to it by assembly
            // name, eg. "MyPipelineExtension, Version=1.0.0.0, PublicKeyToken=1234567812345678".
            //
            // If the extension DLL is not in the GAC, you should refer to it by
            // file path, eg. "c:/MyProject/bin/MyPipelineExtension.dll".
        };
        // MSBuild objects used to dynamically build content.
        Project buildProject;
        ProjectRootElement projectRootElement;
        BuildParameters buildParameters;
        List<ProjectItem> projectItems = new List<ProjectItem>();
        //ErrorLogger errorLogger;

        // Temporary directories used by the content build.
        string buildDirectory;
        string processDirectory;
        string baseDirectory;

        // Generate unique directory names if there is more than one ContentBuilder.
        static int directorySalt;

        // Have we been disposed?
        bool isDisposed;

        #endregion

        #region Properties

        /// Gets the output directory, which will contain the generated .xnb files.
        public string OutputDirectory
        {
            get { return Path.Combine(buildDirectory, "bin/Content"); }
        }

        #endregion

        #region Initialization
        /// Creates a new content builder.
        public ContentBuilder()
        {
            CreateTempDirectory();
            CreateBuildProject();
        }

        /// Finalizes the content builder.
        ~ContentBuilder()
        {
            Dispose(false);
        }

        /// Disposes the content builder when it is no longer required.
        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        /// Implements the standard .NET IDisposable pattern.
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                isDisposed = true;

                DeleteTempDirectory();
            }
        }

        #endregion

        #region MSBuild
        /// Creates a temporary MSBuild content project in memory.
        void CreateBuildProject()
        {
            string projectPath = Path.Combine(buildDirectory, "content.contentproj");
            string outputPath = Path.Combine(buildDirectory, "bin");

            // Create the build project.
            projectRootElement = ProjectRootElement.Create(projectPath);

            // Include the standard targets file that defines how to build XNA Framework content.
            projectRootElement.AddImport("$(MSBuildExtensionsPath)\\Microsoft\\XNA Game Studio\\" +
                                         "v4.0\\Microsoft.Xna.GameStudio.ContentPipeline.targets");

            buildProject = new Project(projectRootElement);

            buildProject.SetProperty("XnaPlatform", "Windows");
            buildProject.SetProperty("XnaProfile", "Reach");
            buildProject.SetProperty("XnaFrameworkVersion", "v4.0");
            buildProject.SetProperty("Configuration", "Release");
            buildProject.SetProperty("OutputPath", outputPath);

            // Register any custom importers or processors.
            foreach (string pipelineAssembly in pipelineAssemblies)
            {
                buildProject.AddItem("Reference", pipelineAssembly);
            }

            // Hook up our custom error logger.
            //errorLogger = new ErrorLogger();

            buildParameters = new BuildParameters(ProjectCollection.GlobalProjectCollection);
            //buildParameters.Loggers = new ILogger[] { errorLogger };
        }

        /// Adds a new content file to the MSBuild project. The importer and
        /// processor are optional: if you leave the importer null, it will
        /// be autodetected based on the file extension, and if you leave the
        /// processor null, data will be passed through without any processing.
        public void Add(string filename, string name, string importer, string processor)
        {
            ProjectItem item = buildProject.AddItem("Compile", filename)[0];

            item.SetMetadataValue("Link", Path.GetFileName(filename));
            item.SetMetadataValue("Name", name);

            if (!string.IsNullOrEmpty(importer))
                item.SetMetadataValue("Importer", importer);

            if (!string.IsNullOrEmpty(processor))
                item.SetMetadataValue("Processor", processor);

            projectItems.Add(item);
        }

        /// Removes all content files from the MSBuild project.
        public void Clear()
        {
            buildProject.RemoveItems(projectItems);

            projectItems.Clear();
        }

        /// Builds all the content files which have been added to the project,
        /// dynamically creating .xnb files in the OutputDirectory.
        /// Returns an error message if the build fails.
        public string Build()
        {
            // Create and submit a new asynchronous build request.
            BuildManager.DefaultBuildManager.BeginBuild(buildParameters);

            BuildRequestData request = new BuildRequestData(buildProject.CreateProjectInstance(), new string[0]);
            BuildSubmission submission = BuildManager.DefaultBuildManager.PendBuildRequest(request);

            submission.ExecuteAsync(null, null);

            // Wait for the build to finish.
            submission.WaitHandle.WaitOne();

            BuildManager.DefaultBuildManager.EndBuild();

            // If the build failed, return an error string.
            if (submission.BuildResult.OverallResult == BuildResultCode.Failure)
            {
                //return string.Join("\n", errorLogger.Errors.ToArray());
            }

            return null;
        }

        #endregion

        #region Temp Directories

        /// Creates a temporary directory in which to build content.
        void CreateTempDirectory()
        {
            // Start with a standard base name:
            //
            //  %temp%\WinFormsContentLoading.ContentBuilder

            baseDirectory = Path.Combine(Path.GetTempPath(), GetType().FullName);

            // Include our process ID, in case there is more than
            // one copy of the program running at the same time:
            //
            //  %temp%\WinFormsContentLoading.ContentBuilder\<ProcessId>

            int processId = Process.GetCurrentProcess().Id;

            processDirectory = Path.Combine(baseDirectory, processId.ToString());

            // Include a salt value, in case the program
            // creates more than one ContentBuilder instance:
            //
            //  %temp%\WinFormsContentLoading.ContentBuilder\<ProcessId>\<Salt>

            directorySalt++;

            buildDirectory = Path.Combine(processDirectory, directorySalt.ToString());

            // Create our temporary directory.
            Directory.CreateDirectory(buildDirectory);

            PurgeStaleTempDirectories();
        }

        /// <summary>
        /// Deletes our temporary directory when we are finished with it.
        /// </summary>
        void DeleteTempDirectory()
        {
            Directory.Delete(buildDirectory, true);

            // If there are no other instances of ContentBuilder still using their
            // own temp directories, we can delete the process directory as well.
            if (Directory.GetDirectories(processDirectory).Length == 0)
            {
                Directory.Delete(processDirectory);

                // If there are no other copies of the program still using their
                // own temp directories, we can delete the base directory as well.
                if (Directory.GetDirectories(baseDirectory).Length == 0)
                {
                    Directory.Delete(baseDirectory);
                }
            }
        }


        /// <summary>
        /// Ideally, we want to delete our temp directory when we are finished using
        /// it. The DeleteTempDirectory method (called by whichever happens first out
        /// of Dispose or our finalizer) does exactly that. Trouble is, sometimes
        /// these cleanup methods may never execute. For instance if the program
        /// crashes, or is halted using the debugger, we never get a chance to do
        /// our deleting. The next time we start up, this method checks for any temp
        /// directories that were left over by previous runs which failed to shut
        /// down cleanly. This makes sure these orphaned directories will not just
        /// be left lying around forever.
        /// </summary>
        void PurgeStaleTempDirectories()
        {
            // Check all subdirectories of our base location.
            foreach (string directory in Directory.GetDirectories(baseDirectory))
            {
                // The subdirectory name is the ID of the process which created it.
                int processId;

                if (int.TryParse(Path.GetFileName(directory), out processId))
                {
                    try
                    {
                        // Is the creator process still running?
                        Process.GetProcessById(processId);
                    }
                    catch (ArgumentException)
                    {
                        // If the process is gone, we can delete its temp directory.
                        Directory.Delete(directory, true);
                    }
                }
            }
        }

        #endregion
    }
}

The font which you are loading is an xml file: any_name.spritefont

Example:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>Segoe UI Mono</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>14</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Regular</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

If you want the form to be click-through then you need to add a random transparency key color to form and:

[DllImport("user32.dll", EntryPoint="GetWindowLong")]
static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

In public Form1()

IntPtr initialStyle = GetWindowLongPtr(this.Handle, -20);
SetWindowLong(this.Handle, -20, (IntPtr)((int)initialStyle | 0x20));

Feel free to correct any mistakes I have made.

Nunatak answered 14/3, 2015 at 5:25 Comment(15)
@Aeciospore I can not test if this method works cause you didn't say which game it is.Ventral
I know comments are not to give thanks, but just i will give a big THANKS to show this approach. only one question, why the non-fullscreen mode restriction? I know TurboHUD has the same limitation but I don't understand why.Aeciospore
@Aeciospore What happens with a full screen app is that it doesn't allow any window on top of it. It can be top most or minimized. You can see it when you alt-tab another window when the app is running. It immediately is minimized. I really don't know why. Maybe because it is not even a window. It gets the desktop. Just a guess.Ventral
@γηράσκω δ' αεί πολλά διδ I appreciate your solution and thats why given the bounty but for other tasks and reasons I didn't have time to test your solution in real life until now, then, now I have translated all the code to VBNET and I just can't find the way to make your solution work, I get one ArgumentException and two WaitHandleCannotBeOpenedException, the glassed window is shown but any text inside or anything else because I'm not sure what the project should do after fixing that exceptions, write, show an image, or what? I'm lost. for these reasons I need your help(see next comment)Aeciospore
@γηράσκω δ' αεί πολλά διδ I would like to know whether you could help me to understand and solve the issues about why my simple test project doesn't works, because if I can't run your solution then the only thing I could do is open a new bounty in search of a pure SharpDX solution and that will be a pitty if XNA could work. thanks in advance, this is the test project, in VS2013: mediafire.com/download/qxgratx766nq9pc/XNA+vb+test+project.rar and this XNA for VS2013: mxa.codeplex.com/releases/view/117230Aeciospore
I forgot to say that, I didn't said which game is because I don't have an specific game in mind, just I would like to apply this HUD technique in the future for whatever game, but if I should say a game for testing purposes then I would like to try it with 'Diablo III' game to compare my newbie expected results with 'TurboHUD'.Aeciospore
@Aeciospore Dont worry. We'll make it run in vb.net. Also I have a second idea, but not today, I have work to do. Tomorrow I am going to see your code.Ventral
@Aeciospore Your code works fine BUT you have a mistake in Form2: You use Form1 instead of Form2 for the mouse down, form closing, paint and load events!!Ventral
No, that is not the problem but thanks for say it because I discovered that the event-handlers of Form2 were handling any event, I added the handles again, I also discovered that another of the problems was with loading the texture, I solved both problems and now I can see drawn the "XNA FRAMEWORK" string , but the project still throwing two WaitHandleCannotBeOpenedException and one ArgumentException elsewhere on the project, I cannot locate and resolve them, now your solution works on my side but... with those unknown errors. thanks for your patience.Aeciospore
@Aeciospore Does the C# code works without any issues? I am using VS 2010.Ventral
@γηράσκω δ' αεί πολλά διδασκόμε its very late here, I will try the C# version tomorrow, thanks.Aeciospore
@γηράσκω δ' αεί πολλά διδασκόμε no problem, its fine like this, thanks for your patienceAeciospore
@Aeciospore You can use the code in c# in a dll and call it from vb.net. I have done it and works fine. I'll send you the files.Ventral
@Aeciospore Create a Class Library project in c#. I named it XNAlib. files hereVentral
@Aeciospore And these are the vb files. Reference the dll file you created. Important: Use .NET framework 4 for both not client profile.Ventral

© 2022 - 2024 — McMap. All rights reserved.