跟我一起用C#做LOL换肤工具

小编是一个资深的lol游戏玩家,虽然比较坑,但是也躺赢到了铂金三。

话说小编也是个屌丝初级程序员,身为程序员的我,看到lol 有617个皮肤而身为屌丝的我不能使用,真心伤,后来我就goole baidu各种查资料,最后总结出来,目前修改皮肤的有三种。

第一种这个很牛逼了,修改服务器那边的参数,这个涉及到的东西太多,小编不多说,也没有那个能力。

第二种修改本地内存,达到移花接木的目的,目前市场上收费或者免费的,都已经停止了这种修改的方法,具体原因不详(貌似某讯很厉害,大家都懂的)。

第三种就是传说中的,皮肤挂载(不知道的百度一下)

好了废话不多少,要想做出这个换肤的工具,我分析的结果如下:

1.我们需要准确快速的找到lol的路径

2.创建漂亮的页面

3.用我们的工具去读取lol的数据库 获取他的英雄列表和皮肤图片

4.搭建皮肤文件的FTP 或者放到传说中的云上

5.用工具下载皮肤然后挂载皮肤

6.构建工具的官网

7.工具在线升级的实现

目前我想到的大体就这么多,具体的实现稍后我们一起来搞,小编新手,大神飘过。

小编我下载了几个网上收费或者免费的换肤工具,试了试,发现第一次打开的时候需要,指定游戏目录或自动搜索目录,结果用了一下自动搜索功能,一个字坑,可能不是收费的缘故做的没有那么给力吧!3分钟后搜出来了,你敢信?身为一个经常使用Everything的我怎么能忍受这个速度,我有试用了一些商业的工具,发现人家打开的时候不用指定目录。

 那么问题来了,搜索 C#高效搜索文件  baidu  google 哪家强(好吧这TM还用说当然是baidu,不要问我为什么,我会告诉你长城是世界八大奇迹之一吗?)

结果找到一篇博友写的http://www.cnblogs.com/TianFang/p/3427776.html(大家可以去看看)。

既然有现成的代码,身为懒惰程序员的我必须的Ctrl+a,Ctrl+c,Ctrl+v 你懂的.

当我满心欢喜的用的时候结果:

什么意思啊这不是坑爹啊!赶紧百度一下,哇秒懂,原来是超出int32上限了啊!(我本地C盘的文件比较多导致的 一般32够用了),那么知道原因了,那就好办了,改成int64不就搞定了,(是不是很“牛逼”!!!!!!)。

不过当我看到这个的时候我又迷糊了,为什么DriveInfo能点出来EnumerateFiles方法,难道跟

 

 这个代码有关系?为了不浪费时间我果断找来我同事(牛x程序员)给看看,牛x就是牛x,一语道破,这就是方法的扩展,既然不懂我就搜了一下 http://www.cnblogs.com/potential/archive/2012/11/04/2754148.html看看巩固一下什么是方法的扩展(相信有很多人跟我一样不知道这是什么东东),哎再不学习就老了。

搞明白大神写的代码后,我发现人家只实现了获取某盘的所有文件,但是跟我要找到lol的路径貌似没有什么关系!后来我在人家代码的基础上修改了一下,代码如下:

FileSearch.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
//using Microsoft.VisualBasic;

public class FileSearch
{
    private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
    private const uint GENERIC_READ = 0x80000000;
    private const int FILE_SHARE_READ = 0x1;
    private const int FILE_SHARE_WRITE = 0x2;
    private const int OPEN_EXISTING = 3;
    private const int FILE_READ_ATTRIBUTES = 0x80;
    private const int FILE_NAME_IINFORMATION = 9;
    private const int FILE_FLAG_BACKUP_SEMANTICS = 0x2000000;
    private const int FILE_OPEN_FOR_BACKUP_INTENT = 0x4000;
    private const int FILE_OPEN_BY_FILE_ID = 0x2000;
    private const int FILE_OPEN = 0x1;
    private const int OBJ_CASE_INSENSITIVE = 0x40;
    private const int FSCTL_ENUM_USN_DATA = 0x900b3;

    [StructLayout(LayoutKind.Sequential)]
    private struct MFT_ENUM_DATA
    {
        public long StartFileReferenceNumber;
        public long LowUsn;
        public long HighUsn;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct USN_RECORD
    {
        public int RecordLength;
        public short MajorVersion;
        public short MinorVersion;
        public long FileReferenceNumber;
        public long ParentFileReferenceNumber;
        public long Usn;
        public long TimeStamp;
        public int Reason;
        public int SourceInfo;
        public int SecurityId;
        public FileAttributes FileAttribute;
        public short FileNameLength;
        public short FileNameOffset;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_STATUS_BLOCK
    {
        public int Status;
        public int Information;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING
    {
        public short Length;
        public short MaximumLength;
        public IntPtr Buffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct OBJECT_ATTRIBUTES
    {
        public int Length;
        public IntPtr RootDirectory;
        public IntPtr ObjectName;
        public int Attributes;
        public int SecurityDescriptor;
        public int SecurityQualityOfService;
    }

    //// MFT_ENUM_DATA
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, ref MFT_ENUM_DATA lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern Int32 CloseHandle(IntPtr lpObject);

    [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int NtCreateFile(ref IntPtr FileHandle, int DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes, ref IO_STATUS_BLOCK IoStatusBlock, int AllocationSize, int FileAttribs, int SharedAccess, int CreationDisposition, int CreateOptions, int EaBuffer,
    int EaLength);

    [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int NtQueryInformationFile(IntPtr FileHandle, ref IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, int Length, int FileInformationClass);

    private IntPtr m_hCJ;
    private IntPtr m_Buffer;
    private int m_BufferSize;

    private string m_DriveLetter;

    private class FSNode
    {
        public long FRN;
        public long ParentFRN;
        public string FileName;

        public bool IsFile;
        public FSNode(long lFRN, long lParentFSN, string sFileName, bool bIsFile)
        {
            FRN = lFRN;
            ParentFRN = lParentFSN;
            FileName = sFileName;
            IsFile = bIsFile;
        }

    }


    private IntPtr OpenVolume(string szDriveLetter)
    {

        IntPtr hCJ = default(IntPtr);
        //// volume handle

        m_DriveLetter = szDriveLetter;

        hCJ = CreateFile("\\\\.\\" + szDriveLetter, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

        return hCJ;

    }


    private void Cleanup()
    {
        if (m_hCJ != IntPtr.Zero)
        {
            // Close the volume handle.
            CloseHandle(m_hCJ);
            m_hCJ = INVALID_HANDLE_VALUE;
        }

        if (m_Buffer != IntPtr.Zero)
        {
            // Free the allocated memory
            Marshal.FreeHGlobal(m_Buffer);
            m_Buffer = IntPtr.Zero;
        }

    }


    public IEnumerable<String> EnumerateFiles(string szDriveLetter)
    {
        try
        {
            var usnRecord = default(USN_RECORD);
            var mft = default(MFT_ENUM_DATA);
            var dwRetBytes = 0;
            var cb = 0;
            var dicFRNLookup = new Dictionary<long, FSNode>();
            var bIsFile = false;

            // This shouldn't be called more than once.
            if (m_Buffer.ToInt64() != 0)
            {
                throw new Exception("invalid buffer");
            }

            // Assign buffer size
            m_BufferSize = 65536;
            //64KB

            // Allocate a buffer to use for reading records.
            m_Buffer = Marshal.AllocHGlobal(m_BufferSize);

            // correct path
            szDriveLetter = szDriveLetter.TrimEnd('\\');

            // Open the volume handle 
            m_hCJ = OpenVolume(szDriveLetter);

            // Check if the volume handle is valid.
            if (m_hCJ == INVALID_HANDLE_VALUE)
            {
                throw new Exception("Couldn't open handle to the volume.");
            }

            mft.StartFileReferenceNumber = 0;
            mft.LowUsn = 0;
            mft.HighUsn = long.MaxValue;

            do
            {
                if (DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref dwRetBytes, IntPtr.Zero))
                {
                    cb = dwRetBytes;
                    // Pointer to the first record
                    IntPtr pUsnRecord = new IntPtr(m_Buffer.ToInt32() + 8);

                    while ((dwRetBytes > 8))
                    {
                        // Copy pointer to USN_RECORD structure.
                        usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType());

                        // The filename within the USN_RECORD.
                        string FileName = Marshal.PtrToStringUni(new IntPtr(pUsnRecord.ToInt64() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2);

                        bIsFile = !usnRecord.FileAttribute.HasFlag(FileAttributes.Directory);
                        dicFRNLookup.Add(usnRecord.FileReferenceNumber, new FSNode(usnRecord.FileReferenceNumber, usnRecord.ParentFileReferenceNumber, FileName, bIsFile));

                        // Pointer to the next record in the buffer.
                        pUsnRecord = new IntPtr(pUsnRecord.ToInt64() + usnRecord.RecordLength);

                        dwRetBytes -= usnRecord.RecordLength;
                    }

                    // The first 8 bytes is always the start of the next USN.
                    mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0);


                }
                else
                {
                    break; // TODO: might not be correct. Was : Exit Do

                }

            } while (!(cb <= 8));

            // Resolve all paths for Files
            foreach (FSNode oFSNode in dicFRNLookup.Values.Where(o => o.IsFile))
            {
                string sFullPath = oFSNode.FileName;
                FSNode oParentFSNode = oFSNode;

                while (dicFRNLookup.TryGetValue(oParentFSNode.ParentFRN, out oParentFSNode))
                {
                    sFullPath = string.Concat(oParentFSNode.FileName, "\\", sFullPath);
                }
                sFullPath = string.Concat(szDriveLetter, "\\", sFullPath);

                yield return sFullPath;
            }
        }
        finally
        {
            //// cleanup
            Cleanup();
        }
    }


    public string EnumerateFiles(string szDriveLetter, string _fileName)
    {
        try
        {
            string _fileUrl = string.Empty;
            var usnRecord = default(USN_RECORD);
            var mft = default(MFT_ENUM_DATA);
            var dwRetBytes = 0;
            var cb = 0;
            var dicFRNLookup = new Dictionary<long, FSNode>();
            var bIsFile = false;

            // This shouldn't be called more than once.
            if (m_Buffer.ToInt64() != 0)
            {
                throw new Exception("invalid buffer");
            }

            // Assign buffer size
            m_BufferSize = 65536;
            //64KB

            // Allocate a buffer to use for reading records.
            m_Buffer = Marshal.AllocHGlobal(m_BufferSize);

            // correct path
            szDriveLetter = szDriveLetter.TrimEnd('\\');

            // Open the volume handle 
            m_hCJ = OpenVolume(szDriveLetter);

            // Check if the volume handle is valid.
            if (m_hCJ == INVALID_HANDLE_VALUE)
            {
                throw new Exception("Couldn't open handle to the volume.");
            }

            mft.StartFileReferenceNumber = 0;
            mft.LowUsn = 0;
            mft.HighUsn = long.MaxValue;

            do
            {
                if (DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref dwRetBytes, IntPtr.Zero))
                {
                    cb = dwRetBytes;
                    // Pointer to the first record
                    IntPtr pUsnRecord = new IntPtr(m_Buffer.ToInt64() + 8);

                    while ((dwRetBytes > 8))
                    {
                        // Copy pointer to USN_RECORD structure.
                        usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType());

                        // The filename within the USN_RECORD.
                        string FileName = Marshal.PtrToStringUni(new IntPtr(pUsnRecord.ToInt64() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2);

                        bIsFile = !usnRecord.FileAttribute.HasFlag(FileAttributes.Directory);
                        dicFRNLookup.Add(usnRecord.FileReferenceNumber, new FSNode(usnRecord.FileReferenceNumber, usnRecord.ParentFileReferenceNumber, FileName, bIsFile));

                        // Pointer to the next record in the buffer.
                        pUsnRecord = new IntPtr(pUsnRecord.ToInt64() + usnRecord.RecordLength);

                        dwRetBytes -= usnRecord.RecordLength;
                        if (!string.IsNullOrEmpty(_fileName) && _fileName.Equals(FileName))
                        {
                            cb = 0;
                            break;
                        }
                    }

                    // The first 8 bytes is always the start of the next USN.
                    mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0);


                }
                else
                {
                    break; // TODO: might not be correct. Was : Exit Do

                }

            } while (!(cb <= 8));

            // Resolve all paths for Files
            foreach (FSNode oFSNode in dicFRNLookup.Values.Where(o => o.IsFile))
            {
                string sFullPath = oFSNode.FileName;
                FSNode oParentFSNode = oFSNode;

                if (!string.IsNullOrEmpty(_fileName) && _fileName.Equals(oFSNode.FileName))
                {

                    while (dicFRNLookup.TryGetValue(oParentFSNode.ParentFRN, out oParentFSNode))
                    {
                        sFullPath = string.Concat(oParentFSNode.FileName, "\\", sFullPath);
                    }
                    _fileUrl = string.Concat(szDriveLetter, "\\", sFullPath);
                    break;
                }

            }
            return _fileUrl;
        }
        finally
        {
            //// cleanup
            Cleanup();
        }
    }

}
View Code

 DriveInfoExtension.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.IO;
 6 
 7 public static class DriveInfoExtension
 8 {
 9     public static IEnumerable<String> EnumerateFiles(this DriveInfo drive)
10     {
11         return new FileSearch().EnumerateFiles(drive.Name);
12     }
13 
14     public static string GetPathByFile(this DriveInfo drive, string _filename)
15     {
16         return new FileSearch().EnumerateFiles(drive.Name, _filename);
17     }
18 }
View Code

执行代码

 

哈哈就问你服不服!!理论上我只获取游戏路径的话大概在3000毫秒左右,不服你可以用windows自带的搜索去搜搜你就知道这个有多牛X,

既然做出来了,那必须去买个萌,吸收吸收欢呼声(是不是很贱)

本期先这样下期我们继续。

posted @ 2015-07-30 09:37  腰里一块砖  阅读(1110)  评论(1)    收藏  举报