ArcSDE C API 在C#下的使用方法

一、首先,要肯定是在C#中是不能够直接的使用添加引用的方法来把DLL加到工程中来直接的使用的。而是通过用[DllImport()]方法来实现DLL中函数的调用。

在使用这个方法是要现在引用库:using System.Runtime.InteropServices;

例:  [DllImport("sde.dll", SetLastError = true, ThrowOnUnmappableChar = true)]

注:后面的两个参数只是用来设置DLL调用时的方法,可以根据具体需要设置。

 

二、C#中由于一些类形和CC++中有一些差别,而且在指针的用法也有所不同。

 

1.下面以SE_connection_create函数作下说明:

LONG SE_connection_create (const CHAR *server,const CHAR *instance,const CHAR *database,const CHAR *username,const CHAR *password,SE_ERROR *error,SE_CONNECTION *connection);

 

2.以上是C_API中的声明,可是看到 const CHAR * ,SE_ERROR *这样的类型。由于在C#中指针的运用是在非安全的状态下应用的,而且应用是比较的复杂。所以就直接使用C#中对应的类型来使用,而不都使用非安全代码。

C++中的类型

C#中的类型

long

Int32

const CHAR *

string

Struct *

IntPtr

Struct **

Out IntPtr

由于SE_CONNECTION SE_ERRORC_API 中自己定义的类型,而这些又不可以从DLL中导出。所以有些必须sdetype.h这个头文件中找相关的定义,如果没有相关的定义的指针类型只能用IntPtr(用于表示指针和句柄或特定的类型)

typedef struct {

  LONG sde_error;                       /* ArcSDE error code */

  LONG ext_error;                       /* DBMS or OS errno code */

  CHAR err_msg1[SE_MAX_MESSAGE_LENGTH]; /* DBMS or SE_ERROR_get_string msg */

  CHAR err_msg2[SE_MAX_MESSAGE_LENGTH]; /* Second DBMS error, if applicable */

} SE_ERROR;

由于在C#的结构提中不能直接实例化定长的数组,所以必须用托管来实现这样的结构体的定义。

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

        public struct Se_Error

        {

            public Int32 sde_error;

            public Int32 ext_error;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]

            public char[] err_msg1;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)]

            public char[] err_msg2;

}

注:不过在C#中的结构体可以用CLASS来代替的,而在类中就可以用定长的数组,在这就不给出转化了。

这里使用struct是为了尽量和原定义一致,避免不必要的错误的出现。下面就是通过转化后的C#中的声明方式,由于为了能作为全局的使用,所以用public static extern

public static extern Int32 SE_connection_create(string server, string instance,

string database, string username, string pwd, ref Se_Error error, out IntPtr conn);

 

三、对于Struct **的使用说明

1.        如果你看到一个类型在sdetype.h找到定义如 typedef struct _SE_ShapeRecord *SE_SHAPE; 而不再提供_SE_ShapeRecord的定义的时候,那么当SE_SHAPE**的使用就只能是Out IntPtr结果就获取了一个IntPtr指针,那么这个结果一定有相关的其他函数获取进一步的信息。这种就是很容易的解决了。

2.            如果你看到一个类型在sdetype.h中能找到定义具体的定义。而在函数的声明中又是Struct **

那么在函数的声明中还可以用Out IntPtr来声明参数。得到了IntPtr后就要直接的获取其中的信息,这时就要用非托管的方法来获取信息。Struct **的实际意义就是一个结构体的数组。最后把数据放入到数组中来一个个的获取信息。

public static extern Int32 SE_instance_get_users(string server, string instance, out IntPtr user_list_addr, out  Int32 lock_count);

SE_INSTANCE_USER 是一个结构体,并且已经在sdetype.h中有了具体的定义了。

    IntPtr lockInfoList;

    Int32 numbers = 0;

    SE_instance_get_users("testxpjp", "5151", out lockInfoList, out  numbers);

    SE_INSTANCE_USER[] manArray = new SE_INSTANCE_USER[numbers];

    IntPtr current = lockInfoList;

    for (int i = 0; i < numbers; i++)

    {

      manArray[i] = new SE_INSTANCE_USER();

      Marshal.PtrToStructure(current, manArray[i]);//内容拷贝

      current = (IntPtr)((int)current + Marshal.SizeOf(manArray[i]));//根据结构体空间大小偏移

     }

Marshal.FreeCoTaskMem(lockInfoList);//释放非托管内存

注:这样是一个一个的数组内容的拷贝,也可以用  Marshal.Copy()来实现一个数组的全体的拷贝。

不过这个函数只支持IntPtr之间的拷贝,不支持不同类型之间的拷贝,其实Marshal.Copy()就是把数据的首地址给一个定义的IntPtr[]数组。

 

四、对于Char*的参数的声明。

     在 LONG SE_layerinfo_get_spatial_column (const SE_LAYERINFO layer, CHAR *table, CHAR *column);中的table,和column在帮助上都是有相关的说明了最大的长度的。

public static extern Int32 SE_layerinfo_get_spatial_column(IntPtr layerinfo,

[Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 1808)]byte[] layername,

[Out, MarshalAs(UnmanagedType.  LPArray, SizeConst = 256)]byte[] column);

这时就可以用以上的托管的方式定长byte[]来传递信息。在获取后用ASCIIEncoding做一下转化就可以了。

五、头文件的说明

       Pedef.h 是坐标系的常量,

       Sdetype是数据类型的定义和方法的声明。

Sg.hSHAPE 和坐标系相关方法的声明。

Sderrno.h是错误号。

Pe.h 结构体的定义。

Sderaster.hraster相关方法声明。

C_API主要包含和服务器中各类信息的提取:如连接的用户,SDE图层数据的信息。 和对图形的操作等等。

posted on 2009-03-26 17:26  Dormouse  阅读(1420)  评论(2)    收藏  举报

导航