用delphi开发Serv-U插件

2024-02-27 03:38
文章标签 开发 插件 delphi serv

本文主要是介绍用delphi开发Serv-U插件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

花了一下午,邊看說明 邊學著寫 Serv-U插件,本來都快完成了,誰知道因為INI裡的設定寫錯了,老是有個地方通不過,只好 Serv-U的主頁去找例子,一找就找到了一個Delphi 4寫的例子,因為是99年的,所以我根據說明 把新增的常量加上去,這下就比較完美了

我就簡單的介紹一下 Serv-U插件機制吧:

Serv-U的說明 裡在Extending Serv-U中詳細地介紹了 插件,用途主要有

可以使用外部資料庫來檢驗用戶帳號信息和文件存取權限
可以新增自訂的事件日誌
增加自訂的指令
等等等等

Serv-U插件分兩種,一種是用戶存取校驗DLL,事件監視DLL

只需要在ServUDaemon.ini中增加:
[EXTERNAL]
EventHookDLL1=WULOG.DLL
EventHookDLL2=myPlugin.DLL
ClientCheckDLL1=CHKNOVELL.DLL
ClientCheckDLL2=myPlugin.DLL

這樣就把DLL註冊到 Serv-U中,如果沒有成功的話,可以在ServUStartUpLog.txt看到「找不到入口」的信息

事件監視DLL是通過回調(Callback)函數來獲得信息(存放在一個Record中)

有了這個例子,您可以很容易的寫出自己的Plugin,為 Serv-U賦予更強大的功能,比如禁止用戶上傳某些文件等等

附件的使用方法,您可以在ServUDaemon.ini中增加:
[EXTERNAL]
ClientCheckDLL1=SUExampl.DLL
EventHookDLL1=SUExampl.DLL

插件會自動記錄事件到C:/FTPLOG.TXT中

readme.txt
===========================================
his is an example of an FTP Serv-U DLL for event notification
AND client access verification, written for Borland's Delphi 4.

Please read the comments in the source code for additional
information.

If you have any comments or spot any bugs, please let me know
(contact information is listed at the end of this document).

Hope this helps!

- Bill Sorensen


Installation:

After building the project, copy the DLL to your Serv-U directory.
Add the following to your SERV-U.INI:

[EXTERNAL]
ClientCheckDLL1=SUExampl.DLL
EventHookDLL1=SUExampl.DLL


Legalese:

The source code is copyright (c) 1999 ASI/EDI Inc. All rights reserved.
It may be distributed for educational purposes so long as this text
file is included in the distribution. Derivative works may be created
from it, but must contain a valid ASI/EDI copyright notice, such as
"portions of this application contain copyrighted (c) material of
ASI/EDI Inc."

ASI/EDI Inc. and the author expressly disclaim any warranty,
express or implied, for this code and documentation.
Use it at your own risk.

FTP Serv-U is copyright (c) 1995-1998 Cat Soft.
ASI/EDI is not affiliated with Cat Soft, and Cat Soft is not
responsible for errors in or support of this source code.

No infringement on trademarks is intended.


The Author:

Written by Bill Sorensen (tzimisce@mwaccess.net - soon to change -
see www.Will.brinet.net for updated email information).

Information on ASI/EDI is available at: www.asiedi.com

[September 21, 1999]
SUEvents.pas

(*
Description : FTP server event handlers.

Copyright (c) 1999 ASI/EDI, Inc. All rights reserved.
WES 08/19/99 Initial Version
*)

unit SUEvents;

interface

uses
Windows, SysUtils, ServUEvt, ServUCli;

procedure OnConnection(const EventStruc: TRFTPEventStr);
// Fires before OnVerifyPassword.

procedure OnConnectionClose(const EventStruc: TRFTPEventStr);
// Called from HandleEventHook, as HandleClientEvent client disconnect
// doesn't fire if server was dropped!

procedure OnUploadSuccess(const EventStruc: TRFTPEventStr);

procedure OnDownloadSuccess(const EventStruc: TRFTPEventStr);

procedure OnTransferFailure(const EventStruc: TRFTPEventStr);

function OnRequestHomeDir(var ClientEventStruc: TRClientEventStr): LongBool;
// Fires after OnVerifyPassword.
// Note - does NOT fire if home dir present in Serv-U user setup!

function OnVerifyPassword(var ClientEventStruc: TRClientEventStr): LongBool;
// Note - does NOT fire after VALID password entered
// based on setup in Serv-U!

implementation

uses
SULog;

procedure OnConnection(const EventStruc: TRFTPEventStr);
begin
LogIt('Client connected');

// Your code here.
end;

procedure OnConnectionClose(const EventStruc: TRFTPEventStr);
begin
LogIt('Connection closed');

// Your code here.
end;

procedure OnUploadSuccess(const EventStruc: TRFTPEventStr);
var
sUploadedFile : String;
begin
sUploadedFile := EventStruc.AuxOne;

LogIt(Format('File %s uploaded successfully',[sUploadedFile]));

// Your code here.
end;

procedure OnDownloadSuccess(const EventStruc: TRFTPEventStr);
var
sFileFullPath : String;
begin
sFileFullPath := EventStruc.AuxOne;

LogIt(Format('File %s downloaded successfully',[sFileFullPath]));

// Your code here.
end;

procedure OnTransferFailure(const EventStruc: TRFTPEventStr);
var
sUploadOrDownload : String;
sFileName : String;
sTransferMode : String;
sError : String;
begin
if EventStruc.Event = EVNT_AbortUp then
sUploadOrDownload := 'upload'
else
sUploadOrDownload := 'download';

// Note that I'm stripping out the path here
// to make the error message more legible.
// If we wanted to delete the file, it's easiest to let Serv-U do it.

sFileName := ExtractFileName(EventStruc.AuxOne);
sTransferMode := EventStruc.AuxTwo;

case EventStruc.SubEvent of
SEVNT_None : sError := 'no error specified';
SEVNT_ErrWrite : sError := 'error writing to disk';
SEVNT_ErrRead : sError := 'error reading from disk';
SEVNT_ErrQuota : sError := 'insufficient disk quota';
SEVNT_ErrTOut : sError := 'packet timed out';
SEVNT_ErrAbort : sError := 'user abort';
SEVNT_ErrUnknown : sError := 'unknown error';
SEVNT_ErrClose : sError := 'connection closed';
else
sError := '????';
end; { case }

LogIt(Format('Failed %s (%s) - file %s, mode %s',
[sUploadOrDownload,sError,sFileName,sTransferMode]));

// Your error logging (or whatever) code here.

end;

function OnRequestHomeDir(var ClientEventStruc: TRClientEventStr): LongBool;
var
sHomeDirFullPath : String;
begin
sHomeDirFullPath := 'C:/TEMP'; // Database lookup, whatever - your code here.

StrCopy(ClientEventStruc.Aux,PChar(sHomeDirFullPath));

ClientEventStruc.Flag := FLAG_FOUND_HOMEDIR;

Result := CLIENT_EVENT_HANDLED;
end;

function OnVerifyPassword(var ClientEventStruc: TRClientEventStr): LongBool;
var
sEnteredPassword : String;
sCorrectCaseUser : String;
bOkToLogin : Boolean;
begin
Result := CLIENT_EVENT_NOT_HANDLED;

sEnteredPassword := ClientEventStruc.Aux;

// OnVerifyPassword is generally called twice - once after username is
// entered but before password is entered (blank password), then
// again when password is actually entered. Serv-U won't let 'em
// in with a blank password (if it's set up correctly), so this is safe.

if Length(sEnteredPassword) > 0 then
begin
// Note that User is uppercased, and we may want the case-sensitive
// login name.
// This is available in Aux following the password and a null byte.
// NOTE - if no username was entered, sCorrectCaseUser will be '(none)'.

sCorrectCaseUser :=
PChar(@ClientEventStruc.Aux[StrLen(ClientEventStruc.Aux) + 1]);

LogIt(Format('User: %s Password: %s',
[sCorrectCaseUser,sEnteredPassword]));

bOkToLogin := True; // Database lookup, whatever - your code here.

if bOkToLogin then
ClientEventStruc.Flag := FLAG_ALLOW_LOGIN
else
ClientEventStruc.Flag := FLAG_DENY_LOGIN;

Result := CLIENT_EVENT_HANDLED;
end; { if }
end;

end.

ServUEvt.pas:
=========================================

(*
Description : Serv-U FTP Server (v2.5a, 32-bit) DLL includes/defines
for event notification and hooking.

Copyright (c) 1999 ASI/EDI, Inc. All rights reserved.
WES 07/15/99 Initial Version
*)

unit ServUEvt;

interface

uses
Windows;

type
// HandleEventHook parameter

TPRFTPEventStr = ^TRFTPEventStr;

// Event notification structure

TRFTPEventStr = record
// event info
Event: DWORD; // event code
SubEvent: DWORD; // sub-event code
// user info
SessionID: DWORD; // unique ID of the FTP session
User: Array[0..40-1] of Char; // user name
ClientIP: Array[0..16-1] of Char; // IP address of client
DomainIP: Array[0..16-1] of Char; // server IP address the client connected to
// event attributes
Duration: DWORD; // duration of events (in seconds)
Size: DWORD; // size of object (i.e. file)
// hook info
hWindow: HWND; // window handle to post decision to
Message: UINT; // message to post
pReplyText: PChar; // pointer to text to send to user
// scratch pad area
AuxOne: Array[0..512-1] of Char; // auxiliary area one
AuxTwo: Array[0..512-1] of Char; // auxiliary area two
// domain info
DomainPort: DWORD; // server port the client connected to
DomainID: DWORD; // unique ID for the domain the client connected to
// more size info
HiSize: DWORD; // high 32 bits of size info (full size is 64 bit value)
end; { record RFTPEventStr }

const
// HandleEventHook return codes
REVNT_None = 0; // nothing
REVNT_Proceed = 1; // let event pass
REVNT_Abort = 2; // stop event
REVNT_Suspend = 3; // suspend event until decision is made

// Serv-U notification event codes
EVNT_None = 0; // none
EVNT_IPName = 1; // symbolic IP name available
EVNT_Connect = 2; // connection was made
EVNT_Close = 3; // closed connection
EVNT_BouncedIP = 4; // bounced client because of IP address
EVNT_TooMany = 5; // bounced user because there are too many
EVNT_WrongPass = 6; // too many times wrong password
EVNT_TimeOut = 7; // connection timed out
EVNT_Login = 8; // user logged in
EVNT_StartUp = 9; // start upload of file
EVNT_EndUp = 10; // successful upload of file
EVNT_StartDown = 11; // start of download of file
EVNT_EndDown = 12; // successful download of file
EVNT_AbortUp = 13; // aborted upload
EVNT_AbortDown = 14; // aborted download
EVNT_Rename = 15; // renamed file/dir
EVNT_DelFile = 16; // deleted file
EVNT_DelDir = 17; // deleted dir
EVNT_ChgDir = 18; // changed working directory
EVNT_MakeDir = 19; // created directory
EVNT_ProgUp = 20; // progress of upload
EVNT_ProgDown = 21; // progress of download
EVNT_Maintenance = 22;// user switching to maintenance mode

// Serv-U hook event codes
EVNT_HookDown = 100; // hook for file downloads
EVNT_HookUp = 101; // hook for file uploads
EVNT_HookAppend = 102; // hook for append file upload
EVNT_HookUnique = 103; // hook for unique name upload
EVNT_HookRename = 104; // hook for rename file/dir
EVNT_HookDelFile = 105; // hook for delete file
EVNT_HookDelDir = 106; // hook for delete dir
EVNT_HookMkd = 107; // hook for make directory
EVNT_HookSite = 108; // hook for the SITE command
EVNT_HookChgDir = 109; // hook for change dir command
EVNT_HookCommand = 110; // hook for raw FTP command
EVNT_HookReply = 111; // hook for raw FTP reply

// Serv-U sub-event codes
SEVNT_None = 0; // no sub-event
SEVNT_ErrWrite = 1; // problem writing to disk
SEVNT_ErrRead = 2; // problem reading from disk
SEVNT_ErrQuota = 3; // insufficient disk quota
SEVNT_ErrTOut = 4; // packet timed out
SEVNT_ErrAbort = 5; // user aborted transfer
SEVNT_ErrUnknown = 6; // unknown error
SEVNT_ErrClose = 7; // data connection closed unexpectedly
SEVNT_System = 8; // switching to SYSTEM maintenance mode
SEVNT_Group = 9; // switching to GROUP maintenance mode
SEVNT_Domain =10; // switching to DOMAIN maintenance mode
SEVNT_ReadOnly =11; // user switching to READ-ONLY maintenance mode

implementation

end.


ServUCli.pas:
=========================================

(*
Description : Serv-U FTP Server (v4.1, 32-bit) DLL includes/defines
for client access verification.

Copyright (c) 1999 ASI/EDI, Inc. All rights reserved.
Copyright (c) 2003 Icebird
WES 08/03/99 Initial Version
*)

unit ServUCli;

interface

uses
Windows;

type
// HandleClientEvent parameter

TPRClientEventStr = ^TRClientEventStr;

// Client event structure

TRClientEventStr = record
Event : DWORD; // event code
Flag : DWORD; // meaning of flag depends on event
User : Array[0..40-1] of Char; // user name
Aux : Array[0..512-1] of Char; // auxiliary area, depends on event
HostIP : Array[0..16-1] of Char; // server IP home
SessionID : DWORD; // unique ID of the FTP session
DomainID: DWORD; // unique ID for the domain the client connected to
DomainPort: DWORD; // server domain port number the client connected to
end; { record TRClientEventStr }

const
// Return values for HandleClientEvent
CLIENT_EVENT_HANDLED : LongBool = True;
CLIENT_EVENT_NOT_HANDLED : LongBool = False;

// Flag values in TRClientEventStr for SRVU_Password event
FLAG_ALLOW_LOGIN : DWORD = 1;
FLAG_DENY_LOGIN : DWORD = 0;

// Flag values in TRClientEventStr for SRVU_HomeDir event
FLAG_FOUND_HOMEDIR : DWORD = 1;
FLAG_NO_HOMEDIR : DWORD = 0;

// Serv-U client event codes
SRVU_LoginMesFile = 1; // get login message file
SRVU_HomeDir = 2; // get home dir
SRVU_Password = 3; // verify password
SRVU_IPAccess = 4; // verify IP access
SRVU_WriteFile = 5; // verify write access
SRVU_ReadFile = 6; // verify read access
SRVU_ModifyFile = 7; // verify mod./del. file access
SRVU_ExecProg = 8; // verify execute access
SRVU_ListDir = 9; // verify dir listing access
SRVU_ChangeDir = 10; // verify dir change access
SRVU_DeleteDir = 11; // verify dir delete access
SRVU_CreateDir = 12; // verify dir create access
SRVU_HideHidden = 13; // get setting for 'hide hidden files'
SRVU_RelPaths = 14; // get setting for 'relative paths'
SRVU_RatioType = 15; // get setting for type of ratios
SRVU_RatioDown = 16; // get setting for download ratio
SRVU_RatioUp = 17; // get setting for upload ratio
SRVU_RatioCredit = 18; // get/adjust ratio credit setting
SRVU_RatioFree = 19; // verify if file is free for ratios
SRVU_QuotaEnable = 20; // verify if disk quota is enabled
SRVU_QuotaChange = 21; // change in disk quota
SRVU_QuotaMax = 22; // maximum disk quota
SRVU_AlwaysLogin = 23; // always allow login
SRVU_OneLoginPerIP = 24; // allow one login per user/IP pair
SRVU_LogClientIP = 25; // log client from this IP address
SRVU_SpeedLimit = 26; // maximum transfer speed
SRVU_PassChange = 27; // change user's password
SRVU_TimeOut = 28; // get user time-out value
SRVU_MaxUsers = 29; // max. no. of users for account
SRVU_PassChallenge = 30; // get password challenge if needed
SRVU_Connect = 31; // information only: client connected
SRVU_Close = 32; // information only: client disconnected
SRVU_MaxLoginPerIP = 33; // max. no. of logins from same IP for user
SRVU_VerifyPasswd = 34; // verify old password before changing it
SRVU_AppendFile = 35; // verify append file access
SRVU_SignOnMes = 36; // get signon message file
SRVU_SignOffMes = 37; // get signoff message file
SRVU_Maintenance = 38; // switch to maintenance mode
SRVU_SessionTimeOut= 39; // session time-out

implementation

end.



SUMain.pas:
========================================
(*
Description : Main module of a Serv-U FTP Server (v2.5a, 32-bit) DLL
for event notification AND client access verification.
Tested under Delphi 4, update pack 3.

Notes : IMPORTANT - Avoid displaying dialogs or any other windows!
These can cause reentrancy in the DLL (due to message
dispatching)!

For this example, I'm assuming you have a C:/TEMP directory.

I'm not handling directory rights here. It's easiest
to set up a default user in Serv-U with appropriate rights
to the parent directory of the users' directories, then
inherit rights to sub-dirs. Be sure to turn on
"Show path relative to homedir" in Serv-U.

Use SessionID to keep track of state, if necessary.

Copyright (c) 1999 ASI/EDI, Inc. All rights reserved.
WES 07/15/99 Initial Version
*)

unit SUMain;

interface

uses
Windows, SysUtils, ServUEvt, ServUCli;

procedure InitializeLibrary;
// Executed when DLL is loaded.

procedure ExitingLibrary;
// Executed when DLL is unloaded (actually, detached from calling process).

procedure LibraryProc(iReason: Integer);
// Internal. Equivalent to DLLEntryPoint.

function HandleEventHook(pEventStruc: TPRFTPEventStr): Word; stdcall;
// Exported callback function - note that CALLBACK is defined as stdcall
// in C's windef.h.

function HandleClientEvent(pEventStruc: TPRClientEventStr): LongBool; cdecl;
// Exported function.

procedure LogErrorMessage(const sErrorMessage: String);
// Beeps and logs error message.

implementation

uses
SUEvents, SULog;

procedure InitializeLibrary;
begin
DLLProc := @LibraryProc; // ensures that ExitingLibrary will be called

try { except }

InitializeLog;

LogIt('FTP server started');

// Your initialization code would go here.

except
on E: Exception do
LogErrorMessage(E.Message);
end; { try..except }
end;

procedure ExitingLibrary;
begin
try { except }

LogIt('FTP server shutdown');

// Your cleanup code would go here.

except
on E: Exception do
LogErrorMessage(E.Message);
end; { try..except }
end;

procedure LibraryProc(iReason: Integer);
begin
if iReason = DLL_PROCESS_DETACH then
ExitingLibrary;
end;

function HandleEventHook(pEventStruc: TPRFTPEventStr): Word;
begin
Result := REVNT_None;

try { except }
case pEventStruc^.Event of
EVNT_Connect : OnConnection(pEventStruc^);
EVNT_Close : OnConnectionClose(pEventStruc^);
EVNT_EndUp : OnUploadSuccess(pEventStruc^);
EVNT_EndDown : OnDownloadSuccess(pEventStruc^);
EVNT_AbortUp,
EVNT_AbortDown : OnTransferFailure(pEventStruc^);
// no else
end; { case }
except
on E: Exception do
LogErrorMessage(E.Message);
end; { try..except }
end;

function HandleClientEvent(pEventStruc: TPRClientEventStr): LongBool;
begin
Result := CLIENT_EVENT_NOT_HANDLED;

try { except }
case pEventStruc^.Event of
SRVU_HomeDir : Result := OnRequestHomeDir(pEventStruc^);
SRVU_Password : Result := OnVerifyPassword(pEventStruc^);
// no else
end; { case }
except
on E: Exception do
LogErrorMessage(E.Message);
end; { try..except }
end;

procedure LogErrorMessage(const sErrorMessage: String);
begin
try { except }
MessageBeep(MB_ICONEXCLAMATION); // Make this play a loud WAV file.

LogIt('ERROR: ' + sErrorMessage);
except
// No exceptions allowed here.
end; { try..except }
end;

end.




SULog.pas:
===========================================
(*
Description : Debugging/logging routines.

Copyright (c) 1999 ASI/EDI, Inc. All rights reserved.
WES 12/30/98 Initial Version
*)

unit SULog;

interface

const
FILENAME_LOG = 'C:/FTPLOG.TXT';

procedure InitializeLog;
// Erases FILENAME_LOG if it exists.

procedure LogIt(const sLogText: String);
// Calls LogToFile for FILENAME_LOG.

procedure LogToFile(const sLogText: String; sFileName: String);
// Writes a string plus carriage-return+linefeed to a text file.
// File is appended to if it existed, created otherwise.
// Buffer is flushed and file is closed before function returns.
// Exception raised on error.

implementation

uses
SysUtils;

procedure InitializeLog;
begin
if FileExists(FILENAME_LOG) then
DeleteFile(FILENAME_LOG);

end;

procedure LogIt(const sLogText: String);
begin
LogToFile(sLogText,FILENAME_LOG);
end;

procedure LogToFile(const sLogText: String; sFileName: String);
var
F : TextFile;
begin
sFileName := SysUtils.Trim(sFileName);

if sFileName = '' then
raise EInOutError.Create('Blank file name passed to LogToFile');

AssignFile(F,sFileName);

if FileExists(sFileName) then
Append(F)
else
Rewrite(F);

// Yes, the Append/Rewrite should be outside the try block.

try { finally }
Writeln(F,sLogText);
Flush(F); // just in case
finally
CloseFile(F);
end; { try..finally }
end;

end.



SUExampl.dpr:
============================================
library SUExampl;

{$IMAGEBASE $44FA0000}

uses
SysUtils,
SUMain in 'SUMain.pas',
ServUEvt in 'ServUEvt.pas',
ServUCli in 'ServUCli.pas',
SUEvents in 'SUEvents.pas',
SULog in 'SULog.pas';

exports
HandleEventHook, HandleClientEvent;

begin
InitializeLibrary;
end.

这篇关于用delphi开发Serv-U插件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/751095

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

RabbitMQ 延时队列插件安装与使用示例详解(基于 Delayed Message Plugin)

《RabbitMQ延时队列插件安装与使用示例详解(基于DelayedMessagePlugin)》本文详解RabbitMQ通过安装rabbitmq_delayed_message_exchan... 目录 一、什么是 RabbitMQ 延时队列? 二、安装前准备✅ RabbitMQ 环境要求 三、安装延时队

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块

Java 与 LibreOffice 集成开发指南(环境搭建及代码示例)

《Java与LibreOffice集成开发指南(环境搭建及代码示例)》本文介绍Java与LibreOffice的集成方法,涵盖环境配置、API调用、文档转换、UNO桥接及REST接口等技术,提供... 目录1. 引言2. 环境搭建2.1 安装 LibreOffice2.2 配置 Java 开发环境2.3 配

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3