Platform invoke 乱码

来源:互联网 发布:mac无线网经常掉线 编辑:程序博客网 时间:2024/06/04 19:54

最近在做一个关于智能卡的项目的时候,遇到一个乱码的问题,具体情况是这样的,调用API的一个方法的时候,在传递的一个结构体变量中有字符串类型的变量,该变量从API中返回的时候变成了乱码,而和它同一个结构体的整型值却是个正常的值。

typedef struct {
   LPSTR ErrorNumber;           /* Error Number */
   LPSTR ErrorString;           /* Description of the error */
   LPSTR ResolutionString;      /* Description of the resolution for the error. */
   DWORD HelpID;                 /* help identifier for the error */
} CARD_ERROR_INFO_1_A, *PCARD_ERROR_INFO_1_A, FAR *LPCARD_ERROR_INFO_1_A;

#ifndef HOST_16BIT
typedef struct {
   LPWSTR ErrorNumber;           /* Error Number */
   LPWSTR ErrorString;           /* Description of the error */
   LPWSTR ResolutionString;      /* Description of the resolution for the error. */
   DWORD HelpID;                 /* help identifier for the error */
} CARD_ERROR_INFO_1_W, *PCARD_ERROR_INFO_1_W, FAR *LPCARD_ERROR_INFO_1_W;
#endif

 

#if defined _UNICODE || defined UNICODE

#define LPCARD_ERROR_INFO_1 LPCARD_ERROR_INFO_1_W

#else

#define LPCARD_ERROR_INFO_1 LPCARD_ERROR_INFO_1_A

 

BOOL ICEAPI GetCardPrinterErrors (LPTSTR lpPrinterName,DWORD level,LPCARD_ERROR_INFO_1 lpbErrorInfo, DWORD cbBuf, LPDWORD lpdwNeeded,LPDWORD lpdwError);

 

下面是对应的C#的方法,在转化前,先要搞清楚几个数据类型,从WinNT.h 中可以看到

LPSTR 实际上就是 char* ,LPWSTR = WCHAR*, WCHAR是Unicode 类型的字符(用2Bytes分配一个字符),而ANSI则用一个Byte来分配字符。char就是Ansi类型。

为了实验方便,我把上面的方法的参数变成一个,LPCARD_ERROR_INFO_1 lpbErrorInfo

 

还有C#部分的关于MarshalAs 和structlayout 的知识

1.基础部分
MarshalAs是什么?它可以用来做什么?
MarshalAs 这个属性用来指示如何在托管代码和非托管代码之间封送数据,可以用于参数,字段或者返回值.该属性为可选属性,因为每个数据类型都有默认的封送处理行为.仅在可以将给定类型封送到多个类型时需要此属性.(MSDN).从这里看,并不是每个p/invoke 或者 com invoke都要用到MarshalAS的.

 

StructLayoutAttribute 类使用户可以控制类或结构的数据字段的物理布局.

通常,公共语言运行库控制类或结构的数据字段在托管内存中的物理布局。如果类或结构需要按某种方式排列,则可以使用 StructLayoutAttribute。如果要将类传递给需要指定布局的非托管代码,则显式控制类布局是重要的。LayoutKind 值 Sequential 用于强制将成员按其出现的顺序进行顺序布局。Explicit 控制每个数据成员的精确位置。如果使用 Explicit,则每个成员必须使用 FieldOffsetAttribute 来指示该字段在类型中的位置.(MSDN)

 

 

[StructLayout(LayoutKind.Sequential)]
public struct testAttr

{
        [MarshalAs(UnmanagedType.LPTStr)]
        public string ErrorNumber;

        [MarshalAs(UnmanagedType.LPTStr)]
        public string ErrorString;

        [MarshalAs(UnmanagedType.LPTStr)]
        public string ResolutionString;

        public UInt32 HelpID;
}

 

[DllImport("PlatformCPlusPlus.dll", EntryPoint = "GetCardPrinterErrors")]
extern static int GetCardPrinterErrors(ref testAttr ta);

 

一开始这样做的时候是出现乱码的,后来仔细看下,原来 LPTSTR在winnt ,winxp中的系统中都是Unicode编码,所以会出现乱码,默认的是用Ansi的,最后的解决方法是,将 [MarshalAs(UnmanagedType.LPTStr)]去掉就可以了

 

下面是实验用的代码

 

#ifdef PLATFORMCPLUSPLUS_EXPORTS
#define ICEAPI __declspec(dllexport)
#else
#define ICEAPI __declspec(dllimport)
#endif


extern "C"
{
 typedef struct
 {
  LPSTR ErrorNumber;
  LPSTR ErrorString;
  LPSTR ResolutionString;
  DWORD HelpID;
 }*LPCARD_ERROR_INFO_1;

ICEAPI BOOL GetCardPrinterErrors1A(LPCARD_ERROR_INFO_1);

}

 

ICEAPI BOOL GetCardPrinterErrors1A
(
 LPCARD_ERROR_INFO_1 lpCard
)
{
 char* temp = (char*)CoTaskMemAlloc(sizeof(char) * strlen(lpCard->ErrorString) + 6);
 strcpy_s(temp,sizeof(char) * (strlen(lpCard->ErrorString) + 6),"test:");
 lpCard->ErrorString = temp;
 lpCard->ErrorNumber = temp;
 lpCard->ResolutionString = temp;
 lpCard->HelpID = 123456;
 return true;

}

 

 

[DllImport("PlatformCPlusPlus.dll", EntryPoint = "GetCardPrinterErrors1A", CharSet = CharSet.Ansi)]
        extern static int GetCardPrinterErrors(ref testAttr ta);

 

static void Main(string[] args)
        {

            testAttr taa = new testAttr();
            taa.ErrorNumber = string.Empty;
            taa.ErrorString = string.Empty;
            taa.HelpID = 0;
            taa.ResolutionString = string.Empty;

            GetCardPrinterErrors(ref taa);

            Console.WriteLine(taa.ErrorNumber);
            Console.WriteLine(taa.ErrorString);
            Console.WriteLine(taa.ResolutionString);
            Console.WriteLine(taa.HelpID.ToString());

            Console.Read();
        }

所以,以后做类似的平台调用涉及到string的都必须要指定该string用的是什么样的编码格式,否则,会出现乱码的情况
而且要明白一点,所提高api的平台,支持的是什么编码格式。

原创粉丝点击