使用SharpDX的HUD基础知识:如何绘制屏幕表面?

时间:2015-03-10 10:14:20

标签: c# .net vb.net winforms sharpdx

方案

我计划学习如何为第三方PC游戏(免费,合法)开发自定义HUD的基础知识,我的目的是开发一个应用程序,在屏幕上绘制/显示其他信息(通过阅读mem地址)。

所以我已经针对专业项目进行了研究,并且我发现TurboHUD使用SharpDX库在屏幕上使用 DirectX <绘制对象/叠加/文本/ strong>基于库,结果非常好(在屏幕上绘制多个对象时,它不会失去性能), 但是,由于该项目的作者没有提供理解他们如何做到这一点的来源,所以我试图自己学习使用相同的专业技术。

问题

如果我错误的方式或错过了其他更好的替代品而不是 SharpDX 来开发此产品,请告知我们。

我的主要问题是:

在C#或最好是VB.Net中,如何使用 SharpDX 在屏幕上有效地绘制自定义字符串?

请注意,我可以将Form的反对意见设置为0,但我认为它应该存在一种正确的方式,并且我想要知道直接在桌面上绘制的正确方法&#34 ;屏幕。

我的期望是推出这款PC游戏,然后推出我的自定义HUD,它将吸引&#34;桌面&#34;屏幕表面添加游戏的其他信息,我希望你了解我。

研究

我应该澄清一点,我对这种DirectX库完全缺乏经验,我使用SharpDX示例包尝试了解它的用法。

由于所有样本都在C#中,因此在VB.Net下学习它的使用起来比较困难。

SharpDX 示例包中,有一个&#39; AdvancedTextRenderingApp &#39; C#项目,但正如其名称所说,它是一个高级示例,并且它还实例化了一个自定义表单(SharpDX.Windows.RenderForm)以在该表单上绘制。

这是我提到的C#项目的VB.Net代码翻译:

http://pastebin.com/KG2c3v09


UPDATE:

我打算对我所做的研究发表评论:

我最近发现了 this useful GitHub repository ,然而,它无法在 Visual Studio 2015 中编译(因为缺少名称空间使用,添加时会产生更多编译错误),它也面向高级SharpDX用户,在分析了完整的样本后,我仍然不知道如何在第三部分过程窗口的表面上书写/绘制......还有C#语法困难我对SharpDX的使用情况有了全面的了解,因为作者也做了各种各样的SharpDX成员的自定义实现,然后......我不仅仅是丢失所有这些例子。

official SharpDX samples 是另一个看似非常有用的东西......可能适用于高级用户。一些示例似乎演示了如何渲染自定义窗口/表面(使用500个繁琐且难以理解的代码行来完成它。而且他们的&#34; Hello world &#34;示例是一个噩梦然而,正如我在我的问题中解释的那样,我想要实现的是在另一个过程的现有窗口的表面上绘制,并且我意识到可能的原因我需要渲染一个& #34;表面&#34;从头开始使用SharpDX,然后将其定位在目标窗口中,然后使表面不可见,然后绘制它,但我不知道如何做这些事情。

1 个答案:

答案 0 :(得分:11)

我花了一些时间才找到如何在XNA中加载字体来绘制文本,但一切正常。

你需要4件事:

  
      
  1. 使表格最顶层
  2.   
  3. 将航空玻璃样式扩展为整个表单(透明度可以工作)
  4.   
  5. 初始化XNA,Microsoft XNA Game Studio 4.0
  6.   
  7. 绘制纹理和文字
  8.   

一个限制

  

游戏不得处于全屏模式。与TurboHUD限制相同

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();
        }
    }
}

以下类只是我发现的示例XNA 4.0 Content Compiler的复制粘贴(稍作调整)。它们仅用于加载用于绘制文本的字体:

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
    }
}

您要加载的字体是xml文件:any_name.spritefont

示例:

<?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>

如果您希望单击该表单,则需要随机添加 透明度键颜色形成和:

[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);

public Form1()

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

随意纠正我所犯的任何错误。