在typescript浏览器端中调用C++编写的函数,WebAssembly传递指针类型的参数,以及处理指针类型的返回值。

首先要在Cmake工程中的cmakelists.txt文件中引入Emscripten工具链:

set(CMAKE_TOOLCHAIN_FILE "D:/CppPkg/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")

直接看C++代码:

#include <emscripten/emscripten.h>
#include <cstdlib>


extern "C" {
   
   
	struct DataResult {
   
   
		double* dArr;
		int propCount;
	};

	EMSCRIPTEN_KEEPALIVE
	double sumArray(double* fArr, int arrLen) {
   
   
		double sum = 0.0;
		for (int i = 0; i < arrLen; i++) {
   
   
			sum += fArr[i];
		}
		return sum;
	}
	EMSCRIPTEN_KEEPALIVE
	double* vectorSum(double* vectorA, double* vectorB, int vecLen) {
   
   
		double* resArr = (double*)malloc(vecLen * sizeof(double));
		for (int i = 0; i < vecLen; i++) {
   
   
			resArr[i] = vectorA[i] + vectorB[i];
		}
		return resArr;
	}
	EMSCRIPTEN_KEEPALIVE
	DataResult* createDataResult(double* dArr, int propCount) {
   
   
		DataResult* dtRes = (DataResult*)malloc(sizeof(DataResult));
		dtRes->dArr = dArr;
		dtRes->propCount = propCount;
		return<
<think> 我们正在讨论的是在虚幻引擎(UE)中使用TypeScript调用C语言声明的有返回值函数的方法。注意,UE本身主要使用C++进行开发,但问题中提到了C语言。在UE中,通常是通过C++来与引擎交互,而C代码可以通过C++进行封装。另外,TypeScript在UE中并不是官方支持的脚本语言,通常UE使用蓝图或C++,但可以通过一些插件(如Puerts)来支持TypeScript。 根据问题,我们需要实现以下步骤: 1. 在C++中声明和定义一个函数(该函数可能调用C语言代码)。 2. 将这个C++函数暴露给TypeScript(通过Puerts或其他方式)。 假设我们使用Puerts(一个让UE支持TypeScript的插件)来实现。Puerts允许将C++函数、类等暴露给TypeScript,然后在TypeScript调用。 具体步骤: 步骤1:编写C函数 假设我们有一个C语言函数,例如在`MyCLib.c`中: ```c // MyCLib.c int add(int a, int b) { return a + b; } ``` 步骤2:使用C++封装这个C函数 在UE的C++项目中,我们创建一个新的模块或使用现有模块,然后编写一个C++类来封装C函数。首先,确保将C文件包含在项目中,并在头文件中声明。 例如,创建一个头文件`MyCLibWrapper.h`: ```cpp // MyCLibWrapper.h #pragma once extern "C" { // 声明C函数 int add(int a, int b); } ``` 然后,在C++中创建一个类来暴露给Puerts。注意,Puerts提供了宏来标记需要暴露的类或函数。 步骤3:使用Puerts的宏暴露函数C++中,我们可以使用`UE_MODULE`和`UE_FUNCTION`等宏来暴露函数。例如: ```cpp // 在某个模块的启动代码中(例如在模块的StartupModule函数中)暴露 #include "PuertsModule.h" #include "JsEnv.h" // 假设我们有一个包装函数 int AddWrapper(int a, int b) { return add(a, b); } // 暴露这个函数 void ExposeToTypeScript() { puerts::FFunctionInfo* AddFunction = new puerts::FFunctionInfo(); AddFunction->Name = "add"; // 在TypeScript中使用的函数名 AddFunction->Function = &AddWrapper; // 函数指针 // 将函数添加到全局对象中 puerts::GetJsEnv()->GlobalObject().SetFunction("add", AddFunction); } // 然后在模块启动时调用ExposeToTypeScript void FMyModule::StartupModule() { ExposeToTypeScript(); } ``` 另一种更常见的方式是使用Puerts的自动绑定功能,通过声明一个UCLASS或使用静态函数,然后用宏标记。 例如,创建一个UCLASS(继承自UObject)来包含这个静态函数: ```cpp // MyCLibWrapper.h UCLASS() class UMyCLibWrapper : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "MyCLib") static int Add(int a, int b) { return add(a, b); } }; ``` 然后,在TypeScript中,我们可以通过`UMyCLibWrapper.Add`来调用。 但是,Puerts提供了一种更直接的方式,即使用`uex`命名空间来调用静态函数。我们需要在TypeScript中声明这个类,然后调用。 步骤4:在TypeScript调用 首先,确保Puerts环境已经设置好。然后,在TypeScript中,我们可以这样调用: ```typescript // 如果使用UObject暴露的方式 let result = UMyCLibWrapper.Add(10, 20); console.log(result); ``` 或者,如果我们直接暴露为全局函数(如前面的第一种方式),则可以: ```typescript let result = add(10, 20); ``` 注意:第二种方式需要确保在C++中已经将函数设置到全局对象上。 然而,Puerts官方推荐使用基于UObject的绑定方式,因为这样可以利用UE的反射机制。 总结: 1. 将C函数编译到UE的C++项目中(可能需要修改构建文件,将.c文件包含进去)。 2. 在C++编写一个静态函数(或UObject的成员函数)来调用C函数。 3. 使用UFUNCTION宏标记这个函数,使其可以被反射(或者使用Puerts的暴露函数的方法)。 4. 在TypeScript中,通过Puerts提供的机制调用这个C++函数。 注意:如果C函数是动态(dll)形式,则需要先加载动态,然后使用dlsym(或Windows下的GetProcAddress)获取函数指针,再调用。 如果用户使用的是动态,步骤会稍微复杂一些,需要加载动态。 下面给出动态加载并调用的示例: 在C++中: ```cpp // 动态加载封装 void* DllHandle = nullptr; // 加载动态 void LoadMyCLib() { FString LibPath = TEXT("路径/到/动态"); DllHandle = FPlatformProcess::GetDllHandle(*LibPath); if (!DllHandle) { // 处理错误 } } // 函数指针类型 typedef int (*AddFunc)(int, int); // 调用动态中的函数 int CallDynamicAdd(int a, int b) { if (DllHandle) { AddFunc Func = (AddFunc)FPlatformProcess::GetDllExport(DllHandle, TEXT("add")); if (Func) { return Func(a, b); } } return 0; } // 然后在暴露给TypeScript函数调用CallDynamicAdd ``` 然后同样将这个CallDynamicAdd函数暴露给TypeScript。 以上就是在UE中使用TypeScript调用C语言声明的有返回值函数的方法。 根据要求,生成相关问题: §§相关问题§§ 1. 如何在UE中集成Puerts? 2. 如何将C代码编译进UE的C++项目中? 3. 在UE中如何使用动态(DLL)? 4. TypeScript调用C++函数时如何处理复杂的参数类型(如结构体)? 5. 在Puerts中如何调试TypeScript代码? </think> 在虚幻引擎中,使用 TypeScript 调用 C 语言声明的有返回值函数需要借助引擎的跨语言通信机制。推荐通过以下步骤实现: ### 核心步骤 1. **封装 C 函数C++ 模块** ```cpp // MyNativeFunctions.h #pragma once #include "CoreMinimal.h" class MYMODULE_API FNativeFunctions { public: // 声明需要调用函数 UFUNCTION(BlueprintCallable, Category = "TS-Bridge") static int AddNumbers(int a, int b); }; ``` ```cpp // MyNativeFunctions.cpp #include "MyNativeFunctions.h" #include "ThirdParty/C_Library/c_header.h" // 包含C头文件 int FNativeFunctions::AddNumbers(int a, int b) { // 调用C语言函数 return c_add(a, b); // c_add在C代码中定义 } ``` 2. **配置 TypeScript 环境(使用 Puerts 插件)** - 安装 [Puerts 插件](https://github.com/Tencent/puerts) 到引擎插件目录 - 在 `tsconfig.json` 中启用 UE 类型定义: ```json { "compilerOptions": { "types": ["puerts/unreal"] } } ``` 3. **TypeScript 调用 C++ 函数** ```typescript // Main.ts import * as UE from 'ue' import { $ref, $unref } from 'puerts' // 调用封装的C语言函数 const result = UE.FNativeFunctions.AddNumbers(5, 3); console.log(`C函数返回结果: ${result}`); ``` ### 关键注意事项 1. **C/C++ 交互要求** - 在 C++ 头文件中用 `extern "C"` 声明 C 函数: ```cpp extern "C" { int c_add(int a, int b); // C语言实现的函数 } ``` - 编译 C 代码为静态(`.lib`/`.a`)并链接到 UE 项目 2. **参数传递规则** | C 语言类型 | TypeScript 对应类型 | |------------|---------------------| | `int` | `number` | | `float` | `number` | | `bool` | `boolean` | | `char*` | `string` | 3. **调试建议** - 在 C++ 封装层添加日志输出验证参数传递 ```cpp UE_LOG(LogTemp, Warning, TEXT("接收参数: a=%d, b=%d"), a, b); ``` - 使用 `puerts` 的 `console.log()` 检查 TypeScript 返回值 ### 替代方案:WebAssembly (实验性) 若需直接调用 C 代码(不通过 C++): ```typescript // 加载WebAssembly模块 const wasmModule = await WebAssembly.instantiateStreaming( fetch("MyCLib.wasm") ); // 调用导出函数 const result = wasmModule.instance.exports.add(5, 3); ``` > ⚠️ 限制:UE 对 WASM 支持不完善,需通过 JavaScript 引擎插件实现[^1] ### 典型错误处理 ```typescript try { const res = UE.FNativeFunctions.Divide(10, 0); } catch (e) { console.error(`C函数异常: ${e.message}`); // 输出: "Attempt to divide by zero" } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值