❶ 如何编译生成dll
使用VC下的cl和link手工创建dll并实现函数导入
1、创建dll头文件:
/*
* dllmain.h
*/
#ifndef _DLLMAIN_H
#define _DLLMAIN_H
int getNumber();
#endif
2、创建dll源文件:
/*
* dllmain.c
*/
#include "dllmain.h"
int getNumber()
{
return 10;
}
3、 创建def文件:
; export.def
LIBRARY MY_DLLMAIN ; MY_DLLMAIN 将成为生成的dll的名称
EXPORTS
getNumber @1 ; 这个名称即为函数的实际导出名称 @1为函数的导出编号
4、生成dll文件:
cl dllmain.c /c
link /def:export.def /dll dllmain.obj
这时,工程中已经包含了 dllmain.h dllmain.c export.def dllmain.obj dllmain.lib dllmain.exp MY_DLLMAIN.dll 其中,后4个文件是编译链接过程中生成的文件
5、创建dlltest.c:
/*
* dlltest.c
*/
#include <stdio.h>
#include "dllmain.h" //dll库的头文件
#pragma comment(lib,"dllmain.lib") //dllmain.lib即是上一步生成的文件
int main()
{
printf("%dn",getNumber());
}
6、编译、链接dlltest.c
cl dlltest.c /c
link dlltest.obj
注意:这里dllmain.lib和dllmain.h应该和dlltest.c在同一个目录中。此步的结果将生成 dlltest.exe
7、运行:
dlltest
这时,系统将载入my_dllmain.dll这个动态链接库,将调用其中的getNubmer函数。
❷ vfp如何调用C#编译的dll
这个跟调用其他dll方法一样的. 你试试如下方法:
假如该方法返回整型值, 2个参数都是字符型
DECLARE integer getainfo IN a.dll String,string
b=getainfo(参数1,参数2)
位置一般放到程序设置的默认目录下, 或者用set path to 指定的路径
❸ VFP如何编译
一、在本机编译、运行exe文件的做法:
⑴在项目中选中一个表单或prg文件,目的是作为主文件(启动文件);
⑵点击菜单"项目",选"设置主文件",选中的文件就为主文件;
⑶在项目窗口中选"连编",连编窗口选"连编可执行文件",选择路径和输入你要生成的exe文件的名字,连编就生成了可执行文件。
二、 你自己用vfp作一个发布安装盘,刻成光盘,送给用户:。
用vfp作一个发布安装盘,步骤:
1 将要发布的文件(.exe,...)复制到一个文件夹中(假设为d:\xxx)
2 运行 vfp6,工具-〉向导-〉安装,在发布树在哪个目录对话框中,选择d:\xxx,下一步
3在步骤2,中如果你在程序中,没有用到控件,单击 下一步即可,否则选定您用到的第三方控件
4在 步骤3磁盘映像 中 选择网络安装,并选个一个要生成的目录(如d:\MySetup)下一步
5 在 步骤4安装选项 的 安装对话标题 中输入标题 如:建筑设备管理系统 版权信息 下一步
6 安装目录、程序组(最好也写:如:建筑设备管理系统)下一步
7 下一步
8 完成
9 退出vfp60
10 到 D:\mysetup\netsetup 下,将文件刻录到光盘(或拷贝U盘)到客户机上,setup即可。
❹ vfp生成dll
把所有的文件都包含在项目中,全部编译到EXE文件中,别人就看不见改不了了。
❺ 如何将VFP9.0的prg文件编译成exe文件
1.建立一个Project , 执行 BUILD,选择 Win32 executable,编译出 EXE
2 .把多个 VFPxxx.Dll, msvcr71.DLL 与编译出来的 EXE 放在同一目录,即可
❻ 怎样用VPF把文件编译成.exe文件
vfp 6.0下:
把以下文件VFP6R.DLL,vfp6rchs.dll,vfp6renu.dll放到windows\system32下,或程序目录下即可.
❼ VFP编写的dll 能不能给VC调用
可以的,vfp写的DLL是COM模式,需要先注册后才能调用。而且DLL内部所含的方法是看不到的,需要开发者提供 方法名 和参数列表,返回值类型。具体的调用方法是用Createobj()...
❽ 在vfp如何联编急要详细步骤
新建一个项目,把你的表单、报表、程序之类反正你编的东西都加进去,
如果你运行的是一个程序的话,直接把它设为主程序,
否则新建一个主程序,
格式参考如下:
do form forms\kl *你首先运行的表单,如果是其它的,自己改一下
on shutdown quit
read event
如果您的程序全部都编好了就可以开始编译您的软件了,很简单,方法如下:
1.按下项目管理器中的连编,出现对话框;
2.选择“连编可执行程序”,确定;
3.输入编译后的EXE文件名,注意目录,然后保存;
接着系统便进入编译过程,这一过程是电脑自动完成的。在这一过程中系统会首先检查您的程序是否有错误,如有错误有时会给出提示,在提示中您一般可以选择“忽略”、“全部忽略”、“取消”,这里的“忽略”就是不管出现的错误继续编译,当然一般不应该这样,一旦出现错误提示应选择取消,然后找出相应的错误,改正后再编译。为了容易查找错误,系统还将错误记录下来,在菜单的“项目”-“错误”中可以看到,其中会讲明是什么错误,发生在哪个程序的哪一条语句中。对于有些错误会不给出提示而直接忽略,但它仍然会把错误记录下来。
如果系统编译时没有记录错误,那是因为在菜单上的“工具”-“选项”-“常规”-“编程”中的“记录编译错误”没有打开。
VFP编译生成的EXE文件是不能直接在另一台电脑上运行的,除非该电脑中已经装有VFP系统,因为EXE文件的运行要依赖于安装在WINDOWS系统中的运行时的库。为此要为该软件制作一套安装盘,方法如下:
在您开发的软件的目录下建一个子目录,比如叫exe,当然您也可以建在别什么地方或叫别的什么名字;
将该软件所要用到的数据库(dbc)、数据库备注(dct)、数据库索引(dcx)、表(dbf)、表索引(cdx、idx)、表备注(fpt)、内存变量文件(mem)等等,再就是编译后的exe文件通通复制到上面所建的目录中,然后将复制过去的数据表中试运行用的记录清除,但要注意有些数据可能是软件预先应提供的,那么就不应该删除,如与软件一起提供给用户的。
注意:prg文件、菜单文件、表单文件、报表文件、标签文件等等不要复制进去,因为它们已经被编译在exe文件中了,还有就是不属于软件运行的文件,如系统分析文件,也不要复制进去。
不用制作安装盘,不需安装VFP也可以.只需要在默认目录下能找到相应的.DLL文件,VFP编译的EXE文件就能正常运行.
对于VFP5编译的程序,.DLL文件是VFP500.DLL,VFP500CHS.DLL.对于VFP6编译的程序,DLL文件是VFP6R.DLL,VFP6RCHS.DLL,对于VFP7编译的程序,DLL文件是MSVCR70.DLL,VFP7R.DLL,VFP7RCHS.DLL.
在发布你的应用程序时,将EXE文件和上述DLL文件拷贝到同一个目录下就可以了.
❾ 如何编译生成dll
创建DLL工程
这里,我们为了简要说明DLL的原理,我们决定使用最简单的编译环境VC6.0,如下图,我们先建立一个新的Win32 Dynamic-Link Library工程,名称为“MyDLL”,在Visual Studio中,你也可以通过建立Win32控制台程序,然后在“应用程序类型”中选择“DLL”选项,
点击确定,选择“一个空的DLL工程”,确定,完成即可。
一个简单的dll
在第一步我们建立的工程中建立一个源码文件”dllmain.cpp“,在“dllmain.cpp”中,键入如下代码
[cpp] view plain
#include <Windows.h>
#include <stdio.h>
BOOL APIENTRY DllMain(HMODULE hMole, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
之后,我们直接编译,即可以在Debug文件夹下,找到我们生成的dll文件,“MyDLL.dll”,注意,代码里面的printf语句,并不是必须的,只是我们用于测试程序时使用。而DllMain函数,是dll的进入/退出函数。
实际上,让线程调用DLL的方式有两种,分别是隐式链接和显式链接,其目的均是将DLL的文件映像映射进线程的进程的地址空间。我们这里只大概提一下,不做深入研究,如果感兴趣,可以去看《Window高级编程指南》的第12章内容。
隐式链接调用
隐士地链接是将DLL的文件影响映射到进程的地址空间中最常用的方法。当链接一个应用程序时,必须制定要链接的一组LIB文件。每个LIB文件中包含了DLL文件允许应用程序(或另一个DLL)调用的函数的列表。当链接器看到应用程序调用了某个DLL的LIB文件中给出的函数时,它就在生成的EXE文件映像中加入了信息,指出了包含函数的DLL文件的名称。当操作系统加载EXE文件时,系统查看EXE文件映像的内容来看要装入哪些DLL,而后试图将需要的DLL文件映像映射到进程的地址空间中。当寻找DLL时,系统在系列位置查找文件映像。
1.包含EXE映像文件的目录
2.进程的当前目录
3.Windows系统的目录
4.Windows目录
5.列在PATH环境变量中的目录
这种方法,一般都是在程序链接时控制,反映在链接器的配置上,网上大多数讲的各种库的配置,比如OPENGL或者OPENCV等,都是用的这种方法
显式链接调用
这里我们只提到两种函数,一种是加载函数
[cpp] view plain
HINSTANCE LoadLibrary(LPCTSTR lpszLibFile);
HINSTANCE LoadLibraryEx(LPCSTR lpszLibFile,HANDLE hFile,DWORD dwFlags);
返回值HINSTANCE值指出了文件映像映射的虚拟内存地址。如果DLL不能被映进程的地址空间,函数就返回NULL。你可以使用类似于
[cpp] view plain
LoadLibrary("MyDLL")
或者
[cpp] view plain
LoadLibrary("MyDLL.dll")
的方式进行调用,不带后缀和带后缀在搜索策略上有区别,这里不再详解。
显式释放DLL
在显式加载DLL后,在任意时刻可以调用FreeLibrary函数来显式地从进程的地址空间中解除该文件的映像。
[cpp] view plain
BOOL FreeLibrary(HINSTANCE hinstDll);
这里,在同一个进程中调用同一个DLL时,实际上还牵涉到一个计数的问题。这里也不在详解。
线程可以调用GetMoleHandle函数:
[cpp] view plain
GetMoleHandle(LPCTSTR lpszMoleName);
来判断一个DLL是否被映射进进程的地址空间。例如,下面的代码判断MyDLL.dll是否已被映射到进程的地址空间,如果没有,则装入它:
[cpp] view plain
HINSTANCE hinstDll;
hinstDll = GetMoleHandle("MyDLL");
if (hinstDll == NULL){
hinstDll = LoadLibrary("MyDLL");
}
实际上,还有一些函数,比如 GetMoleFileName用来获取DLL的全路径名称,FreeLibraryAndExitThread来减少DLL的使用计数并退出线程。具体内容还是参见《Window高级编程指南》的第12章内容,此文中不适合讲太多的内容以至于读者不能一下子接受。
DLL的进入与退出函数
说到这里,实际上只是讲了几个常用的函数,这一个小节才是重点。
在上面,我们看到的MyDLL的例子中,有一个DllMain函数,这就是所谓的进入/退出函数。系统在不同的时候调用此函数。这些调用主要提供信息,常常被DLL用来执行进程级或线程级的初始化和清理工作。如果你的DLL不需要这些通知,就不必再你的DLL源代码中实现此函数,例如,如果你创建的DLL只含有资源,就不必实现该函数。但如果有,则必须像我们上面的格式。
DllMain函数中的ul_reason_for_call参数指出了为什么调用该函数。该参数有4个可能值: DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH、DLL_PROCESS_DETACH。
其中,DLL_PROCESS_ATTACH是在一个DLL首次被映射到进程的地址空间时,系统调用它的DllMain函数,传递的ul_reason_for_call参数为DLL_PROCESS_ATTACH。这只有在首次映射时发生。如果一个线程后来为已经映射进来的DLL调用LoadLibrary或LoadLibraryEx,操作系统只会增加DLL的计数,它不会再用DLL_PROCESS_ATTACH调用DLL的DllMain函数。
而DLL_PROCESS_DETACH是在DLL被从进程的地址空间解除映射时,系统调用它的DllMain函数,传递的ul_reason_for_call值为DLL_PROCESS_DETACH。我们需要注意的是,当用DLL_PROCESS_ATTACH调用DLL的DllMain函数时,如果返回FALSE,说明初始化不成功,系统仍会用DLL_PROCESS_DETACH调用DLL的DllMain。因此,必须确保没有清理那些没有成功初始化的东西。
DLL_THREAD_ATTACH:当进程中创建一个线程时,系统察看当前映射到进程的地址空间中的所有DLL文件映像,并用值DLL_THREAD_ATTACH调用所有的这些DLL的DllMain函数。该通知告诉所有的DLL去执行线程级的初始化。注意,当映射一个新的DLL时,进程中已有的几个线程在运行,系统不会为已经运行的线程用值DLL_THREAD_ATTACH调用DLL的DllMain函数。
而DLL_THREAD_DETACH,如果线程调用ExitThread来终结(如果让线程函数返回而不是调用ExitThread,系统会自动调用ExitThread),系统察看当前映射到进程空间的所有DLL文件映像,并用值DLL_THREAD_DETACH来调用所有的DLL的DllMain函数。该通知告诉所有的DLL去执行线程级的清理工作。
这里,我们需要注意的是,如果线程的终结是因为系统中的一个线程调用了TerminateThread,系统就不会再使用DLL_THREAD_DETACH来调用DLL和DllMain函数。这与TerminateProcess一样,不再万不得已时,不要使用。
下面,我们贴出《Window高级编程指南》中的两个图来说明上述四种参数的调用情况。
好的,介绍了以上的情况,下面,我们来继续实践,这次,建立一个新的空的win32控制台工程TestDLL,不再多说,代码如下:
[cpp] view plain
#include <iostream>
#include <Windows.h>
using namespace std;
DWORD WINAPI someFunction(LPVOID lpParam)
{
cout << "enter someFunction!" << endl;
Sleep(1000);
cout << "This is someFunction!" << endl;
Sleep(1000);
cout << "exit someFunction!" << endl;
return 0;
}
int main()
{
HINSTANCE hinstance = LoadLibrary("MyDLL");
if(hinstance!=NULL)
{
cout << "Load successfully!" << endl;
}else {
cout << "Load failed" << endl;
}
HANDLE hThread;
DWORD dwThreadId;
cout << "createThread before " << endl;
hThread = CreateThread(NULL,0,someFunction,NULL,0,&dwThreadId);
cout << "createThread after " << endl;
cout << endl;
Sleep(3000);
cout << "waitForSingleObject before " << endl;
WaitForSingleObject(hThread,INFINITE);
cout << "WaitForSingleObject after " << endl;
cout << endl;
FreeLibrary(hinstance);
return 0;
}
代码很好理解,但是前提是,你必须对线程有一定的概念。另外,注意,我们上面编译的获得的“MyDLL.dll"必须拷贝到能够让我们这个工程找到的地方,也就是上面我们提到的搜索路径中的一个地方。
这里,我们先贴结果,当然,这只是在我机器上其中某次运行结果。
有了上面我们介绍的知识,这个就不是很难理解,主进程在调用LoadLibrary时,用DLL_PROCESS_ATTACH调用了DllMain函数,而线程创建时,用DLL_THREAD_ATTACH调用了DllMain函数,而由于主线程和子线程并行的原因,可能输出的时候会有打断。但是,这样反而能让我们更清楚的理解程序。