64位程序调用32位DLL

        最近再把原来写的股票分析程序转换成64位版本,程序中调用了银江的通视数据接口dll,因为银江提供的dll是32位的,但windows下面64位程序并不能直接调用32位的dll,所以只能百度了.
        网上有说用进程外com的方式可以,之前从没接触过com,硬着头皮搞了半天,发现了问题,进程外com对于dll提供函数返回值不涉及指针的话没有任何问题,但是如果dll函数返回值是一个指针,问题就来了,由于这个指针和我自己的数据接收程序不在同一个进程地址空间,所以根本没有办法通过指针得到正确的接收数据.所以只能放弃这个方法,转向如何在进程间传递数据.
        我自己程序是用QT编写,mingw编译的,网上关于进程间通信(IPC)资料一大把,看了一下基本上QT在windows下面如果想在进程间传递大数据,只能用LocalSocket或者共享内存的方式.两种方式的基本思路差不多,我自己的接收程序是64位的,另外在写一个32位的server程序,负责调用银江的数据接口dll,server程序接收到数据以后,以上面两种方式传递给我64位的接收程序就可以了. 
        首先以LocalSocket的方式来设计接口的,因为共享内存方式会设计比较麻烦的进程间同步问题,localsocket本身就有一条同步信号机制可供使用,具体涉及使用QT的QLocalSocket,QLocalServer类,网上资料很多,不赘述.既然是首先提这种方式,肯定是因为最终没选他,理由是,localsocket会把我传的整块数据随即分割,需要我在接收端判断并重新合成原始完整块数据.这就要求接收端多余的判断操作,和内存创建销毁操作,最终还是放弃了.当然我并没有太深入的去学习localsocket这种方式有没有办法不自动分割发送的完整大块数据,如果有的话,这应该是一种理想的方式.
        下面就要讲讲我最终采用的共享内存方式了,主要涉及QT的QSharedPointer类,开3个共享内存;
        第1个用来存储接收到的数据块.
        第2个用来放接收端(64位)的winid,主要是提供给发送32位的dll调用端读取,在接收到数据后通知64位的接收端有新的数据需要从共享内存中读取;
        第3个共享内存区是同步信号区,存了一个整型变量,1代表等待64位客户端读取数据,0代表没有需要客户端读取的数据.程序的初始状态这个值为0,32位server端接收到新数据后,会先进入一个轮询过程,在这个值为1时一直等待,只有在这个值为0的时候才会打开数据共享区,并将数据放入共享区,之后再将这个值置为0.并发送给64位客户端通知消息(用windows的API,函数PostMessageW,里面目标窗口句柄就是第2个共享区中的数据);之后客户端收到消息以后,会先去读取共享内存中的数据,将起copy到本地进程中,然后置这里的信号量置为0.
        共享内存方式基本就如上所述了,当然中间还是会有点小问题,因为接收到银江数据头是下面这样的结构:
        typedef struct tagRCV_DATA
{
int m_wDataType; // 文件类型
int m_nPacketNum; // 记录数,参见注一
RCV_FILE_HEADEx m_File; // 文件接口
BOOL m_bDISK; // 文件是否已存盘的文件
union
{
RCV_REPORT_STRUCTEx * m_pReport;
RCV_HISTORY_STRUCTEx * m_pDay;
RCV_MINUTE_STRUCTEx * m_pMinute;
RCV_POWER_STRUCTEx * m_pPower;
void * m_pData; // 参见注二
};
} RCV_DATA,*PRCV_DATA;
        可以看出最后一个是个指针,这个指针指实际上在32位server端指向的是这个数据头下面的紧接着的内存地址,但是这个地址是server进程中的绝对地址,到了64位客户端,如果仍然按照这个值,就不可能得到正确的数据,所以客户端不应该用这个值来对后续的数据访问,而是在copy下来已经在本进程内存中的数据包的首地址上加上RCV_DATA这个数据包头的大小(这里是288字节),这样才能得到正确的后续数据地址.

你可能感兴趣的:(64位程序调用32位DLL)