c#to c++

来源:互联网 发布:java软件培训班哪个好 编辑:程序博客网 时间:2024/05/16 17:58

指针在C/C++里面可是一个好东西,但是到java,.net的时代指针已经被封装起来,对用户不可见,这点java做的非常的彻底。.net可能因为还存在一个托管C++,因此指针并没有完全废除,C#还是保留了指针的操作。
       要使用指针首先要对使用指针的代码用unsafe进行进行声明,声明和public声明一样,可以对整个类进行声明,也可以是类里面某个方法或者属性。在代码里什么后,还需要修改工程项目的Build属性,让编译器支持指针的操作。
       做好事前的工作就可以使用指针了。指针的使用方法和C++下使用没有太多差别。只要编译器不报错就没有太大问题。
       下面是对指针的一些使用上的理解:
1.  指针类型可以是实体变量(int,double)也可以是enum,同时也支持结构体变量struct。但不能是类。不过空指针可以指向类,只不过空指针不能进行任何操作,也只能把空指针作为传递对象来使用。
2. C#提供一个的关键字stackalloc用于申请堆栈内存。注意,这个申请内存分配的是栈内存,当函数执行完毕后,内存会被自动回收。不过我想用这个栈内存基本可以解决40%的问题,而且使用的时候不必担心内存泄漏问题。
3. .net 好像不直接支持堆内存的申请(这个对.net来说很危险),不过我们可以通过调用win32 api 的方法进行申请。这样就可以解决剩下40%的问题。堆内存申请的方法在MSDN里面有相关的文档,具体实现代码见附1。
4.  结构体是一个特殊的对象。他与类的定义就差一个关键字,使用方法也和类一样,可以定义属性,可以定义方法。但是在进行指针操作的时候双方就有很大的差别了。结构体可以通过sizeof()取得大小,大小与结构体里有多少实体变量有关,但是如果struck里定义了类的对象,或者指针,sizeof可能会编译不过(void* 的空指针例外,不过需要在结构体声明处加上unsafe)。
5. fixed关键字:目前了解的不多,不过有一个很实用的例子可以让指针能够和.net里的数组进行交互操作:
 
                byte[] buffer = new byte[100];
                fixed (byte* p = buffer)
                {
                    P[0] = 123;
                    ……
                }
 
6.  其它
7. 
 
 
 
 
附1:
    public unsafe class Memory
    {
        // Handle for the process heap. This handle is used in all calls to the
        // HeapXXX APIs in the methods below.
        static int ph = GetProcessHeap();
        // Private instance constructor to prevent instantiation.
        private Memory() { }
        // Allocates a memory block of the given size. The allocated memory is
        // automatically initialized to zero.
        public static void* Alloc(int size)
        {
            void* result = HeapAlloc(ph, HEAP_ZERO_MEMORY, size);
            if (result == null) throw new OutOfMemoryException();
            return result;
        }
        // Copies count bytes from src to dst. The source and destination
        // blocks are permitted to overlap.
        public static void Copy(void* src, void* dst, int count)
        {
            byte* ps = (byte*)src;
            byte* pd = (byte*)dst;
            if (ps > pd)
            {
                for (; count != 0; count--) *pd++ = *ps++;
            }
            else if (ps < pd)
            {
                for (ps += count, pd += count; count != 0; count--) *--pd = *--ps;
            }
        }
        // Frees a memory block.
        public static void Free(void* block)
        {
            if (!HeapFree(ph, 0, block)) throw new InvalidOperationException();
        }
        // Re-allocates a memory block. If the reallocation request is for a
        // larger size, the additional region of memory is automatically
        // initialized to zero.
        public static void* ReAlloc(void* block, int size)
        {
            void* result = HeapReAlloc(ph, HEAP_ZERO_MEMORY, block, size);
            if (result == null) throw new OutOfMemoryException();
            return result;
        }
        // Returns the size of a memory block.
        public static int SizeOf(void* block)
        {
            int result = HeapSize(ph, 0, block);
            if (result == -1) throw new InvalidOperationException();
            return result;
        }
        // Heap API flags
        const int HEAP_ZERO_MEMORY = 0x00000008;
        // Heap API functions
        [DllImport("kernel32")]
        static extern int GetProcessHeap();
        [DllImport("kernel32")]
        static extern void* HeapAlloc(int hHeap, int flags, int size);
        [DllImport("kernel32")]
        static extern bool HeapFree(int hHeap, int flags, void* block);
        [DllImport("kernel32")]
        static extern void* HeapReAlloc(int hHeap, int flags,
           void* block, int size);
        [DllImport("kernel32")]
        static extern int HeapSize(int hHeap, int flags, void* block);
    }

-----------
我刚刚用了非安全代码成功了,但是难道就没有别的办法了吗?  
  struct   myStruct  
  {  
  public   int   a;  
  public   int   b;  
  }  
   
  [DllImport("dll.dll")]    
  // [return:   MarshalAs(UnmanagedType.LPStruct)]  
  static   extern   int   test();    
   
  static   void   Main(string[]   args)  
  {  
  unsafe  
  {  
  myStruct*   p=(myStruct*)test();  
  Console.Write(p->a);  
  }  
  }
-----------
Imports System.Runtime.InteropServices
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
    public ushort wYear;
    public ushort wMonth;
    public ushort wDayOfWeek;
    public ushort wDay;
    public ushort wHour;
    public ushort wMinute;
    public ushort wSecond;
    public ushort wMilliseconds;
}
class Win32API {
    [DllImport("Kernel32.dll")]
    public static extern void GetSystemTime(MySystemTime st);
}
-------------
【C#】不安全代码中的指针用法探讨
    有人说:"有的女人就像c#,长得很漂亮,但家务活不行。"  呵呵,其实我倒是认为不是那个女人不行,而是那个男人不行,征服不了那个女人。C#长得的确算漂亮,如果你驾驭了它,一样能让它服服帖帖做好家务。

    对于习惯C的程序员,Java之类的面向对象编程语言用着不是很爽,很多直接访问内存的操作行不通。而C#提供了指针的机制,以满足C族程序员的这点嗜好。不过刚开始了解到C#支持指针的时候,我也不以为然,总觉得这么搞显得不伦不类的。经过一番研究,慢慢感觉到了在一个有着强大基础类库的OO语言中使用指针的价值和威力。下面用代码展示一下使用指针的一些常用操作在C#中是怎么玩的,由于仅仅是展示,所以杂七杂八的代码全放在一起了。

示例代码
 1using System;
 2
 3namespace Sophy.UnsafeCode
 4{
 5    unsafe class Program
 6    {
 7        static void Main(string[] args)
 8        {
 9            //在栈上分配内存
10            byte* arr_on_stack = stackalloc byte[100];
11
12            //下标访问数组
13            for (int i = 0; i < 100; i++)
14            {
15                arr_on_stack[i] = 0;
16            }
17
18            //在堆上分配内存
19            fixed (byte* arr_on_heap = new byte[100])
20            {
21                //指针访问数组
22                for (int i = 0; i < 100; i++)
23                {
24                    *(arr_on_heap + i) = 0;
25                }
26            }
27
28            //在栈上分配一个结构体
29            Point p = new Point();
30            //用结构体指针操作栈上的结构体
31            Point* pp = &p;
32            pp->x = 200;
33            (*pp).y = 300;
34
35            //在堆上分配一个结构体
36            fixed (byte* bs = new byte[sizeof(Point)])
37            {
38                //用结构体指针操作堆上的结构体
39                Point* ph = (Point*)bs;
40                (*ph).x = 400;
41                ph->y = 500;
42            }
43
44            //打印结构体内存地址
45            Console.WriteLine("pp Memory Address: 0x{0:X}.", ((int)pp).ToString());
46
47            //识别CPU字节序
48            pp->x = 1;
49            byte* pb = (byte*)&(pp->x);
50            if (1 == *pb)
51            {
52                Console.WriteLine("Your CPU is little endian.");
53            }
54            else if (1 == *(pb + sizeof(int) - 1))
55            {
56                Console.WriteLine("Your CPU is big endian.");
57            }
58            else
59            {
60                Console.WriteLine("Unkown.");
61            }
62        }
63    }
64
65    unsafe struct Point
66    {
67        public int x;
68        public int y;
69    }
70}
    在C#中想要使用指针,要给类型、方法或者代码段加上unsafe关键字,并且编译的时候要加上/unsafe选项。在Visual Studio 2005中,勾上“项目属性->生成”里的“允许不安全代码”,编译时就会自动加上/unsafe选项。

    C#中的指针只能指向值类型,并且值类型中不能含有引用类型。如果允许指针指向引用类型,那将是非常令人迷惑的事情。也许你注意到了这行代码:

     fixed (byte* bs = new byte[sizeof(Point)])

     {

     }

     它把一个数组赋给了一个指针变量,数组是引用类型,那不是和上面说的矛盾了吗?其实我认为是编译器做了特殊处理,在这里直接将数组的地址赋给了指针变量。一个简单的fixed关键字,编译器在背后肯定做了不少事情。因为引用类型是在托管堆中分配的,受运行库管理,当内存中碎片太多时,垃圾回收器可能会启动内存压缩,有可能将数组移动到别的地方,这时指针指向的就不是原来的数组了,所以fixed作用还在于,把引用类型的数组“钉”在内存的那个位置上,不允许垃圾回收器移动,直到代码执行到fixed后面两个大括号之外为止。

----------------
指针在C#中的一点总结
       指针在C/C++里面可是一个好东西,但是到java,.net的时代指针已经被封装起来,对用户不可见,这点java做的非常的彻底。.net可能因为还存在一个托管C++,因此指针并没有完全废除,C#还是保留了指针的操作。
       要使用指针首先要对使用指针的代码用unsafe进行进行声明,声明和public声明一样,可以对整个类进行声明,也可以是类里面某个方法或者属性。在代码里什么后,还需要修改工程项目的Build属性,让编译器支持指针的操作。
 public unsafe partial class pointer : Form
       做好事前的工作就可以使用指针了。指针的使用方法和C++下使用没有太多差别。只要编译器不报错就没有太大问题。
       下面是对指针的一些使用上的理解:
1.  指针类型可以是实体变量(int,double)也可以是enum,同时也支持结构体变量struct。但不能是类。不过空指针可以指向类,只不过空指针不能进行任何操作,也只能把空指针作为传递对象来使用。
2. C#提供一个的关键字stackalloc用于申请堆栈内存。注意,这个申请内存分配的是栈内存,当函数执行完毕后,内存会被自动回收。不过我想用这个栈内存基本可以解决40%的问题,而且使用的时候不必担心内存泄漏问题。
3. .net 好像不直接支持堆内存的申请(这个对.net来说很危险),不过我们可以通过调用win32 api 的方法进行申请。这样就可以解决剩下40%的问题。堆内存申请的方法在MSDN里面有相关的文档。
4.  结构体是一个特殊的对象。他与类的定义就差一个关键字,使用方法也和类一样,可以定义属性,可以定义方法。但是在进行指针操作的时候双方就有很大的差别了。结构体可以通过sizeof()取得大小,大小与结构体里有多少实体变量有关,但是如果struck里定义了类的对象,或者指针,sizeof可能会编译不过(void* 的空指针例外,不过需要在结构体声明处加上unsafe)。
5. fixed关键字:fixed()会告诉垃圾收集器,类实例的某些成员有指向他们的指针,所以这些实例不能移动目前了解的不多,不过有一个很实用的例子可以让指针能够和.net里的数组进行交互操作:

 

Code

            private void button1_Click(object sender, EventArgs e)
        {
            MyClass myObject = new MyClass();
            //不能创建指向类的指针,这是因为垃圾收集器不包含指针的任何信息,只包含引用的信息
            //大多数类都包含值类型的成员,可以为这些值类型成员创建类型成员创建指针,但需要一种特殊的语法
            fixed (long* pObject = &(myObject.X))
            fixed(float* fObject=&(myObject.F))
            {
                this.label2.Text = pObject->ToString();
                this.label2.Text += fObject->ToString();
            }
        }
 

6: 指针的取地址操作 和C里面的一样

 

Code
  private void button2_Click(object sender, EventArgs e)
        {
            int x = 10;
            int* pX = &x;
            this.label3.Text +="Address is"+ (uint)pX;         
        }
 

7:一个使用指针的基于堆栈的高效数组举例:C#很容易使用数组,但是有一个缺点就是这些数组实际上都是对象,是System.Array的实例,因此数组只能存储在堆上,会增加系统的开销,而使用指针就可以做到,但只能用于一位数组

 

Code
 private void pointer_Load(object sender, EventArgs e)
        {
            //分配堆栈内存,不会把内存初始化为任何默认值
            decimal* pDecimals=stackalloc decimal[10];
            pDecimals[0] = 0; //pDecimals[0] is the same as *pDecimals
            pDecimals[1] = 1; //pDecimals[1] is the same as *(pDecimals+1)
            pDecimals[2] = 2;
            pDecimals[3] = 3;
            pDecimals[4] = 4;
            pDecimals[5] = 5;
            pDecimals[6] = 6;
            pDecimals[7] = 7;
            pDecimals[8] = 8;
            pDecimals[9] = 9;
            for (int i = 0; i < 10; i++)
            {
            this.label1.Text+=pDecimals[i].ToString();
            }
        }
 

不过在实际的开发中用的不是很多!如果有那个兄弟有这方面的研究,我倒是愿意和他一起研究一下,毕竟指针是很高深的东西,我自己觉得!

--------------
c++写的dll中的函数:
public   static   extern   Int16   dc_read(Int16     icdev,   byte   _Adr,byte   *_Data);

C#中声明:[DllImport( "dcrf32.dll ")]
          public   static   extern   short   dc_read   (   int     icdev,   int   adr,[Out]   byte[]   sdata   );  


--------------
C# 编程指南
指针类型(C# 编程指南)

在不安全的上下文中,类型可以是指针类型以及值类型或引用类型。指针类型声明具有下列形式之一:

 复制代码
type* identifier;
void* identifier; //allowed but not recommended下列类型都可以是指针类型:

sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。

任何枚举类型。

任何指针类型。

仅包含非托管类型的字段的任何用户定义的结构类型。

指针类型不继承 object,并且指针类型与 object 之间不存在转换。此外,装箱和取消装箱不支持指针。但是,允许在不同指针类型之间以及指针类型与整型之间进行转换。

当在同一个声明中声明多个指针时,* 仅与基础类型一起使用,而不是作为每个指针名称的前缀。例如:

 复制代码
int* p1, p2, p3;   // Ok
int *p1, *p2, *p3;   // Invalid in C#指针不能指向引用或包含引用的结构,因为即使有指针指向对象引用,该对象引用也可能会被执行垃圾回收。GC 并不注意是否有任何类型的指针指向对象。

myType* 类型的指针变量的值是 myType 类型的变量的地址。下面是指针类型声明的示例:

示例  说明 
int* p
 p 是指向整数的指针
 
int** p
 p 是指向整数的指针的指针
 
int*[] p
 p 是指向整数的指针的一维数组
 
char* p
 p 是指向字符的指针
 
void* p
 p 是指向未知类型的指针
 

指针间接寻址运算符 * 可用于访问位于指针变量所指向的位置的内容。例如,对于下面的声明,

 复制代码
int* myVariable;表达式 *myVariable 表示在 myVariable 中包含的地址处找到的 int 变量。

不能对 void* 类型的指针应用间接寻址运算符。但是,可以使用强制转换将 void 指针转换为其他指针类型,反之亦然。

指针可以为 null。如果将间接寻址运算符应用于 null 指针,则会导致由实现定义的行为。

注意,在方法之间传递指针会导致未定义的行为。示例包括通过 Out 或 Ref 参数向局部变量返回指针或作为函数结果向局部变量返回指针。如果将指针设置在固定的块中,它所指向的变量可能不再是固定的。

下表列出可在不安全的上下文中针对指针执行的运算符和语句:

运算符/语句  用途 
*
 执行指针间接寻址。
 
->
 通过指针访问结构的成员。
 
[]
 对指针建立索引。
 
&
 获取变量的地址。
 
++ 和 --
 递增或递减指针。
 
加、减
 执行指针算法。
 
==、!=、<、>、<= 和 >=
 比较指针。
 
stackalloc
 在堆栈上分配内存。
 
fixed 语句
 临时固定变量以便可以找到其地址。
 
-------------------------
OutArrayOfStructs 示例
.NET Framework 开发人员指南
OutArrayOfStructs 示例

此示例演示如何将包含整数和字符串的结构数组作为 Out 参数传递给非托管函数。源代码示例包含在 平台调用技术示例 中。

此示例演示使用 Marshal 类和使用不安全代码如何调用本机函数。

此示例使用包装函数和 PinvokeLib.dll 中定义的平台调用(也在源文件中提供)。它使用 TestOutArrayOfStructs 函数和 MYSTRSTRUCT2 结构。该结构包含以下元素:

 复制代码
typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size;
} MYSTRSTRUCT2;MyStruct 类包含 ANSI 字符的字符串对象。CharSet 字段指定 ANSI 格式。MyUnsafeStruct,是一个包含 IntPtr 类型(而不是字符串)的结构。

LibWrap 类包含重载的 TestOutArrayOfStructs 原型方法。如果一个方法将指针声明为参数,则该类应使用 unsafe 关键字加以标记。由于 Visual Basic 2005 无法使用不安全代码,因此重载方法、不安全修饰符和 MyUnsafeStruct 结构都是不必要的。

App 类实现 UsingMarshal 方法,它执行传递数组所需的所有任务。该数组用 out(在 Visual Basic 中为 ByRef)关键字加以标记,以指示数据从被调用方传递给调用方。此实现使用以下 Marshal 类方法:

PtrToStructure,它用于从非托管缓冲区向托管对象封送数据。

DestroyStructure,它用于释放为结构中的字符串保留的内存。

FreeCoTaskMem,它用于释放为该数组保留的内存。

如前所述,C# 允许使用不安全代码,而 Visual Basic 2005 则不允许。在 C# 示例中,UsingUnsafe 是一个替换方法实现,它使用指针而不是 Marshal 类来传回包含 MyUnsafeStruct 结构的数组。

声明原型
Visual Basic 复制代码
' Declares a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Class MyStruct
   Public buffer As String
   Public someSize As Integer
End Class 'MyStruct

Public Class LibWrap
' Declares a managed prototype for the unmanaged function.
   Declare Sub TestOutArrayOfStructs Lib "..//LIB//PinvokeLib.dll" ( _
      ByRef arrSize As Integer, ByRef outArray As IntPtr )
End Class 'LibWrap
C# 复制代码
// Declares a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MyStruct
{
   public String buffer;
   public int size;
}
// Declares a structure with a pointer.
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnsafeStruct
{
   public IntPtr buffer;
   public int size;
}

public unsafe class LibWrap
{
   // Declares managed prototypes for the unmanaged function.
   [ DllImport( "..//LIB//PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size,
      out IntPtr outArray );
   [ DllImport( "..//LIB//PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size,
   MyUnsafeStruct** outArray );
}
调用函数
Visual Basic 复制代码
Public Class App
   Public Shared Sub Main()
      Console.WriteLine( ControlChars.CrLf & "Using marshal class" & _
ControlChars.CrLf )
      UsingMarshal()
      'Visual Basic 2005 cannot use unsafe code.
   End Sub 'Main
  
   Public Shared Sub UsingMarshal()  
      Dim arrSize As Integer
      Dim outArray As IntPtr
      LibWrap.TestOutArrayOfStructs( arrSize, outArray )
      Dim manArray(arrSize - 1) As MyStruct
      Dim current As IntPtr = outArray
      Dim i As Integer
     
      For i = 0 To arrSize - 1
     
         manArray(i) = New MyStruct()
         Marshal.PtrToStructure( current, manArray(i))
        
         Marshal.DestroyStructure( current, GetType( MyStruct ))
         current = IntPtr.op_explicit( current.ToInt64() _
           + Marshal.SizeOf( manArray(i) ))
        
         Console.WriteLine( "Element {0}: {1} {2}", i, manArray(i)._
           buffer, manArray(i).someSize )
      Next i
      Marshal.FreeCoTaskMem( outArray )
   End Sub 'UsingMarshal
End Class 'App

C# 复制代码
public class App
{
   public static void Main()
   {
      Console.WriteLine( "/nUsing marshal class/n" );
      UsingMarshal();
      Console.WriteLine( "/nUsing unsafe code/n" );
      UsingUnsafe();
   }
  
   public static void UsingMarshal()  
   {
      int size;
      IntPtr outArray;
      LibWrap.TestOutArrayOfStructs( out size, out outArray );
      MyStruct[] manArray = new MyStruct[ size ];
      IntPtr current = outArray;
      for( int i = 0; i < size; i++ )
      {
         manArray[ i ] = new MyStruct();
         Marshal.PtrToStructure( current, manArray[ i ]);
        
         //Marshal.FreeCoTaskMem( (IntPtr)Marshal.ReadInt32( current ));
         Marshal.DestroyStructure( current, typeof(MyStruct) );
         current = (IntPtr)((long)current +
            Marshal.SizeOf( manArray[ i ] ));
        
         Console.WriteLine( "Element {0}: {1} {2}", i,
            manArray[ i ].buffer, manArray[ i ].size );
      }
      Marshal.FreeCoTaskMem( outArray );
   }
  
   public static unsafe void UsingUnsafe()
   {
      int size;
      MyUnsafeStruct* pResult;
      LibWrap.TestOutArrayOfStructs( out size, &pResult );
      MyUnsafeStruct* pCurrent = pResult;
      for( int i = 0; i < size; i++, pCurrent++ )
      {
         Console.WriteLine( "Element {0}: {1} {2}", i,
            Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size );
         Marshal.FreeCoTaskMem( pCurrent->buffer );
      }
      Marshal.FreeCoTaskMem( (IntPtr)pResult );
   }
}

-------------------------
赖长河(laich) 14:57:47
http://msdn.microsoft.com/zh-cn/chats/zycewsya(VS.80).aspx
赖长河(laich) 14:58:39
http://msdn.microsoft.com/zh-cn/vstudio/as6wyhwt(VS.80).aspx
赖长河(laich) 14:58:44
http://msdn.microsoft.com/zh-cn/vstudio/2k1k68kw(VS.80).aspx

http://www.huarw.com/program/net/c/200609/35706.html


这是我的接口实现。
int UMWEBCLIENT GetPlayerList(const int maxrows,int* rows, tagPlayerInfo** ppPlayerInfo)
{
 if (maxrows<=0) return -4;
 if (um_public_client::Instance().getsocket() == INVALID_SOCKET) return -1;

 tagGetPlayerList* player = new tagGetPlayerList;
 player->serialize(um_public_client::Instance().getindex(),maxrows);

 HDN hdn = new tagDataNode;
 hdn->sbuf = (char *)player;
 hdn->event = (long)CreateEvent(NULL,false,false,NULL);

 if (hdn->event == NULL) return -3;
 if (!um_public_client::Instance().InsertData(hdn)) return -3;
 if (!um_write_thread::Instance().putQueue(hdn->sbuf)) return -3;

 if (WaitForSingleObject((HANDLE)(hdn->event),um_public_client::Instance().gettimeout()) == WAIT_OBJECT_0)
 {
  if (!um_public_client::Instance().FindData(((header*)hdn->sbuf)->index,hdn) ) return -3;
  
  int rlt ;
  if (hdn->rlt)  //返回成功
  {
   tagRepPlayerList * repplayer= (tagRepPlayerList*)(hdn->rbuf);
   rlt = repplayer->bSucceed;
   *rows = repplayer->bufflen / sizeof(tagPlayerInfo);
   if (*rows>0)
   {
    *ppPlayerInfo = (tagPlayerInfo*)CoTaskMemAlloc((*rows) * sizeof(tagPlayerInfo));
    memcpy(*ppPlayerInfo,repplayer+sizeof(tagRepPlayerList),repplayer->bufflen);
   }
  }  
  else
   rlt = -1;

  um_public_client::Instance().DeleteData(((header*)hdn->sbuf)->index);
  return rlt;
 }
 else
 {
  um_public_client::Instance().DeleteData(((header*)hdn->sbuf)->index);
  return -2;
 }
}
赖长河(laich) 15:00:27
  *ppPlayerInfo = (tagPlayerInfo*)CoTaskMemAlloc((*rows) * sizeof(tagPlayerInfo));
    memcpy(*ppPlayerInfo,repplayer+sizeof(tagRepPlayerList),repplayer->bufflen);
 体现在两行代码上。

 

--------------------------
//获取排行
int UMWEBCLIENT GetPlayerList(const int maxrows, int* rows, tagPlayerInfo** ppPlayerInfo);
这是c++写的一个方法,um_web_client.dll是供调用的dll
ppPlayerInfo 是结构体
// public struct tagPlayerInfo
// {
// public int id;
// public char[] PlayerName;
// public int Country;
// public int OfficerRace;
// public int Level;
// public int MilitaryRank;
// public int Money;
// public int ResourceCount;
// public int CityCount;
// public int GeneralCount;
// public int Credit;
// };
[DllImport("um_web_client.dll")]
请问在c#中如何声明及调用这个方法,请高手们给出具体的写法,
这个结构体c++中用的好象是双指针,
我现在要求是在c#中循环取出所有的tagPlayerInfo,放到list中
由于对指针方面的操作一点不了解,请帮忙写段代码,谢谢!
附c++方法实现

int UMWEBCLIENT GetPlayerList(const int maxrows,int* rows, tagPlayerInfo** ppPlayerInfo)
{
 if (maxrows<=0) return -4;
 if (um_public_client::Instance().getsocket() == INVALID_SOCKET) return -1;

 tagGetPlayerList* player = new tagGetPlayerList;
 player->serialize(um_public_client::Instance().getindex(),maxrows);

 HDN hdn = new tagDataNode;
 hdn->sbuf = (char *)player;
 hdn->event = (long)CreateEvent(NULL,false,false,NULL);

 if (hdn->event == NULL) return -3;
 if (!um_public_client::Instance().InsertData(hdn)) return -3;
 if (!um_write_thread::Instance().putQueue(hdn->sbuf)) return -3;

 if (WaitForSingleObject((HANDLE)(hdn->event),um_public_client::Instance().gettimeout()) == WAIT_OBJECT_0)
 {
  if (!um_public_client::Instance().FindData(((header*)hdn->sbuf)->index,hdn) ) return -3;
  
  int rlt ;
  if (hdn->rlt)  //返回成功
  {
   tagRepPlayerList * repplayer= (tagRepPlayerList*)(hdn->rbuf);
   rlt = repplayer->bSucceed;
   *rows = repplayer->bufflen / sizeof(tagPlayerInfo);
   if (*rows>0)
   {
    *ppPlayerInfo = (tagPlayerInfo*)CoTaskMemAlloc((*rows) * sizeof(tagPlayerInfo));
    memcpy(*ppPlayerInfo,repplayer+sizeof(tagRepPlayerList),repplayer->bufflen);
   }
  }  
  else
   rlt = -1;

  um_public_client::Instance().DeleteData(((header*)hdn->sbuf)->index);
  return rlt;
 }
 else
 {
  um_public_client::Instance().DeleteData(((header*)hdn->sbuf)->index);
  return -2;
 }
}