- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图将TeamSpeak3 SDK与我的delphi一起使用,但遇到了一些问题,代码可以编译并可以正常工作,大多数代码是示例项目中的示例代码,但尝试读取返回的数据除外。
1.我可以正确释放内存吗?
2.我是否可以正确地从SDK中读取返回的数据,或者可以采用更好的方法来完成?
我在另一个线程中问了有关此SDK的问题,但是我显然太快了,无法将线程标记为已回答。 :/
SDK文档:
要获取指定虚拟服务器上所有当前可见的客户端的列表:
未签名的int ts3client_getClientList(serverConnectionHandlerID,result);
uint64 serverConnectionHandlerID;
anyID **结果;
参量
•serverConnectionHandlerID
请求其客户端列表的服务器连接处理程序的ID。
•结果
接收客户端ID的NULL终止数组的变量的地址。
除非发生错误,否则必须使用ts3client_freeMemory释放阵列。
成功返回ERROR_ok,否则返回public_errors.h中定义的错误代码。如果发生错误,则结果数组未初始化并且不能释放。
可以使用以下命令查询指定虚拟服务器上所有通道的列表:
未签名的int ts3client_getChannelList(serverConnectionHandlerID,result);
uint64 serverConnectionHandlerID;
uint64 **结果;
参量
•serverConnectionHandlerID
请求其频道列表的服务器连接处理程序的ID。
•结果
接收通道ID的NULL数组的变量的地址。除非发生错误,否则必须使用ts3client_freeMemory释放阵列。
成功返回ERROR_ok,否则返回public_errors.h中定义的错误代码。如果发生错误,则结果数组未初始化并且不能释放。
未签名的int ts3client_getCaptureDeviceList(modeID,result); const char * modeID; char ****结果;
参量
•modeID
定义要使用的播放/捕获模式。对于不同的模式,可能会有不同的设备列表。返回有效模式ts3client_getDefaultPlayBackMode / ts3client_getDefaultCaptureMode和ts3client_getPlaybackModeList / ts3client_getCaptureModeList。
•结果
接收以NULL结尾的数组{{char * deviceName,char * deviceID},{char * deviceName,char * deviceID},...,NULL}的变量的地址。
除非函数返回错误,否则需要使用ts3client_freeMemory释放数组的元素和数组本身。
成功返回ERROR_ok,否则返回public_errors.h中定义的错误代码。如果发生错误,则结果数组未初始化,并且不得释放。
可以列出可用于给定模式的播放和捕获设备,以及当前的操作系统默认设置。返回的设备值可用于初始化设备。
要查询默认的回放和捕获设备,请致电
要获取指定模式下所有可用的播放和捕获设备的列表,请致电
ts3client_getPlaybackDeviceList(modeID,result);
const char * modeID;
char ****结果;
未签名的int ts3client_getCaptureDeviceList(modeID,result);
const char * modeID;
char ****结果;
参量
•modeID
定义要使用的播放/捕获模式。对于不同的模式,可能会有不同的设备列表。有效模式由返回
ts3client_getDefaultPlayBackMode / s3client_getDefaultCaptureMode和ts3client_getPlaybackModeList / ts3client_getCaptureModeList。
•结果
接收以NULL结尾的数组{{char * deviceName,char * deviceID},{char * deviceName,char * deviceID},...,NULL}的变量的地址。
除非函数返回错误,否则需要使用ts3client_freeMemory释放数组的元素和数组本身。
成功返回ERROR_ok,否则返回public_errors.h中定义的错误代码。如果发生错误,则结果数组未初始化,并且不得释放。
未签名的int ts3client_startConnection(serverConnectionHandlerID,identity,ip,port,nickname,defaultChannelArray,defaultChannelPassword,serverPassword);
uint64 serverConnectionHandlerID; const char *身份; const
char * ip; unsigned int端口; const char *昵称; const char **
defaultChannelArray; //这很糟糕,我没有得到const char *
defaultChannelPassword; const char * serverPassword;
参量
•serverConnectionHandlerID
此服务器连接的唯一标识符。使用ts3client_spawnNewServerConnectionHandler创建
•身份
客户身份。必须通过调用ts3client_createIdentity创建此字符串。
请注意,应用程序仅应创建一次身份,将字符串存储在本地,然后将其重新用于以后的连接。
•ip
TeamSpeak 3服务器的主机名或IP。
如果您传递的是主机名而不是IP,则客户端库将尝试将其解析为IP,但是在解析过程中,该功能可能会阻塞异常长的时间。如果您依赖该函数快速返回,建议您自己解析主机名(例如异步解析),然后使用IP而不是主机名调用ts3client_startConnection。
• 港口
TeamSpeak 3服务器的UDP端口,默认情况下为9987。TeamSpeak 3使用UDP。将来可能会添加对TCP的支持。
•昵称
登录时,客户端尝试在连接的服务器上使用此昵称。请注意,这不一定是实际分配的昵称,因为服务器可以修改昵称(“ gandalf_1”而不是请求的“ gandalf”)或拒绝被阻止的名称。
•defaultChannelArray
字符串数组,用于定义TeamSpeak 3服务器上通道的路径。如果通道存在并且用户具有足够的权限并根据需要提供正确的密码,则该通道将在登录时加入。
要定义到任意级别的子通道的路径,请创建一个通道名称数组,详细说明默认通道的位置(例如“祖父母”,“父母”,“ mydefault”,“”)。该数组以空字符串终止。
传递NULL以加入服务器的默认通道。
•defaultChannelPassword
默认频道的密码。如果不需要密码或未指定默认通道,则传递一个空字符串。
• 服务器密码
服务器的密码。如果服务器不需要密码,则传递一个空字符串。
所有字符串都需要以UTF-8格式编码
重要
返回C字符串或数组的客户端库函数动态分配内存,调用者必须使用ts3client_freeMemory释放这些内存。重要的是仅在函数返回ERROR_ok的情况下才访问和释放内存。
如果函数返回错误,则结果变量未初始化,因此可以释放或访问它
可能会使应用程序崩溃。
有关其他说明和示例,请参见“调用客户端库函数”一节。
可以使用以下命令查询特定错误代码的可打印错误字符串:
未签名的ts3client_getErrorMessage(errorCode,error);
unsigned int errorCode;
char **错误;
参量
• 错误代码
从所有客户端库函数返回的错误代码。
•错误
接收错误消息字符串的变量的地址,该字符串以UTF-8格式编码。除非函数的返回值不是ERROR_ok,否则应使用ts3client_freeMemory释放该字符串。
例:
unsigned int error;
anyID myID;
error = ts3client_getClientID(scHandlerID, &myID); /* Calling some Client Lib function */
if(error != ERROR_ok) {
char* errorMsg;
if(ts3client_getErrorMessage(error, &errorMsg) == ERROR_ok)
{ /* Query printable error */
printf("Error querying client ID: %s\n", errorMsg);
ts3client_freeMemory(errorMsg); /* Release memory */
}
}
type
PPanyID = ^PAnyID;
PanyID = ^anyID;
anyID = word;
var
error: longword;
errormsg: PAnsiChar;
procedure TfrmMain.RequestOnlineClients;
var
ids : PanyID;
pids : PanyID;
aid : anyID;
begin
error := ts3client_getClientList(FTSServerHandlerID, @ids);
if (error <> ERROR_ok) then
begin
if (ts3client_getErrorMessage(error, @errormsg) = ERROR_ok) then
begin
LogMsg(Format('Error requesting online clients: %s', [errormsg]));
ts3client_freeMemory(errormsg);
end;
end else
begin
pids := ids;
while (pids^ <> 0) do
begin
aid := pids^;
LogMsg(format('userid %u',[aid, getUserNickNameById(aid)]));
inc(pids);
end;
ts3client_freeMemory(@pids^); // here's potiential problem
end;
end;
procedure TfrmMain.RequestChannels;
var
ids : PUint64;
pids : PUint64;
aid : uint64;
channelname : PAnsiChar;
begin
error := ts3client_getChannelList(FTSServerHandlerID, @ids);
if (error <> ERROR_ok) then
begin
if (ts3client_getErrorMessage(error, @errormsg) = ERROR_ok) then
begin
LogMsg(Format('Error requesting channels: %s', [errormsg]));
ts3client_freeMemory(errormsg);
end;
end else
begin
pids := ids;
while (pids^ <> 0) do
begin
aid := pids^;
LogMsg(format('channelid %u %s',[aid, getChannelNameById(aid)]));
inc(pids);
end;
ts3client_freeMemory(@pids^);
end;
end;
**// Added details 25-11-2014**
char* defaultMode;
if(ts3client_getDefaultPlayBackMode(&defaultMode) == ERROR_ok) {
char*** array;
if(ts3client_getPlaybackDeviceList(defaultMode, &array) == ERROR_ok) {
for(int i=0; array[i] != NULL; ++i) {
printf("Playback device name: %s\n", array[i][0]); /* First element: Device name */
printf("Playback device ID: %s\n", array[i][1]); /* Second element: Device ID */
/* Free element */
ts3client_freeMemory(array[i][0]);
ts3client_freeMemory(array[i][1]);
ts3client_freeMemory(array[i]);
}
ts3client_freeMemory(array); /* Free complete array */
} else {
printf("Error getting playback device list\n");
}
} else {
printf("Error getting default playback mode\n");
}
Example to query all available playback devices:
char* defaultMode;
if(ts3client_getDefaultPlayBackMode(&defaultMode) == ERROR_ok) {
char*** array;
if(ts3client_getPlaybackDeviceList(defaultMode, &array) == ERROR_ok) {
for(int i=0; array[i] != NULL; ++i) {
printf("Playback device name: %s\n", array[i][0]); /* First element: Device name */
printf("Playback device ID: %s\n", array[i][1]); /* Second element: Device ID */
/* Free element */
ts3client_freeMemory(array[i][0]);
ts3client_freeMemory(array[i][1]);
ts3client_freeMemory(array[i]);
}
ts3client_freeMemory(array); /* Free complete array */
} else {
printf("Error getting playback device list\n");
}
} else {
printf("Error getting default playback mode\n");
}
procedure TfrmMain.ConnectServer2;
var
version : PAnsiChar;
DefaultChannelsArr : PPAnsiChar;
begin
if Connected then Exit;
if not ClientInitialized then
InitializeClient;
// Dbl Check if we can connect
if ClientInitialized then
try
// Connect to server on localhost:9987 with nickname "client", no default channel, no default channel password and server password "secret"
// error := ts3client_startConnection(FTSServerHandlerID, identity, '127.0.0.1', 9987, 'Delphi Client', nil, '', 'secret'); // example connection setup
ts3check(ts3client_startConnection(FTSServerHandlerID, PAnsiChar(FSetup.ClientIdentity), PAnsiChar(FSetup.ServerAddress), FSetup.FServerPort, PAnsiChar(FSetup.NickName), nil, '', PAnsiChar(FSetup.ServerPassword)));
{ TODO -oMe -cImportant : Need to check how to convert ansistrings to UTF8 } // UnicodeToUtf8() // AnsiToUtf8()...
// Query and print client lib version
ts3check(ts3client_getClientLibVersion(@version));
LogMsg(Format('Client lib version: %s', [version]));
ts3client_freeMemory(version); // Release dynamically allocated memory
// Do not set connected here, wait for the callback connected state
except
on e: exception do
begin
UnInitializeClient; // clear the hole thing and start over
LogMsg(Format('Error connecting: %s',[e.Message]));
end;
end;
end;
最佳答案
我会这样翻译ts3client_getClientList
:
function ts3client_getClientList(serverConnectionHandlerID: UInt64;
out result: PAnyID): Cardinal; cdecl; external '...';
out
参数比双指针要好。它使意图更清晰。
var
ids: PAnyID;
idarr: TArray<anyID>;
....
ts3check(ts3client_getClientList(serverConnectionHandlerID, ids));
try
idarr := GetIDs(ids);
finally
ts3check(ts3client_freeMemory(ids));
end;
ts3check
是一个函数,如果传递了
ERROR_ok
以外的返回值,则会引发异常。
function ts3client_getErrorMessage(error: Cardinal;
out errormsg: PAnsiChar): Cardinal; cdecl; external '...';
....
procedure ts3check(error: Cardinal);
var
errormsg: PAnsiChar;
errorstr: string;
begin
if error = ERROR_ok then
exit;
if ts3client_getErrorMessage(error, @errormsg) <> ERROR_ok then
raise Ets3Error.CreateFmt('Error code %d', [error]);
errorstr := UTF8ToUnicodeString(errormsg);
ts3client_freeMemory(errormsg);
raise Ets3Error.CreateFmt('Error code %d (%s)', [error, errorstr]);
end;
GetIDs
:
function GetIDs(const ids: PAnyID): TArray<anyID>;
var
Count: Integer;
p: PAnyID;
begin
Count := 0;
p := ids;
while p^ <> 0 do
begin
inc(Count);
inc(p);
end;
SetLength(Result, Count);
Count := 0;
p := ids;
while p^ <> 0 do
begin
Result[Count] := p^;
inc(Count);
inc(p);
end;
end;
ts3client_getErrorMessage
的调用将使更高级的代码更易于阅读。使用诸如
OleCheck
和
Win32Check
之类的东西作为灵感。
关于delphi - Delphi和使用Teamspeak SDK,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27105743/
请在标记为重复之前阅读。 我正在创建一组依赖智能卡进行身份验证的应用程序。到目前为止,每个应用程序都单独控制智能卡读卡器。几周后,我的一些客户将同时使用多个应用程序。因此,我认为创建一个控制身份验证过
我想设置一个小程序,从数据库中检索信息,然后根据请求将该信息分发给另一个程序。例如,一个名为“Master”的程序将从数据库中检索数据并创建一个对象集合(列表、数组等,无论哪种效果最好),然后一个名为
我有两台电脑,都装有 XE2。我以为我在两者上安装了相同的安装,但在其中一个上安装第 3 方软件包时遇到问题,而另一个则正常。 无论如何,我希望两者都一样。最简单的人可能只是通过移入我的 Dropbo
有冲突吗? 最佳答案 所有新版本的 Delphi 始终可以安全地安装到旧版本的下一个版本。 每个新版本都应安装在其自己的目录中。 如果您要安装多个版本,请始终先安装最旧的版本,然后再安装最新版本。 我
快速提问:如果我从代码中删除 // 或 (* *) 中的注释,Delphi 2007 的执行时间会受到影响吗?最终结果是一个可能包含数千行注释的 EXE 文件。 最佳答案 编译器会简单地忽略注释,并且
我必须对照另一个文件检查文件的每一行。 如果第二个文件中存在第一个文件中的一行,则必须删除它。 现在,我正在使用2个列表框,并且“对于listbox1.items.count-1可以开始...” 我的
我正在尝试在访问数据库中添加一些数据。但是我有麻烦,因为这会返回错误: ADOQuery1 missing sql property 实现了对代码的几次修改,到目前为止没有任何效果。 我究竟做错了什么
我用Delphi 5编写了一个程序,在Windows 8 32位PC上可以正常运行。我发现在Windows 7 64位笔记本电脑上运行它最终会导致reallocmem错误,而该错误在32位PC上不会发
看来这是我需要的工具,用于提取XML并与TClientDataset连接。我已经在几篇文章和文档中看到了它,但是我无法在XE2组件列表中找到它-在任何地方!应该在哪里?是否在可能未安装的可选软件包中?
我正在寻找一个非常通用的TDBTree组件,我想听听一些建议。我正在特别寻找一种显示主记录和“ n”个链接表记录的记录。 (我的意思是来自各个表的记录)。例如,TDBTree将钩接到主表,明细表1,附
我需要将按钮制作成旋转三角形的形状(或者说是任何多边形)。谁能提供任何建议? 最佳答案 查看Win32 API CreatePolygonRgn()和SetWindowRgn()函数,以创建一个HRG
你好专家 我的JvPasswordForm1有一个旧的JVC组件。 似乎该组件不再存在:它替换为哪个组件? 重新获得 最佳答案 尝试查找TJvLoginDialog,TjvPassword已合并到其中
几天前,我已经设置了我的开发环境(在装有Win 7的VM和域上的用户的VM上安装了delphi 2009),并安装了我的组件(jedi's,devExpress,ADS等)。 今天,我启动机器,打开d
开始对控件进行子分类的正确位置/时间是什么? 恢复原始窗口proc的正确时间是几点? 现在我在表单创建过程中子类化: procedure TForm1.FormCreate(Sender: TObje
有人可以给我一些有关如何登录访问的网页(使用任何网络浏览器)的指示吗?我应该建立一个全球代理....钩住网络....吗?我需要记录的只是页面地址,而不是其中包含的信息。 我正在使用Delphi。 谢谢
我创建了一个像 TMyClass = class(TObject) private FList1: TObjectList; FList2: TObjectList; public end;
我有一个BPG文件,我已对其进行修改以用作我们公司的自动构建服务器的make文件。为了使其正常工作,我必须进行更改 用途*用途 'unit1.pas'中的unit1 * unit1 'unit2.pa
我将Delphi 7代码迁移到了Delphi XE4。我在Delphi XE4的LoadFromStram方法中遇到错误,但对于Delphi 7来说也可以正常工作。 错误: First chance
我正在尝试学习一些新技巧,以便更好地组织我在 Delphi 中的单元中的一些源代码。 我注意到我访问的一些函数或方法似乎是类中的类,但是我还没有成功地在类中创建一个工作类,虽然它编译得很好,但在执行代
我有一个包含许多类的大单元,现在我想通过将某些类分成新的单元来重构该单元。 我不得不承认我缺乏使用Delphi内置IDE功能的经验。利用内置功能“查找|查找对类型的本地引用”并没有多大帮助,因为类方法
我是一名优秀的程序员,十分优秀!