delphi 调用 c语言 dll
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了delphi 调用 c语言 dll相关的知识,希望对你有一定的参考价值。
我用C语言写了一个Dll,编译成功。
是一个非常简单的加密算法,代码如下:
#include<stdio.h>
__declspec(dllexport) void Encipher(char a[16])
int i,len;
int s=1;
len=strlen(a);
for(i=0;i<len;i++)
a[i]=a[i]+s;
s=s+2;
现在我在Delphi中如何调用它并实现这样的功能,点击Button1,获取edit1.text的内容,存于数组中,然后调用Dll中的函数,进行简单加密,然后将结果赋给edit2.text。
型参了吧。
不管怎么说,照着你的要求做了 delphi程序。
type
TArrChar = array[0..15] of char;
procedure Encipher(a:TArrChar);cdecl;external 'xxx.dll';
implementation
$R *.dfm
procedure TForm1.Button1Click(Sender: TObject);
var
a:TArrChar;
begin
CopyMemory(@a,@Edit1.text[1],16);
Encipher(a);
Edit2.Text:=a;
end; 参考技术A 用delphi写dll啊,那样调用方便些。看不懂C语言的代码
从Delphi调用C ++ DLL时发生访问冲突
我在Visual C ++ 6.0中编写了Unicode DLL。然后尝试从Delphi XE3调用DLL函数。
当我在Delphi中调试时,当跨过线路调用DLL函数时,我总是会遇到访问冲突异常。
但是,当我在Visual C ++中调试时,我可以看到从Delphi传递的所有参数都是正确的,并且我可以毫无例外地跳过所有代码行。
如果在调试器之外运行,那么我将看不到任何“访问冲突异常。
我尝试了许多方法,但是仍然无法弄清楚在Delphi中调试时如何消除异常。
下面是Visual C ++ 6.0部分中的代码:
TestDLL.cpp:
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString((LPCSTR)IDS_MYTEST), lParam);
/*
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString(_T("Test")), lParam);*/
}
TestDLL.h:
// TestDLL.h : main header file for the TESTDLL DLL
//
#if !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
#define AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef BOOL (CALLBACK* MESSAGEPROC)(CONST DWORD dwMessageId, CONST LPVOID lp, LPVOID lParam);
VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam);
#ifdef __cplusplus
}
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
下面是Delphi XE3部分中的代码:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;
PForm1 = ^TForm1;
TMessageProc = function (const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
{$EXTERNALSYM TMessageProc}
var
Form1: TForm1;
procedure Test(const lpMessageProc: TMessageProc; lParam: Pointer); stdcall;
implementation
{$R *.dfm}
procedure Test; external 'TestDLL.dll' index 2;
function MessageProc(const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
begin
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test(MessageProc, @Self); // <---- This code line will cause "access violation
end;
我相信,当它尝试使用CString((LPCSTR)IDS_MYTEST)从资源加载字符串时,DLL测试功能中会出现问题。如果我将代码更改为CString(_T(“ Test”)),则问题消失。
谢谢
您猜想,此声明将无效:
CString((LPCSTR)IDS_MYTEST)
尽管CString
的此构造函数确实允许您向其传递资源ID,但它将尝试在调用进程的资源(即Delphi EXE的资源)而不是DLL的资源中查找资源。从DLL的资源加载字符串时,需要使用DLL的HINSTANCE
(由DLL的DllMain()
提供)。您可以为此使用CString::LoadString()
方法,例如:
CString::LoadString()
我终于弄清楚这是MFC代码(VC6.0版本)的错误。
我不知道是否可以发布MFC源代码,因此仅粘贴函数头和相关部分。
在Microsoft Visual Studio VC98 MFC SRC STRCORE.CPP中,我们可以看到以下三个功能:
HINSTANCE hInst;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;
return TRUE;
}
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
{
CString str;
str.LoadString(hInst, IDS_MYTEST);
(*lpMessageProc)(1500, (LPCTSTR)str, lParam);
}
}
正如我们在上面的代码片段中看到的那样,只有函数1包含将在lpsz上进行特殊处理并检查它是否是字符串资源ID的代码,如果是,则从资源中加载字符串。函数2和3都没有这样的特殊过程。
当我们在VS6中创建项目时,项目的默认设置为_MBCS,在这种情况下,功能1将变为[]。
////////////////////////////////////////////////////////////////////////////// // More sophisticated construction CString::CString(LPCTSTR lpsz) // Function 1 { Init(); if (lpsz != NULL && HIWORD(lpsz) == NULL) { UINT nID = LOWORD((DWORD)lpsz); if (!LoadString(nID)) TRACE1("Warning: implicit LoadString(%u) failed ", nID); } else { // Construct string normally } } ///////////////////////////////////////////////////////////////////////////// // Special conversion constructors #ifdef _UNICODE CString::CString(LPCSTR lpsz) // Function 2 { // Construct string normally } #else //_UNICODE CString::CString(LPCWSTR lpsz) // Function 3 { // Construct string normally } #endif //!_UNICODE
所以CString(((LPCSTR)nResID)将实际上调用函数1并正确加载字符串资源。
由于未定义_UNICODE,因此功能2将被禁用。函数3适用于宽字符字符串。
因此,对于_MBCS项目,一切都与MSDN文档完美且一致地工作。
但是,当我将_MBCS更改为_UNICODE时,功能1将变为
CString::CString(LPCSTR lpsz)
将启用功能2,并且将禁用功能3。
所以CString((LPCSTR)nResID)实际上会调用函数2,该函数没有特殊的过程来加载字符串资源,这会造成问题。
此问题有两种解决方案:
始终使用CString((LPCTSTR)nResID)而不是CString((LPCSTR)nResID)从资源加载字符串。但是,此用法与MSDN文档不一致,因此我们必须将其称为未记录的用法。
始终使用LoadString加载字符串资源。
尽管解决方案1稍微简单一些,但它是未记录的用法,所以我最终选择了解决方案2来解决我的问题。
非常感谢您为解决此问题所提供的所有帮助。
以上是关于delphi 调用 c语言 dll的主要内容,如果未能解决你的问题,请参考以下文章