使用 Visual Basic 通过 32 位 地址访问内存

2001年7月6日

马尼拉,菲律宾

作者:Chris Vega [gwapo@models.com]

  当我们谈论“真的”指针和内存地址,我们大都会想到 Visual Basic 的局限性,比如,由于 VB 没有作为变量声明的指针数据类型,它不能直接访问内存。当某些场合需要一个变量的“地址”而不是它的值的时候,这一点混淆就显得特别明显。例如,那个变量位于内存(当前进程、其它进程或者动态链接库的虚拟空间)中的何处。

  是的,VB 确实“没有”指针变量,但是你是否曾试过将一个正规的 VB 数据类型转变为一个指针?你是否认为这是不可能的?好吧,还是再想一下,因为在 Visual Basic 中(从发行版本5开始),Microsoft 提供了一系列便利的函数以将你的正规变量转换为指针,它们是:

1] VarPtr - 返回一个变量或者数组元素的地址
   StrPtr - 返回字符串的地址

  Visual Basic 中除字符串以外的变量,都位于它的内存位置上,你可以通过调用 VarPtr 函数获取这个变量的地址。字符串实际上是作为 BSTR 储存的,这是一个指向“字符数组的指针”的指针,这样你就需要 StrPtr 以得到“字符数组的指针”的地址,而不是用 VarPtr 获得 BSTR 的地址。

范例:
 Dim ptrMyPointer As Long
 Dim intMyInteger As Integer
 Dim strMyString As String * 25

' 这就是一个调用
 ptrMyPointer = VarPtr(intMyInteger)
 ' 将内存中 intMyInteger 这个变量的32位地址赋予 ptrMyPointer

strMyString = "变量的地址:" & Hex(ptrMyPointer)
 MsgBox strMyString

' 这是另一个调用
 ptrMyPointer = StrPtr(strMyString)
 ' 给出字符数组首元素的地址,例如,字符串的第一个字母。

2] VarPtrArray - 返回变量数组的地址
   VarPtrStringArray - 返回字符传数组的地址

  Visual Basic 中数组被包存在 SAFEARRAY 结构中,你需要使用 VarPtrArray 函数以获取数组的地址,但是在使用该函数之前,你必须手工把它从 msvbvm50.dll 中声明到 VB 程序中。

范例:

' 对于 VB 5
 ' ========
 Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Var() as Any) As Long

' 对于 VB 6
 ' ========
 Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Var() as Any) As Long

' 调用

Dim lngSafeArrayAddress As Long
 Dim lngArrayOfLongs(6) As Long
 Dim i As Long

Randomize
 For i = 0 to 6
  lngArrayOfLongs = Int(Rnd * &HFFFF)
 Next

lngSafeArrayAddress = VarPtrArray(lngArrayOfLongs())

' 返回数组 lngArrayOfLongs 的安全地址,s of an Array , you
 ' 你可以将这些地址用于快速排序或其它用途。

  事实上,VarPtrStringArray 更难以用于你的程序中,因为你需要创建一个类型库并手工将该类型库引用到 VB 程序中。要做一个类型库,你需要一个 MIDL 编译器,它是一个用于将 *.odl 文件编译成类型库的命令行工具。
  对于 VB5,创建一个文本文件并且保存为 VB5StrPtr.odl,加入以下内容:

----------开始剪切--------------------------------------------------
#define RTCALL _stdcall
[uuid(6E814F00-7439-11D2-98D2-00C04FAD90E7),lcid (0), version(5.0), helpstring("VarPtrStringArray Support for VB5")]
library PtrLib
{
 importlib ("stdole2.tlb");
 [dllname("msvbvm50.dll")]
 module ArrayPtr
   {
    [entry("VarPtr")]
    long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
   }
}
----------结束剪切-------------------------------------------------

  用以下命令编译: MIDL /t VB5StrPtr.odl

  对于 VB6,创建一个文本文件并且保存为 VB6StrPtr.odl,加入以下内容:

-----------开始剪切--------------------------------------------------
#define RTCALL _stdcall
[uuid(C6799410-4431-11d2-A7F1-00A0C91110C3),lcid (0), version(6.0), helpstring("VarPtrStringArray Support for VB6")]
library PtrLib
{
 importlib ("stdole2.tlb");
 [dllname("msvbvm60.dll")]
 module ArrayPtr
   {
    [entry("VarPtr")]
    long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
   }
}
----------结束剪切-------------------------------------------------

  用以下命令编译: MIDL /t VB6StrPtr.odl

  现在,你有了类型库,将该类型库引用到 VB 程序中,然后你可以用以下方式获取字符串数组:

Dim MyArrayOfStrings(3) As String
Dim AddressOfArray As Long
MyArrayOfStrings(0)="Chris"
MyArrayOfStrings(1)="Vega"
MyArrayOfStrings(2)="gwapo@models.com"

' 调用
AddressOfArray = VarPtrStringArray ( MyArrayOfStrings() )

' 给出数组首元素的地址,而且是该首元素的第一个字符,
' 例如,这里是字符“C”在内存中的地址

' *** 怎样?你没有 MIDL 编译器?或者你不愿麻烦自己创建类型库并手工引用?
' 这里有一种足够容易的简单方法。
' 因为 StrPtr 函数具有获得字符串地址的能力,而字符串数组的元素全部都是字符串,
' 所以你应该清楚了,你可以对数组的首元素进行这个调用

AddressOfArray = StrPtr ( MyArrayOfStrings(0) )

' 返回更上述方法完全相同的结果

3] ObjPtr - 返回一个对象的地址

  面向对象编程由众多对象组成,而这些对象和它的众多属性一起保存在内存中,作为一种结构化的布局。你需要调用 ObjPtr 函数来获取它的位置。

范例:
 ' 你要知道 Form1 处于内存何处,本方法告诉你它在线程中的地址

Dim objMyObject As New Form1
 MsgBox "Form1 位于:" & Hex( ObjPtr( objMyObject ) )

  好,到此为止你一定在想:无论如何,怎么才能把这些地址变成实际有用的东西呢?其实如果你这样想答案就很清楚了:地址是一个内存中的位置,而你的变量中保存的就是一个内存中的位置,并且有它本身在内存中的位置。搞糊涂了?我们让它简单一点,你可以简单的认为这个地址是保存数据的位置,数据是可读写的,而你需要通过这个地址来读写它。唔,Visual Basic 能够做这种事情吗?

  不能,如果你只是简单的考虑 Visual Basic 的能力的话,但是你的程序可以使用 API 函数。我现在谈到的 API 是从 KERNEL32.DLL 输出的运行库,名为 RtlMoveMemory 和 RtlCopyMemory。

  它太吸引人了。首先我们已经找到了通过把变量转变为指针来得到内存地址的方法,现在我们又有了读写这些地址所指内容的方法。但是只要将这两个声明中的任一个加入你的程序中,而不是全部,因为它们的功能是一样的。我建议使用第二个,因为它被所有的 Windows 系统支持,而 RtlCopyMemory 则不然。

Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlCopyMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
 ' RtlCopyMemory 将一块内存的内容复制到另一块中。

' 或者

Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)

' RtlMoveMemory 可以向前或向后移动内存,匹配的或不匹配的,
 ' 以 4字节的块为单位,后面为所有保留的字节。

参数:

Destination
  指向要移动的目标。

Source
  指向要复制的内存。

Length
  指定要复制的字节数。

  为了使它更容易使用,你可以把下面内容复制粘贴到 modMemory.bas 中:

------------开始剪切------------------------------------------------------------------

Attribute VB_Name = "modMemory"
 ' =============================================================================
 ' 复制内存 API
 ' =============================================================================
 Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
                    
 ' =============================================================================
 ' 数据长度
 ' =============================================================================
 Public Enum e_BinaryData
     DefineByte = 1                          '  8 位数据
     DefineWord = 2                          ' 16 位数据
     DefineDoubleWord = 4                    ' 32 位数据
     DefineQuadWord = 8                      ' 64 位数据
 End Enum

' =============================================================================
 ' 允许直接读 MemPointer 指向的内存
 ' 用和 Asm 一样的字节数定义 (DB, DW, DD, DX)
 ' =============================================================================
 Function ReadMem(ByVal MemPointer As Long, _
                  SizeInBytes As e_BinaryData)
     Select Case SizeInBytes
         Case DefineByte
             Dim DB As Byte
             CopyMemory DB, ByVal MemPointer, 1
             ReadMem = DB
         Case DefineWord
             Dim DW As Integer
             CopyMemory DW, ByVal MemPointer, 2
             ReadMem = DW
         Case DefineDoubleWord
             Dim DD As Long
             CopyMemory DD, ByVal MemPointer, 4
             ReadMem = DD
         Case DefineQuadWord
             Dim DX As Double
             CopyMemory DX, ByVal MemPointer, 8
             ReadMem = DX
     End Select
 End Function

' =============================================================================
 ' 允许直接写 MemPointer 指向的内存
 ' 用和 Asm 一样的字节数定义 (DB, DW, DD, DX)
 ' =============================================================================
 Sub WriteMem(ByVal MemPointer As Long, _
              SizeInBytes As e_BinaryData, _
              ByVal DataToWrite)
     CopyMemory ByVal MemPointer, VarPtr(DataToWrite), SizeInBytes
 End Sub

------------结束剪切---------------------------------------------------------------

用例:

通过内存为变量赋值:

Dim ptrVariable As Long
 Dim xCounter As Long

ptrVariable = VarPtr(ptrVariable)
 WriteMem ptrVariable, DefineWord, &HFFFF
 ' 与 ptrVariable = &HFFFF 等价

读内存的内容,使用:

ptrVariable = ReadMem(ptrVariable, DefineWord)

  现在我们能够获得指针并访问它们了。但是如果你一步步跟着以上步骤看下来,你可能奇怪一条原本的 Visual Basic 赋值操作比这里介绍的直接内存赋值操作快得多。然而本文旨在指出可以使用 Visual Basic 访问内存,而这一点的主要意义不仅在于读取和分析变量,接下来,你可以通过获得内存地址简单地处理运行的 DLL。同时利用 modMemory.bas 和 PE (Portable Executable) 文件格式的知识,你可以分析 DLL 主体,看看它们是如何处理的。最好的是,可以获取它所有输出函数的列表;差点忘记,可以把它们 spy 出来或者干脆获取函数体的副本进行反汇编,比低级语言访问更多的内容,这也是 C 语言被称为工业标准的原因;现在你可以书写跟 C 表现相同的 Visual Basic 程序,祝你好运!

- Chris Vega [gwapo@models.com]

Accessing Memory by 32-bit Addresing in Windows using Visual Basic

July 6, 2001

Manila, Philippines

By: Chris Vega [gwapo@models.com]

When we talk about *real* Pointer and Memory Addressing, most of us thinks of Visual Basic limitations, ie, VB cannot access memory because VB has no pointer datatype for a variable declarations. This confusion grow even larger when a scenarios needed one *address* of a variable instead of its value, ie, from where in memory was that variable located into a virtual space of currently running process or a process or dynamic library.

Yes, there is actually *no* pointer variable for VB, but have you ever tried to turn a regular VB Datatype into a Pointer? do you think its not possible? well, think again, cause in Visual Basic (starting from release version 5), a serries of handy funtions is presented by Microsoft to turn this regular variables of yours into a pointer, these are:

1] VarPtr - Returns the Address of a Variable or Array Element
   
           StrPtr - Returns the Address of String

Variables in Visual Basic, except Strings are located into its
  Memory Location, you can get the Address of this variable by
  calling VarPtr Function. Strings however are stored as BSTR's,
  a pointer to a "pointer on array of characters", where you need
  StrPtr to have the address of "pointer to the array of characters"
  instead an address to BSTR if you used VarPtr in String.

ex.
   Dim ptrMyPointer As Long
   Dim intMyInteger As Integer
   Dim strMyString As String * 25

' A call

ptrMyPointer = VarPtr(intMyInteger)

' gives ptrMyPointer a 32-bit Address of the Variable
   ' intMyInteger in Memory

strMyString = "Address of Variable : " & Hex(ptrMyPointer)

MsgBox strMyString

' Next, a call

ptrMyPointer = StrPtr(strMyString)

' gives the Address of the First Element of the Array of
   ' Character, ie, First letter of the String.

2] VarPtrArray - Returns the Address of an Array of Variables
    VarPtrStringArray - Returns the Address of an Array of Strings

Arrays in Visual Basic are store in SAFEARRAYs, and you need to
  use the function VarPtrArray to get the address of this array, but
  before you can use the function, you need to manually declare the
  function from msvbvm50.dll to your VB Application.

ex.

' for VB 5
   ' ========
   Declare Function VarPtrArray _
                                         Lib "msvbvm50.dll" Alias "VarPtr" _
                    (Var() as Any) As Long

' for VB 6
   ' ========
   Declare Function VarPtrArray _
                                         Lib "msvbvm60.dll" Alias "VarPtr" _
                    (Var() as Any) As Long

' The Call

Dim lngSafeArrayAddress As Long
   Dim lngArrayOfLongs(6) As Long
   Dim i As Long

Randomize
   For i = 0 to 6
    lngArrayOfLongs = Int(Rnd * &HFFFF)
   Next

lngSafeArrayAddress = VarPtrArray(lngArrayOfLongs())

' Returns the Safe Address of an Array lngArrayOfLongs, you
   ' can simply use 'em for *fast* sorting or many more!

VarPtrStringArray however are more difficult to incorporate into
  you application since you need to create a TypeLibrary and manually
  refference the Library into VB Application.

To make a Type Library, you need a MIDL compiler, a CommandLine tool
  that compiles *.odl file into a Type Library,

For VB5 Create a Text File and Save it to VB5StrPtr.odl with content:

-------------Cut here--------------------------------------------------
  #define RTCALL _stdcall
  [
  uuid(6E814F00-7439-11D2-98D2-00C04FAD90E7),
  lcid (0), version(5.0), helpstring("VarPtrStringArray Support for VB5")
  ]
  library PtrLib
  {
  importlib ("stdole2.tlb");
  [dllname("msvbvm50.dll")]
  module ArrayPtr
     {
     [entry("VarPtr")]
     long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
     }
  }
  ----------End Cut here-------------------------------------------------

And compile it with:
   MIDL /t VB5StrPtr.odl

For VB6 Create a Text File and Save it to VB6StrPtr.odl with content:

-------------Cut here--------------------------------------------------
  #define RTCALL _stdcall
  [
  uuid(C6799410-4431-11d2-A7F1-00A0C91110C3),
  lcid (0), version(6.0), helpstring("VarPtrStringArray Support for VB6")
  ]
  library PtrLib
  {
  importlib ("stdole2.tlb");
  [dllname("msvbvm60.dll")]
  module ArrayPtr
     {
     [entry("VarPtr")]
     long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
     }
  }
  ----------End Cut here-------------------------------------------------

And compile it with:
   MIDL /t VB6StrPtr.odl

Now, you have the Type Library, and Referrenced the Library to your VB
  Application, you can get the Array of Strings in this way:

Dim MyArrayOfStrings(3) As String
  Dim AddressOfArray As Long
  MyArrayOfStrings(0)="Chris"
  MyArrayOfStrings(1)="Vega"
  MyArrayOfStrings(2)="gwapo@models.com"

' A call
  AddressOfArray = VarPtrStringArray ( MyArrayOfStrings() )

' gives you the Address of the first element in the Array and First
  ' character of this element, ie, Address where "C" is located in
  ' Memory

' *** How about it, you dont have MIDL compiler? or dont want to go
  ' into a process of creating Type Library and Referencing it manually,
  ' a simple approach of using StrPtr will be handly enough for you, since
  ' this function has the capability of getting the Address of a String, and
  ' each element in an Array of Strings is non other than String, so you
  ' get the picture clear, you have to point your call to the first element
  ' of the Array of String and call

AddressOfArray = StrPtr ( MyArrayOfStrings(0) )

' returns the same result as the above call

3] ObjPtr - Returns the Address of an Object

Object Oriented Programming consist of Objects, and these objects also
  stored into Memory together with all of its properties, as a structured
  layout, and to obtain its location you need to call ObjPtr Funtion

ex.
   ' You want to know where is your Form1 resides in Memory, this
   ' Method gives you the Address, in Thread

Dim objMyObject As New Form1

MsgBox "Form1 located at : " & Hex( ObjPtr( objMyObject ) )

Ok, from this point, you are thinking on, How in the world should this Address becomes
useful in anyways? well the answer is very clear if you think this way, an Address is
a Location in Memory, and your Variables is a Location in Memory with its own Location
in Memory, confused? well, to make it simple, you can simply think that this Address is
a Location where Datas are stored, and Datas are READABLE and WRITABLE, but you need the
Address to have it Written or Read the Data on it, Hmmm, Is Visual Basic Capable of
doing these things?

Well, not, if you think plain as in Visual Basic Capability, but APIs are functions that
are ready for use by you application, the APIs im blabing about is a RunTime Libararies
called RtlMoveMemory and RtlCopyMemory, exported by KERNEL32.DLL.

Aint it charming? First we have found a way to achieve a Memory Address by converting a
Variable into a Pointer, Now we have ways to Read and Write to anf from these addresses,
but how you may ask? By adding either one of this Declarations to your Application, but not
both, since they funtion the same, i suggest use the second one since it supported by all
Windows System, while RtlCopyMemory is not.

Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlCopyMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
 ' RtlCopyMemory copies the contents of one buffer to another.

' OR

Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)

' RtlMoveMemory moves memory either forward or backward, aligned or unaligned,
 ' in 4-byte blocks, followed by any remaining bytes.

Parameters:

Destination
  Points to the destination of the move.

Source
  Points to the memory to be copied.

Length
  Specifies the number of bytes to be copied.

To make it more easy to Use, Included the File modMemory.bas for Copy and Paste
in this Article:

------------cut here------------------------------------------------------------------

Attribute VB_Name = "modMemory"
 ' =============================================================================
 ' Copy Memory API
 ' =============================================================================
 Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
                    
 ' =============================================================================
 ' Data Sizes
 ' =============================================================================
 Public Enum e_BinaryData
     DefineByte = 1                          '  8 Bits Data
     DefineWord = 2                          ' 16 Bits Data
     DefineDoubleWord = 4                    ' 32 Bits Data
     DefineQuadWord = 8                      ' 64 Bits Data
 End Enum

' =============================================================================
 ' Allows Direct Reading from Memory Pointed by MemPointer
 ' with definition of bytes used as in Asm (DB, DW, DD, DX)
 ' =============================================================================
 Function ReadMem(ByVal MemPointer As Long, _
                  SizeInBytes As e_BinaryData)
     Select Case SizeInBytes
         Case DefineByte
             Dim DB As Byte
             CopyMemory DB, ByVal MemPointer, 1
             ReadMem = DB
         Case DefineWord
             Dim DW As Integer
             CopyMemory DW, ByVal MemPointer, 2
             ReadMem = DW
         Case DefineDoubleWord
             Dim DD As Long
             CopyMemory DD, ByVal MemPointer, 4
             ReadMem = DD
         Case DefineQuadWord
             Dim DX As Double
             CopyMemory DX, ByVal MemPointer, 8
             ReadMem = DX
     End Select
 End Function

' =============================================================================
 ' Allows Direct Writing to Memory Pointed by MemPointer
 ' with definition of bytes used as in Asm (DB, DW, DD, DX)
 ' =============================================================================
 Sub WriteMem(ByVal MemPointer As Long, _
              SizeInBytes As e_BinaryData, _
              ByVal DataToWrite)
     CopyMemory ByVal MemPointer, VarPtr(DataToWrite), SizeInBytes
 End Sub

------------end cut here---------------------------------------------------------------

Usage:

To assign to a variable using memory:

Dim ptrVariable As Long
  Dim xCounter As Long

ptrVariable = VarPtr(ptrVariable)
  WriteMem ptrVariable, DefineWord, &HFFFF
   ' Same as ptrVariable = &HFFFF

To read from a Memory, use:

ptrVariable = ReadMem(ptrVariable, DefineWord)

Wow, we got a Pointer and we can access them now, but if you time instructions, you
may be amazed that a raw Visual Basic Assignment Operations is much faster that
of the Direct Memory Assignment Operation, but what i am pointing out here is that
Memory can now be Accessed Using Visual Basic, and the global Idea of this is to
Read and Analyse not only the Variable, from this Downward, you can simply run through
running DLL by acquiring their memory addresses, equiped with modMemory.bas with
knowledge of Portable Executable format, Bingo, you can play with the DLL Body, See
how they process and best of all, Get a List of all of its Exported Functions; and
before i forgot, why not spy em out or even get a copy of their function body to
Disassembly purpose, all of which and more are accessible on Low Level Languages,
thats why C was declared as Industry Standard; Now you can write Visual Basic
Application that can performs like C, goodluck

- Chris Vega [gwapo@models.com]

使用 Visual Basic 通过 32 位 地址访问内存(中英对照)相关推荐

  1. 32位地址的寻址方式

    在32位微机系统中,除了支持前面的七种寻址方式外,又提供了一种更灵活.方便,但也更复杂的内存寻址方式,从而使内存地址的寻址范围得到了进一步扩大. 在用16位寄存器来访问存储单元时,只能使用基地址寄存器 ...

  2. 七种寻址方式(32位地址的寻址方式)

    在32位微机系统中,除了支持前面的七种寻址方式外,又提供了一种更灵活.方便,但也更复杂的内存寻址方式,从而使内存地址的寻址范围得到了进一步扩大. 在用16位寄存器来访问存储单元时,只能使用基地址寄存器 ...

  3. 32位下的内存地址分布

    32位下的内存地址分布图如下:1g为内核空间,3g为用户空间 内核空间:内核空间表示运行在处理器最高级别的超级用户模式(supervisor mode)下的代码或数据,内核空间占用从0xC000000 ...

  4. 使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表

    原文:使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表 我们知道目标平台是32位的程序运行在64位的系统上,去访问部分注册表的时候系统自动重定向到win32node节点对应的 ...

  5. 32位单片机 一个32位地址代表一个字节而不是4个字节(32位)

    在数据手册上,BSRR的偏移地址为0X18,然后手册讲完BSRR后直接讲LCKR了,并且LCKR的偏移地址是 OX1C .所以根据 OX1C-0X18=0X04 就知道BSRR是32位寄存器了.因为一 ...

  6. 707-详解32位Linux系统内存地址映射

    详解32位Linux系统内存地址映射 我们先看一段简单的C程序: 我们先来看一张图: 我们平时所说的x86 32位指的是:80386往后到现在的同一个体系的CPU处理芯片,但是x86这个芯片是从808 ...

  7. 32位java 最大内存_【答疑系列】为什么32位系统只支持最大4G内存?

    这个问题一直都有同学问到,算是提问次数最多的问题之一了. 32位是什么 现在主流的操作系统都是64位的,早期存在32位操作系统,相信大家也都有所听闻,其实,在更早之前,还有16位.8位的,这里就不展开 ...

  8. win7 32位的4g内存可用内存只有2g到3g怎么解决?

    win7 32位的4g内存可用内存只有2g到3g怎么解决?这里简要介绍一些常用的解决方法,可以适当的增加内存,需要的朋友可以参考下 win7 32位可用内存有时候只有2g多或者3g多,这里简要介绍一些 ...

  9. 32位计算机分配的最大内存大小,32位系统支持多大内存,教您如何提升32位系统的内存...

    民用的32位的操作系统的内存都是4G,但犹豫要保留一部分供给硬件使用,所以留给用户的可用内存就比较少了,一般来说只有3.2G到3.5G左右,剩下的就都浪费了,那么,该怎么避免这种浪费呢?又应该如何去提 ...

最新文章

  1. 基于数组的无锁队列(译)
  2. Centos7 安装 nginx 服务器的两种方式
  3. Payment Terms 付款条件
  4. ideal pom文件安装到maven库中_java学习之web基础(14)Maven基础学习
  5. ASP.NET常用语句1--20条 非常实用
  6. Sping : @InitBinder注解
  7. 刘德华--6雪藏是一种代价
  8. Android 4.4 NotificationManagerService使用详解与原理分析(二)__原理分析
  9. TCP 协议学习小结
  10. 脚本变量中包含空格的解决办法
  11. Linux的常见的发行版以及不同发行版之间的联系与区别
  12. Windows 10 常用软件推荐
  13. C# 添加Excel水印
  14. excel函数自变量linux,excle 求自变量 | 如何用EXCEL已知自变量和函数值求函数式
  15. vue前端项目基于淘宝lib-flexible做手机端适配
  16. 从输出海外吃鸡游戏浅谈创新
  17. 单片机 电子电路 嵌入式 毕设 课设 私活 代做
  18. EDGE浏览器关闭网址栏自动补全
  19. 设计模式--桥接模式
  20. Python发送邮件的类

热门文章

  1. CAD二次开发获取CAD内所有的大字体SHX字体
  2. vb调用lisp中vlx函数_CAD二次开发,lisp程序生成应用程序VLX,如何在CAD里面创建一个快捷图标,点击快捷图标就可以调用程序...
  3. 拯救熊猫眼!戒除手机瘾!不做手机控,全靠它了!
  4. 锐捷VSU配置实例(附拓扑图)
  5. 好用的字体图标插件:阿里图标库(iconfont)
  6. python编程输入数字输出月份英文_编程题:输入英文月份单词,输出对应月的数字形式。...
  7. oracle固定资产减少怎么查,固定资产原值减少账务处理是怎样的
  8. 手把手教你搭建Jenkins实现自动化部署Jar
  9. 除了乔布斯,科技圈还有哪些大佬值得充信仰?
  10. 【博图v15安装报错问题解决方法