我在Inno Setup Script中从DLL文件调用一个函数,它的返回类型是PAnsiChar
。为了获取整个字符串,我需要取消引用指针,但标准的Pascal语法在这里不起作用。有可能做到这一点吗?
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances@files:IsStartServer.dll stdcall setuponly';
function NextButtonClick(CurPage: Integer): Boolean;
var
hWnd: Integer;
Str : AnsiString;
begin
if CurPage = wpWelcome then begin
hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
MessageBox(hWnd, 'Hello from Windows API function', 'MessageBoxA', MB_OK or MB_ICONINFORMATION);
MyDllFuncSetup(hWnd, 'Hello from custom DLL function', 'MyDllFunc', MB_OK or MB_ICONINFORMATION);
Str := SQLDLL;
try
{ if this DLL does not exist (it shouldn't), an exception will be raised }
DelayLoadedFunc(hWnd, 'Hello from delay loaded function', 'DllFunc', MB_OK or MB_ICONINFORMATION);
except
{ handle missing dll here }
end;
end;
Result := True;
end;
我只有DLL文件。原始语言是德尔福。
我更新到最新版本的Inno Setup 6.0.3,并在我家用Windows 10 Pro机器上测试了以下代码:
[Setup]
AppName=My Program
AppVersion=1.5
WizardStyle=modern
DefaultDirName={autopf}\My Program
DisableProgramGroupPage=yes
DisableWelcomePage=no
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
Source: "IsStartServer.dll"; Flags: dontcopy
[Code]
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances@files:IsStartServer.dll stdcall';
function NextButtonClick(CurPage: Integer): Boolean;
var
Str : PAnsiChar;
begin
Str := SQLDLL;
Result := True;
end;
我不明白为什么它必须查看我的“临时”目录?我还听说这个问题可能与Windows 10 UAC的组策略有关,但我不确定我应该做些什么来消除这个错误。
在Inno Setup Pascal脚本中不能取消对指针的引用。
但也有许多黑客允许这样做。这些技巧非常具体,因此取决于特定的用例。
尽管在您的特定情况下,指向字符数组的指针在API中很普遍,Inno Setup Pascal脚本(类似于Delphi)可以将指向字符数组的指针分配给一个字符串。
因此,您应该能够简单地将PChar
分配给AnsiString
:
function ReturnsPAnsiChar: PAnsiChar; extern '...';
var
Str: AnsiString;
begin
Str := ReturnsPAnsiChar;
end;
请参阅如何将字符串从DLL返回到Inno安装程序?
如果我理解正确,您的SQLDLL
本身管理一些内存缓冲区并返回指向Unicode字符串的指针(不是ANSI,这就是为什么根据您的评论,当您尝试PAnsiChar
时只有一个字符)。
Inno Setup不直接支持这一点,甚至没有PWideChar
类型。但是,我们可以自己处理。我们只需要分配一个大小合适的Inno字符串并手动复制数据。
下面是一个如何做到这一点的示例。它使用GetCommandLineW
作为返回PWideChar
的示例函数,但您可以使用SQLDLL
函数执行同样的操作。
PWideChar
)。 < li >使用< code>lstrlenW获取字符串长度。 < li >创建一个空的常规< code >字符串,但使用< code>SetLength将其设置为正确的长度。这将保留足够的容量,我们可以在下一步将实际内容写入其中。 < li >使用< code>lstrcpyW将指针引用的字符串复制到常规< code>String变量。 < ul > < li >(如果您使用的是ANSI版本的Inno Setup:请使用< code>WideCharToMultiByte,参见本文末尾的我的更新。)
诀窍是导入 lstrcpyW
,这样目标指针被声明为字符串
,但源指针被声明为基数
(或我的 typedef PWideChar
在这里)。
type
PWideChar = Cardinal; { Inno doesn't have a pointer type, so we use a Cardinal instead }
{ Example of a function that returns a PWideChar }
function GetCommandLineW(): PWideChar;
external 'GetCommandLineW@kernel32.dll stdcall';
{ This function allows us to get us the length of a string from a PWideChar }
function lstrlenW(lpString: PWideChar): Cardinal;
external 'lstrlenW@kernel32.dll stdcall';
{ This function copies a string - we declare it in such a way that we can pass a pointer
to an Inno string as destination
This works because Inno will actually pass a PWideChar that points to the start of the
string contents in memory, and internally the string is still null-terminated
We just have to make sure that the string already has the right size beforehand! }
function lstrcpyW_ToInnoString(lpStringDest: String; lpStringSrc: PWideChar): Integer;
external 'lstrcpyW@kernel32.dll stdcall';
function InitializeSetup(): Boolean;
var
returnedPointer: PWideChar; { This is what we get from the external function }
stringLength: Cardinal; { Length of the string we got }
innoString: String; { This is where we'll copy the string into }
begin
{ Let's get the PWideChar from the external function }
returnedPointer := GetCommandLineW();
{ The pointer is actually just a renamed Cardinal at this point: }
Log('String pointer = ' + IntToStr(returnedPointer));
{ Now we have to manually allocate a new Inno string with the right length and
copy the data into it }
{ Start by getting the string length }
stringLength := lstrlenW(returnedPointer);
Log('String length = ' + IntToStr(stringLength));
{ Create a string with the right size }
innoString := '';
SetLength(innoString, stringLength);
{ This check is necessary because an empty Inno string would translate to a NULL pointer
and not a pointer to an empty string, and lstrcpyW cannot handle that. }
if StringLength > 0 then begin
{ Copy string contents from the external buffer to the Inno string }
lstrcpyW_ToInnoString(innoString, returnedPointer);
end;
{ Now we have the value stored in a proper string variable! }
Log('String value = ' + innoString);
Result := False;
end;
如果将其放入安装程序并运行,则会看到如下输出:
[15:10:55,551] String pointer = 9057226
[15:10:55,560] String length = 106
[15:10:55,574] String value = "R:\Temp\is-9EJQ6.tmp\testsetup.tmp" /SL5="$212AC6,121344,121344,Z:\Temp\testsetup.exe" /DEBUGWND=$222722
如您所见,命令行字符串(我们作为 PWideChar
获得)被正确复制到常规字符串变量中,并且可以在最后正常访问。
更新:如果您使用的是Inno Setup的ANSI版本,而不是Unicode,单独使用这段代码是不行的。需要的更改如下:不使用< code>lstrcpyW,而是使用< code>WideCharToMultiByte:
function WideCharToMultiByte_ToInnoString(CodePage: Cardinal; dwFlags: Cardinal; lpWideCharStr: PWideChar; cchWideChar: Cardinal; lpMultiByteStr: String; cbMultiByte: Cardinal; lpDefaultChar: Cardinal; lpUsedDefaultChar: Cardinal): Integer;
external 'WideCharToMultiByte@kernel32.dll stdcall';
{ Later on: Instead of calling lstrcpyW_ToInnoString, use this:
Note: The first parameter 0 stands for CP_ACP (current ANSI code page), and the
string lengths are increased by 1 to include the null terminator }
WideCharToMultiByte_ToInnoString(0, 0, returnedPointer, stringLength + 1, innoString, stringLength + 1, 0, 0);
本文向大家介绍C语言取消引用指针,包括了C语言取消引用指针的使用技巧和注意事项,需要的朋友参考一下 示例 要取消引用a_pointer并更改a的值,我们使用以下操作 可以使用以下打印语句对此进行验证。 但是,将一个NULL指针取消引用或其他无效指针将是错误的。这个 通常是未定义的行为。p1可能不会被取消引用,因为它指向的地址0xbad可能不是有效地址。谁知道那里有什么?它可能是操作系统内存,或另一
问题内容: 我最近才刚开始接触Go,我有一个主要的困惑点:我在努力理解何时确切需要显式取消引用指针。 例如,我知道运算符将处理对指针的解引用 在其他哪些情况下会这样做?例如,似乎使用数组。 我在规范中找不到此内容,指针部分很短,甚至没有提到取消引用。对取消引用go的指针的规则进行的任何澄清都将很棒! 问题答案: 所述选择器表达式(例如)这是否: 选择器会 自动取消引用 结构的 指针 。如果是指向结
问题内容: 如何将Item结构和所有指针复制到新结构? 我不希望新结构引用旧结构。 问题答案: 本质上您想要的是标准库不支持的深层副本。 您的选择: “手动”执行复制,例如,创建新的结构并复制字段,其中必须以递归方式手动复制指针或切片/地图/通道/等。 通过将您的结构分配给另一个可复制所有字段的结构,这是最容易做到的,因此,您基本上只需要培养指针/地图/切片等(但需要递归)。 使用外部库,例如,或
问题内容: 我是GoLang的新手,来自Delphi C ++世界-诚然对这种语言感到非常兴奋,我认为它将成为“下一件大事”。 我正在尝试了解Go解析器和编译器如何处理指针和引用-似乎找不到任何放置一些明确规则的地方。 例如,在下面的代码示例中,返回类型和局部变量是指针类型,并且在其声明中需要使用指针符号,但是在使用时不必取消引用它们:。但是在同一代码中,输入参数被声明为指针,并且必须被取消引用才
这是控制台报告中的代码和错误 启动层初始化期间发生错误 java.lang.module.FindException:无法为E:\seleniumwebdriversoftwares\org.testng.eclipse.updatesite\plugins\org.testng.source-6.14.2.r201802161450.jar派生模块描述符原因:java.lang.module.I
嗨我有以下方法: 不得不提的是,startDate和endDate是长变量。我尝试在if条件中添加null检查,也尝试使用longValue()方法,但没有结果。你知道我怎样才能解决这个问题吗?可能是fndBugs端的bug?