请问怎么在子线程中调用dll动态库里的函数啊

请问怎么在子线程中调用dll动态库里的函数啊,第1张

typedef DWORD(PMessageBox)(HWND,PCHAR,PCHAR,UINT);

PMessageBox ads;

ads = (PMessageBox)GetProcAddress(LoadLibrary("user32dll"),"MessageBoxA");

ads(0,"123","123",0);

涉及到的API请自行百度

LoadLibrary可用GetModuleHandle进行代替。

比如你想注入的进程是QQEXE

那么首先判断进程是否存在,判断方法如下:

在USES 中加入TLhelp32单元

function Tform1CheckTask(ExeFileName: string): Boolean;\\判断进程是否存在

const

PROCESS_TERMINATE=$0001;

var

ContinueLoop: BOOL;

FSnapshotHandle: THandle;

FProcessEntry32: TProcessEntry32;

begin

result := False;

FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);

FProcessEntry32dwSize := Sizeof(FProcessEntry32);

ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);

while integer(ContinueLoop) <> 0 do begin

if ((UpperCase(ExtractFileName(FProcessEntry32szExeFile)) =UpperCase(ExeFileName))

or (UpperCase(FProcessEntry32szExeFile) =UpperCase(ExeFileName))) then

result := True;

ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32);

end;

end;

调用方法:

procedure TForm1Button1Click(Sender: TObject);\\按钮上单击事件

begin

if CheckTask('qqexe')=true then\\判断qqexe是否存在

showmessage('QQ进程存在!');//如果存在一个提示

//(当然这里你可以换成你想执行的代码:载入DLL。根据你的需要而定吧)

end;

创建DLL工程

这里,我们为了简要说明DLL的原理,我们决定使用最简单的编译环境VC60,如下图,我们先建立一个新的Win32 Dynamic-Link Library工程,名称为“MyDLL”,在Visual Studio中,你也可以通过建立Win32控制台程序,然后在“应用程序类型”中选择“DLL”选项,

点击确定,选择“一个空的DLL工程”,确定,完成即可。

一个简单的dll

在第一步我们建立的工程中建立一个源码文件”dllmaincpp“,在“dllmaincpp”中,键入如下代码

[cpp] view plain copy

#include <Windowsh>

#include <stdioh>

BOOL APIENTRY DllMain(HMODULE hModule, 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文件,“MyDLLdll”,注意,代码里面的printf语句,并不是必须的,只是我们用于测试程序时使用。而DllMain函数,是dll的进入/退出函数。

实际上,让线程调用DLL的方式有两种,分别是隐式链接和显式链接,其目的均是将DLL的文件映像映射进线程的进程的地址空间。我们这里只大概提一下,不做深入研究,如果感兴趣,可以去看《Window高级编程指南》的第12章内容。

隐式链接调用

隐士地链接是将DLL的文件影响映射到进程的地址空间中最常用的方法。当链接一个应用程序时,必须制定要链接的一组LIB文件。每个LIB文件中包含了DLL文件允许应用程序(或另一个DLL)调用的函数的列表。当链接器看到应用程序调用了某个DLL的LIB文件中给出的函数时,它就在生成的EXE文件映像中加入了信息,指出了包含函数的DLL文件的名称。当 *** 作系统加载EXE文件时,系统查看EXE文件映像的内容来看要装入哪些DLL,而后试图将需要的DLL文件映像映射到进程的地址空间中。当寻找DLL时,系统在系列位置查找文件映像。

1包含EXE映像文件的目录

2进程的当前目录

3Windows系统的目录

4Windows目录

5列在PATH环境变量中的目录

这种方法,一般都是在程序链接时控制,反映在链接器的配置上,网上大多数讲的各种库的配置,比如OPENGL或者OPENCV等,都是用的这种方法

显式链接调用

这里我们只提到两种函数,一种是加载函数

[cpp] view plain copy

HINSTANCE LoadLibrary(LPCTSTR lpszLibFile);

HINSTANCE LoadLibraryEx(LPCSTR lpszLibFile,HANDLE hFile,DWORD dwFlags);

返回值HINSTANCE值指出了文件映像映射的虚拟内存地址。如果DLL不能被映进程的地址空间,函数就返回NULL。你可以使用类似于

[cpp] view plain copy

LoadLibrary("MyDLL")

或者

[cpp] view plain copy

LoadLibrary("MyDLLdll")

的方式进行调用,不带后缀和带后缀在搜索策略上有区别,这里不再详解。

显式释放DLL

在显式加载DLL后,在任意时刻可以调用FreeLibrary函数来显式地从进程的地址空间中解除该文件的映像。

[cpp] view plain copy

BOOL FreeLibrary(HINSTANCE hinstDll);

这里,在同一个进程中调用同一个DLL时,实际上还牵涉到一个计数的问题。这里也不在详解。

线程可以调用GetModuleHandle函数:

[cpp] view plain copy

GetModuleHandle(LPCTSTR lpszModuleName);

来判断一个DLL是否被映射进进程的地址空间。例如,下面的代码判断MyDLLdll是否已被映射到进程的地址空间,如果没有,则装入它:

[cpp] view plain copy

HINSTANCE hinstDll;

hinstDll = GetModuleHandle("MyDLL");

if (hinstDll == NULL){

hinstDll = LoadLibrary("MyDLL");

}

实际上,还有一些函数,比如 GetModuleFileName用来获取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 copy

#include <iostream>

#include <Windowsh>

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;

}

代码很好理解,但是前提是,你必须对线程有一定的概念。另外,注意,我们上面编译的获得的“MyDLLdll"必须拷贝到能够让我们这个工程找到的地方,也就是上面我们提到的搜索路径中的一个地方。

这里,我们先贴结果,当然,这只是在我机器上其中某次运行结果。

有了上面我们介绍的知识,这个就不是很难理解,主进程在调用LoadLibrary时,用DLL_PROCESS_ATTACH调用了DllMain函数,而线程创建时,用DLL_THREAD_ATTACH调用了DllMain函数,而由于主线程和子线程并行的原因,可能输出的时候会有打断。但是,这样反而能让我们更清楚的理解程序。

不能说dll中的函数都不能被并行调用。但是如果dll本身使用了全局变量,并且没有做同步,肯定是不行的,你的dll就是这个情况。

那么你需要自己同步,也就是保证始终只有一个线程在调用:

object lockobj = new object();

ParallelFor(0, _dtpostRowsCount, (i) =>

{

string ip = _dtpostRows[i][2]ToString();

newka newkas = new newka(ip, 3000, 1);

lock (lockobj)

{

PingTask(_dtpostRows[i], newkas);

}

ThreadSleep(300);

});

不能直接导入到maya中,必须先导入到3dmax中再倒入到maya中

步骤:

先下载GameAssassin和3dmax插件与需要的dll(这些文件可以到GameAssassin官方网站上下载到),并运行

安装3dmax插件

运行游戏,按下ALT+F7截取模型

打开3dmax并导入模型

打开文件菜单中的导出,格式为OBJ(也可以是FBX)

打开maya并导入你导出的文件就可以了

以上就是关于请问怎么在子线程中调用dll动态库里的函数啊全部的内容,包括:请问怎么在子线程中调用dll动态库里的函数啊、Delphi注入DLL 如何获取当前进程名、如何编译生成dll等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9502367.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存