C语言,主程序怎么把文件指针传给dll

拉菲一箱 发布于 2011/09/26 21:14
阅读 1K+
收藏 0

如题,最好给个例子

多谢

加载中
0
周翼翼
周翼翼

为什么是文件指针而不是文件名?

如果非是文件指针,主程序open得到FILE*指针,做为参数传给dll里的函数,不行嘛?

0
拉菲一箱
拉菲一箱

引用来自“周翼翼”的答案

为什么是文件指针而不是文件名?

如果非是文件指针,主程序open得到FILE*指针,做为参数传给dll里的函数,不行嘛?

不行的
0
divl
divl
诶,dll不就是个函数库么;用户层程序用的是句柄(数组索引),系统层程序(如驱动)可以用指针(数组的具体值)【ms规定的】;win内核是基于面向对象的思想的,当我们使用资源是会产生一个上下文(就像指令的上下文:ip,cs,ss,eax...),如当操做文件时,是不需要记录当前记录的位置了,这个信息就记录在对象(在打开文件时创建)里面;对象属于对象目录;对象说明白点就是个数据结构,对象指针指向它;应用程序有个数组记录你打开的资源(句柄,指针);当然是否有H能绕过这个机制,在应用层用指针这我就不知道了;
0
hikari
hikari

1. 新建一个dll项目,名字为file-dll,在file-dll.cpp里面添加以下代码,然后编译:

#include <stdio.h>

extern "C"
{
	__declspec(dllexport)
		long MyFileHandler(void **aFile);
};

long MyFileHandler(void **aFile)
{
	if (!aFile)
		return -1;

	FILE *file = (FILE*)(*aFile);

	if (!file)
		return -1;

	fseek(file, 0, SEEK_END);

	return ftell(file);
}

2. 新建一个exe项目,名字为file-exe(console类型的),在file-exe.cpp里面添加以下代码, 运行之前把file-dll.dll复制到file-exe项目的Debug目录

#include <windows.h>

typedef long (* MyFileHandler_Ptr)(void **aFile);

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE dll = LoadLibraryA("file-dll.dll");
	if (!dll)
		return -1;

	MyFileHandler_Ptr myFileHandler = (MyFileHandler_Ptr)GetProcAddress(dll, "MyFileHandler");
	if (!myFileHandler)
		return -1;

	FILE *file = fopen("k:\\temp\\sites.txt", "rb");
	if (file)
	{
		long testValue = 0;
		testValue = myFileHandler((void**)&file);
		printf("testValue = %d\n", testValue);
		fclose(file);
	}
	else
		printf("test failed.\n");

	getchar();

	return 0;
}

0
拉菲一箱
拉菲一箱

引用来自“hikari”的答案

1. 新建一个dll项目,名字为file-dll,在file-dll.cpp里面添加以下代码,然后编译:

#include <stdio.h>

extern "C"
{
	__declspec(dllexport)
		long MyFileHandler(void **aFile);
};

long MyFileHandler(void **aFile)
{
	if (!aFile)
		return -1;

	FILE *file = (FILE*)(*aFile);

	if (!file)
		return -1;

	fseek(file, 0, SEEK_END);

	return ftell(file);
}

2. 新建一个exe项目,名字为file-exe(console类型的),在file-exe.cpp里面添加以下代码, 运行之前把file-dll.dll复制到file-exe项目的Debug目录

#include <windows.h>

typedef long (* MyFileHandler_Ptr)(void **aFile);

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE dll = LoadLibraryA("file-dll.dll");
	if (!dll)
		return -1;

	MyFileHandler_Ptr myFileHandler = (MyFileHandler_Ptr)GetProcAddress(dll, "MyFileHandler");
	if (!myFileHandler)
		return -1;

	FILE *file = fopen("k:\\temp\\sites.txt", "rb");
	if (file)
	{
		long testValue = 0;
		testValue = myFileHandler((void**)&file);
		printf("testValue = %d\n", testValue);
		fclose(file);
	}
	else
		printf("test failed.\n");

	getchar();

	return 0;
}

确定能行?
0
mallon
mallon
别这么干,会出问题的!
hikari
hikari
请教一下,具体会出什么问题?
0
周翼翼
周翼翼
~~,我明白了.不能这么传.main函数和dll函数并不是在同一进程空间内的,dll里有个dllmain不是?不同进程空间的内存不能传来传去,我试过,好像是在main里申请的char[]也不能传进dll,内存保护?
周翼翼
周翼翼
@hikari : 你说的对.我再学习学习.
hikari
hikari
这里的代码没有创建一个新的进程
0
hikari
hikari

引用来自“大竹叶青”的答案

引用来自“hikari”的答案

1. 新建一个dll项目,名字为file-dll,在file-dll.cpp里面添加以下代码,然后编译:

#include <stdio.h>

extern "C"
{
	__declspec(dllexport)
		long MyFileHandler(void **aFile);
};

long MyFileHandler(void **aFile)
{
	if (!aFile)
		return -1;

	FILE *file = (FILE*)(*aFile);

	if (!file)
		return -1;

	fseek(file, 0, SEEK_END);

	return ftell(file);
}

2. 新建一个exe项目,名字为file-exe(console类型的),在file-exe.cpp里面添加以下代码, 运行之前把file-dll.dll复制到file-exe项目的Debug目录

#include <windows.h>

typedef long (* MyFileHandler_Ptr)(void **aFile);

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE dll = LoadLibraryA("file-dll.dll");
	if (!dll)
		return -1;

	MyFileHandler_Ptr myFileHandler = (MyFileHandler_Ptr)GetProcAddress(dll, "MyFileHandler");
	if (!myFileHandler)
		return -1;

	FILE *file = fopen("k:\\temp\\sites.txt", "rb");
	if (file)
	{
		long testValue = 0;
		testValue = myFileHandler((void**)&file);
		printf("testValue = %d\n", testValue);
		fclose(file);
	}
	else
		printf("test failed.\n");

	getchar();

	return 0;
}

确定能行?
VS2008我运行过了,这段代码是可行的,但是补充说明一下的是,这里代码不是说最好的或者最合理的甚至说最安全的,只是用来说明你提出的问题的其中一个可尝试的方案。用_open函数也可以,那个返回到是int,用CreateFileW/CreateFileA的WINAPI返回的是HANDLE,但是这个HANDLE要是要传到别的进程里面,需要在CreateProcess的启动参数设置句柄可继承,或者用DuplicateHandle复制一个HANDLE给新的进程,不过这样有点复杂化了。
 
Dll要导出FILE*是不可以的,因为导出Dll函数时也需要把参数涉及的结构也导出,这样有可能要导出很大一棵关联的定义树。

所以用了void**,在32位的情况下,传递结构指针的地址是一个较简单的做法。

这里不涉及多进程,也不需定义fastcall或者stdcall之类的,但是要保证exe和dll的默认调用协议都是一样的。

如果你试过不行,请多多指教,个人用vc也不是很久。

如果你对vc研究感兴趣,也欢迎参观我的浏览器项目(涉及到vc/c#,浏览器接口,浏览器控件,detours沙盒原理,内存加载dll原理。),里面有一些调用dll的示范项目。

0
divl
divl

引用来自“周翼翼”的答案

~~,我明白了.不能这么传.main函数和dll函数并不是在同一进程空间内的,dll里有个dllmain不是?不同进程空间的内存不能传来传去,我试过,好像是在main里申请的char[]也不能传进dll,内存保护?
传是可以传的,应用程序切入内核是通过调用WIN32API(crt也会调用),而win32api是以dll形式提供的(user32.dll,kernel32.dll,gdi32.dll),举个例子:在读文件的时候是否回传个地址给read();dll和调用它的进程是在同一个进程空间里的(属于关系),只是在物理内存中只有一份dll,进程调用它,就映射进自己的虚拟地址空间(系统dll映射地址都一样【所有进程用的是同一个系统】,用户态dll就有可能不一样,如果建议地址没被占用就一样,如:有的映射到0X01000000,有点到0X02000000随便举的);能不能吧地址传入dll,要看具体的声明;在调用dll时,有一个多线程的问题(即函数是否可重入的问题),要用同步对象进行同步或异步;有一个多进程的问题,多个进程同时映射时的地址,这个是dll有自己的存储空间,就像线程的TLS;还有是dll是系统态的还用户态,如果是系统态的在吧地址传进去后,发生了调度,这个虚拟地址在别的进程指向了别的空间,一般就要可以把虚拟地址换为物理地址再用;不同进程空间的地址也可以传,只是不是直接传的,比如,不同进程间的同步,共享内存啊;实际能不能传就是虚拟地址与物理地址映射的问题,会不会因执行顺序而结果不一样;   一家之言,仅供参考
周翼翼
周翼翼
我再去学习看看能不能理解.
0
明月惊鹊
明月惊鹊

引用来自“周翼翼”的答案

~~,我明白了.不能这么传.main函数和dll函数并不是在同一进程空间内的,dll里有个dllmain不是?不同进程空间的内存不能传来传去,我试过,好像是在main里申请的char[]也不能传进dll,内存保护?
怎么会不同的进程空间???? 应该是相同的。
周翼翼
周翼翼
是相同的.我理解错了.
返回顶部
顶部