gpt4 book ai didi

delphi - Delphi和使用Teamspeak SDK

转载 作者:行者123 更新时间:2023-12-03 15:58:07 27 4
gpt4 key购买 nike

我试图将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;


现在,我不认为您真的想要一个ID数组。您可能很乐意直接处理ID。我不想进入该怎么做,因为那样会使我进入您看不见的代码。您不会像我之前那样完全编写代码,但是希望可以将以上内容用作想法的来源。

所有这些的主要目的是尝试封装尽可能多的混乱的样板代码。包装对 ts3client_getErrorMessage的调用将使更高级的代码更易于阅读。使用诸如 OleCheckWin32Check之类的东西作为灵感。

我要指出的一点是,将这些代码放在表单中感觉不对。通常,将此类代码从您的UI中删除更为干净。对该库进行包装,以供您的UI代码使用。将包装纸放在专用的包装盒中,以免隐藏粗糙的细节。

关于delphi - Delphi和使用Teamspeak SDK,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27105743/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com