您的位置:首页 > 其它

平台移植 - 4 (Cygwin与Win32程序的交互)

2012-04-06 12:21 393 查看
http://blog.csdn.net/null_shadow/article/details/1807797

前面几章谈到了Cygwin的安装, 培植, 编译, 运行 等基本步骤, 本章将要讨论整个平台代码移植中的重点 : 程序的交互. (Cygwin <-> Win32)

根据调用的方式, 我把交互简单分为下面2类:

1. Cygwin程序调用Win32-Function :

据前所述, Cygwin平台下是架构在Win32平台上的一个子平台, 所以其本身就有调用Win32-API的能力.(可以用VC6提供的Dependency-Walker打开/bin/cygwin1.dll查看,会发现其主要依赖于KERNEL32.dll), 所以在Cygwin里面, 如果想调用Win32-API如 : MessageBoxA(...), 只需要在Source里简单的include <windows.h> 再调用就可以了, 用Cygwin-GCC编译测试, 可以看到程序正常运行.

所以, Cygwin调用Win32程序没有太大的困难, 至少知道是有途径可以调用成功的.

2. Win32程序调用Cygwin-Function :

Cygwin官方并不提供这种直接的Win32调用Cygwin-DLL里面Function的能力. 原因大致是: 依赖于Cygwin平台的程序在入口的时候(特别的, 是在main-function执行之前),需要由Cygwin进行必要的Init. 如果是以Win32程序作为入口点, 则没办法由Cygwin平台直接提供这样的支持.(因为Cygwin只提供基于Cygwin平台的编译器)

不过,非官方的提供了这样的途径用于Win32-EXE调用Cygwin-DLL. 方法有静态调用和动态调用两种之分.

下面主要介绍的是动态调用 (很遗憾, 静态调用没有测试成功, 有调用成功的朋友敬请提出解决方案:)~)

动态调用的过程大致如下:

1.Make sure you have 4K of scratch space at the bottom of your stack.

-- Do this before or just at your program starting.

2.Dynamic - loading Cygwin1.dll, and call the method : "cygwin_dll_init" to do the Init. work.

3.Dynamic - loading the function u wanna in Cygwin-DLL.

即确保你的堆栈底部有大约4K的空间 (其实是Cywin里面有个叫cygtls的结构体决定的, 一般不会超过4KB). 这4KB空间即是Cygwin平台运行时,其做一些操作所需要的一个空间, 所以必须确保这块空间留给Cywin, 而不是应用程序本身.   然后, 动态调用Cygwin1.dll里面的cygwin_dll_init方法做初始化动作. 到此, 初始化的动作就全部完成了. 接下来, 就可以动态调用任意你想要的在Cygwin-DLL里面的Function了.

在实现方法上, 由Max Kaehn提供了一种简单的方法实现. (见下面的参考链接-2)

主要的代码贴在这里: (由Max Kaehn提供, 再由我的一位同事XiaoHu精简改写 ^_^ ~~)

padding.cpp :


#include <windows.h>


#include <stdio.h>


#include <iostream>


#include <vector>


#include "padding.h"




using std::cout;


using std::cerr;


using std::endl;




padding *padding::_main = NULL;


DWORD padding::_mainTID = 0;




padding::padding ()


{


_main = this;


_mainTID = GetCurrentThreadId ();




_end = _padding + sizeof (_padding);


char *stackbase;


#ifdef __GNUC__


__asm__ (


"movl %%fs:4, %0"


:"=r"(stackbase)


);


#else


__asm


{


mov eax, fs:[4];


mov stackbase, eax;


}


#endif


_stackbase = stackbase;




// We've gotten as close as we can to the top of the stack. Even


// subverting the entry point, though, still doesn't get us there-- I'm


// getting 64 bytes in use before the entry point. So we back up the data


// there and restore it when the destructor is called:


if ((_stackbase - _end) != 0)


{


size_t delta = (_stackbase - _end);




_backup.resize (delta);




memcpy (&(_backup[0]), _end, delta);


}


}




padding::~padding ()


{


_main = NULL;




if (_backup.size ())


{


memcpy (_end, &(_backup[0]), _backup.size ());


}


}




void padding::check ()


{


if (_main == NULL)


throw std::runtime_error ("No padding declared!");


if (_mainTID != GetCurrentThreadId ())


throw std::runtime_error ("You need to initialize cygwin::connector "


"in the same thread in which you declared the "


"padding.");




if (_main->_backup.size ())


cout << "Warning! Stack base is "


<< static_cast<void *>(_main->_stackbase)


<< ". padding ends at " << static_cast<void *>(_main->_end)


<< ". Delta is " << (_main->_stackbase - _main->_end)


<< ". Stack variables could be overwritten!" << endl;


}

cygload.cpp :


#include <windows.h>


#include <stdio.h>


#include <vector>


#include "padding.h"




HMODULE hModule = NULL;




void InitCygwin()


{


if(hModule == NULL)


{


hModule = LoadLibrary(TEXT("cygwin1.dll"));


void (*cygwin_dll_init)() =(void (*)())GetProcAddress(hModule, "cygwin_dll_init");


cygwin_dll_init();


}


}




void FreeCygwin()


{


if(hModule != NULL)


{


FreeLibrary(hModule);


hModule = NULL;


}


}




extern "C" void CygwinStartUp(void (*main)())


{


padding padding;


InitCygwin();


main();


FreeCygwin();


}





将上面的代码用VS.NET编译成CygLoad.dll.

下面是Main-Function开始时调用的代码(用VB.NET编写)


Imports System.Runtime.InteropServices




Friend Class Program


' Nested Types


Public Delegate Sub MainEntryMethod()


' Methods


<DllImport("CygLoad.dll")> _


Public Shared Sub CygwinStartUp(ByVal mainEntry As MainEntryMethod)


End Sub




<STAThread()> _


Friend Shared Sub Main()


Program.CygwinStartUp(New Program.MainEntryMethod(AddressOf Program.MainEntry))


End Sub




Friend Shared Sub MainEntry()


Application.EnableVisualStyles()


Application.SetCompatibleTextRenderingDefault(False)


Application.Run(New MainForm())


End Sub


End Class







上面的代码即是做初始化工作, 完成后, 就可以在你的代码的任意地方动态调用function了, 如下:


void FunctionInCygwin(char *str)


{


void (*lpFunctionInCygwin)(char*);


HMODULE hExport = LoadLibrary(TEXT("FunctionInCygwin.dll")); //Cygwin编译的实际的DLL


lpFunctionInCygwin= (void(*)(char*))GetProcAddress(hExport,"FunctionInCygwin");


lpFunctionInCygwin(str); //动态调用该DLL里面的FunctionInCygwin方法.


FreeLibrary(hExport);


}

到此调用全部Over. 在你的代码里面直接调用FunctioninCygwin即可(实际上是动态调用Cygwin编译的FunctionInCygwin.dll 里面的 FunctionInCygwin(char *) 方法.



参考:

http://cygwin.com/faq/faq.programming.html#faq.programming.msvs-mingw

http://cygwin.com/ml/cygwin-patches/2005-q2/msg00102.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: