mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-10 12:00:31 +00:00
Expose C++ interface via API headers, for C++ UI
* Since the exported C functions just take an explicit 'this' parameter and call the corresponding function, we can just make it contractual via a virtual interface that the pointer can be dereferenced.
This commit is contained in:
@@ -100,10 +100,38 @@ struct ResourceId
|
||||
#include "d3d11_pipestate.h"
|
||||
#include "gl_pipestate.h"
|
||||
|
||||
// for C++ expose the interface as a virtual interface
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct IReplayOutput
|
||||
{
|
||||
virtual bool SetOutputConfig(const OutputConfig &o) = 0;
|
||||
virtual bool SetTextureDisplay(const TextureDisplay &o) = 0;
|
||||
virtual bool SetMeshDisplay(const MeshDisplay &o) = 0;
|
||||
|
||||
virtual bool ClearThumbnails() = 0;
|
||||
virtual bool AddThumbnail(void *wnd, ResourceId texID) = 0;
|
||||
|
||||
virtual bool Display() = 0;
|
||||
|
||||
virtual bool SetPixelContext(void *wnd) = 0;
|
||||
virtual bool SetPixelContextLocation(uint32_t x, uint32_t y) = 0;
|
||||
virtual void DisablePixelContext() = 0;
|
||||
|
||||
virtual bool PickPixel(ResourceId texID, bool customShader,
|
||||
uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RENDERDOC_EXPORTS
|
||||
struct ReplayOutput;
|
||||
struct ReplayOutput;
|
||||
#else
|
||||
struct ReplayOutput { };
|
||||
#ifdef __cplusplus
|
||||
typedef IReplayOutput ReplayOutput;
|
||||
#else
|
||||
struct ReplayOutput { };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetOutputConfig(ReplayOutput *output, const OutputConfig &o);
|
||||
@@ -123,10 +151,74 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_PickPixel(ReplayOutput
|
||||
uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val);
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC ReplayOutput_PickVertex(ReplayOutput *output, uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y);
|
||||
|
||||
// for C++ expose the interface as a virtual interface
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct IReplayRenderer
|
||||
{
|
||||
virtual APIProperties GetAPIProperties() = 0;
|
||||
|
||||
virtual ReplayOutput* CreateOutput(void *handle) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual void ShutdownOutput(ReplayOutput *output) = 0;
|
||||
|
||||
virtual bool HasCallstacks() = 0;
|
||||
virtual bool InitResolver() = 0;
|
||||
|
||||
virtual bool SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv) = 0;
|
||||
virtual bool SetFrameEvent(uint32_t frameID, uint32_t eventID) = 0;
|
||||
virtual bool GetD3D11PipelineState(D3D11PipelineState *state) = 0;
|
||||
virtual bool GetGLPipelineState(GLPipelineState *state) = 0;
|
||||
|
||||
virtual ResourceId BuildCustomShader(const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, rdctype::str *errors) = 0;
|
||||
virtual bool FreeCustomShader(ResourceId id) = 0;
|
||||
|
||||
virtual ResourceId BuildTargetShader(const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, rdctype::str *errors) = 0;
|
||||
virtual bool ReplaceResource(ResourceId from, ResourceId to) = 0;
|
||||
virtual bool RemoveReplacement(ResourceId id) = 0;
|
||||
virtual bool FreeTargetResource(ResourceId id) = 0;
|
||||
|
||||
virtual bool GetFrameInfo(rdctype::array<FetchFrameInfo> *frame) = 0;
|
||||
virtual bool GetDrawcalls(uint32_t frameID, rdctype::array<FetchDrawcall> *draws) = 0;
|
||||
virtual bool FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array<CounterResult> *results) = 0;
|
||||
virtual bool EnumerateCounters(rdctype::array<uint32_t> *counters) = 0;
|
||||
virtual bool DescribeCounter(uint32_t counterID, CounterDescription *desc) = 0;
|
||||
virtual bool GetTextures(rdctype::array<FetchTexture> *texs) = 0;
|
||||
virtual bool GetBuffers(rdctype::array<FetchBuffer> *bufs) = 0;
|
||||
virtual bool GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::str> *trace) = 0;
|
||||
virtual ShaderReflection* GetShaderDetails(ResourceId shader) = 0;
|
||||
virtual bool GetDebugMessages(rdctype::array<DebugMessage> *msgs) = 0;
|
||||
|
||||
virtual bool PixelHistory(ResourceId target, uint32_t x, uint32_t y, uint32_t sampleIdx, rdctype::array<PixelModification> *history) = 0;
|
||||
virtual bool DebugVertex(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace) = 0;
|
||||
virtual bool DebugPixel(uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive, ShaderDebugTrace *trace) = 0;
|
||||
virtual bool DebugThread(uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace) = 0;
|
||||
|
||||
virtual bool GetUsage(ResourceId id, rdctype::array<EventUsage> *usage) = 0;
|
||||
|
||||
virtual bool GetCBufferVariableContents(ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array<ShaderVariable> *vars) = 0;
|
||||
|
||||
virtual bool SaveTexture(const TextureSave &saveData, const char *path) = 0;
|
||||
|
||||
virtual bool GetPostVSData(uint32_t instID, MeshDataStage stage, MeshFormat *data) = 0;
|
||||
|
||||
virtual bool GetMinMax(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval) = 0;
|
||||
virtual bool GetHistogram(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], rdctype::array<uint32_t> *histogram) = 0;
|
||||
|
||||
virtual bool GetBufferData(ResourceId buff, uint32_t offset, uint32_t len, rdctype::array<byte> *data) = 0;
|
||||
virtual bool GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, rdctype::array<byte> *data) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RENDERDOC_EXPORTS
|
||||
struct ReplayRenderer;
|
||||
struct ReplayRenderer;
|
||||
#else
|
||||
struct ReplayRenderer { };
|
||||
#ifdef __cplusplus
|
||||
typedef IReplayRenderer ReplayRenderer;
|
||||
#else
|
||||
struct ReplayRenderer { };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(ReplayRenderer *rend, APIProperties *props);
|
||||
@@ -143,10 +235,10 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SetFrameEvent(Replay
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetD3D11PipelineState(ReplayRenderer *rend, D3D11PipelineState *state);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetGLPipelineState(ReplayRenderer *rend, GLPipelineState *state);
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeCustomShader(ReplayRenderer *rend, ResourceId id);
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_ReplaceResource(ReplayRenderer *rend, ResourceId from, ResourceId to);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_RemoveReplacement(ReplayRenderer *rend, ResourceId id);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeTargetResource(ReplayRenderer *rend, ResourceId id);
|
||||
@@ -181,10 +273,35 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetHistogram(ReplayR
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBufferData(ReplayRenderer *rend, ResourceId buff, uint32_t offset, uint32_t len, rdctype::array<byte> *data);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetTextureData(ReplayRenderer *rend, ResourceId tex, uint32_t arrayIdx, uint32_t mip, rdctype::array<byte> *data);
|
||||
|
||||
// for C++ expose the interface as a virtual interface
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct IRemoteAccess
|
||||
{
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
virtual const char* GetTarget() = 0;
|
||||
virtual const char* GetAPI() = 0;
|
||||
virtual uint32_t GetPID() = 0;
|
||||
virtual const char* GetBusyClient() = 0;
|
||||
|
||||
virtual void TriggerCapture() = 0;
|
||||
virtual void QueueCapture(uint32_t frameNumber) = 0;
|
||||
virtual void CopyCapture(uint32_t remoteID, const char *localpath) = 0;
|
||||
|
||||
virtual void ReceiveMessage(RemoteMessage *msg) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RENDERDOC_EXPORTS
|
||||
struct RemoteAccess;
|
||||
struct RemoteAccess;
|
||||
#else
|
||||
struct RemoteAccess { };
|
||||
#ifdef __cplusplus
|
||||
typedef IRemoteAccess RemoteAccess;
|
||||
#else
|
||||
struct RemoteAccess { };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_Shutdown(RemoteAccess *access);
|
||||
@@ -200,10 +317,29 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_CopyCapture(RemoteAccess
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RemoteAccess_ReceiveMessage(RemoteAccess *access, RemoteMessage *msg);
|
||||
|
||||
// for C++ expose the interface as a virtual interface
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct IRemoteRenderer
|
||||
{
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
virtual bool LocalProxies(rdctype::array<rdctype::str> *out) = 0;
|
||||
virtual bool RemoteSupportedReplays(rdctype::array<rdctype::str> *out) = 0;
|
||||
|
||||
virtual ReplayCreateStatus CreateProxyRenderer(uint32_t proxyid, const char *logfile, float *progress, ReplayRenderer **rend) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RENDERDOC_EXPORTS
|
||||
struct RemoteRenderer;
|
||||
struct RemoteRenderer;
|
||||
#else
|
||||
struct RemoteRenderer { };
|
||||
#ifdef __cplusplus
|
||||
typedef IRemoteRenderer RemoteRenderer;
|
||||
#else
|
||||
struct RemoteRenderer { };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RemoteRenderer_Shutdown(RemoteRenderer *remote);
|
||||
|
||||
@@ -110,6 +110,8 @@ enum RDCDriver
|
||||
RDC_Custom9,
|
||||
};
|
||||
|
||||
typedef uint32_t bool32;
|
||||
|
||||
namespace DXBC { class DXBCFile; }
|
||||
namespace Callstack { class StackResolver; }
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ void RenderDoc::RemoteAccessServerThread(void *s)
|
||||
Threading::ReleaseModuleExitThread();
|
||||
}
|
||||
|
||||
struct RemoteAccess
|
||||
struct RemoteAccess : public IRemoteAccess
|
||||
{
|
||||
public:
|
||||
RemoteAccess(Network::Socket *sock, string clientName, bool forceConnection, bool localhost)
|
||||
|
||||
@@ -227,7 +227,7 @@ void RenderDoc::BecomeReplayHost(volatile bool32 &killReplay)
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoteRenderer
|
||||
struct RemoteRenderer : public IRemoteRenderer
|
||||
{
|
||||
public:
|
||||
RemoteRenderer(Network::Socket *sock)
|
||||
|
||||
@@ -1268,6 +1268,16 @@ ReplayOutput *ReplayRenderer::CreateOutput(void *wndhandle)
|
||||
return out;
|
||||
}
|
||||
|
||||
void ReplayRenderer::ShutdownOutput(ReplayOutput *output)
|
||||
{
|
||||
RDCUNIMPLEMENTED("Shutting down individual outputs");
|
||||
}
|
||||
|
||||
void ReplayRenderer::Shutdown()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
ResourceId ReplayRenderer::BuildTargetShader(const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, rdctype::str *errors)
|
||||
{
|
||||
ResourceId id;
|
||||
@@ -1509,9 +1519,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(Repla
|
||||
extern "C" RENDERDOC_API ReplayOutput* RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, void *handle)
|
||||
{ return rend->CreateOutput(handle); }
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend)
|
||||
{ delete rend; }
|
||||
{ rend->Shutdown(); }
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output)
|
||||
{ RDCUNIMPLEMENTED("destroying individual outputs"); }
|
||||
{ rend->ShutdownOutput(output); }
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend)
|
||||
{ return rend->HasCallstacks(); }
|
||||
@@ -1527,24 +1537,20 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetD3D11PipelineStat
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetGLPipelineState(ReplayRenderer *rend, GLPipelineState *state)
|
||||
{ return rend->GetGLPipelineState(state); }
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
|
||||
{
|
||||
if(shaderID == NULL) return false;
|
||||
if(shaderID == NULL) return;
|
||||
|
||||
*shaderID = rend->BuildCustomShader(entry, source, compileFlags, type, errors);
|
||||
|
||||
return (*shaderID != ResourceId());
|
||||
}
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeCustomShader(ReplayRenderer *rend, ResourceId id)
|
||||
{ return rend->FreeCustomShader(id); }
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
|
||||
{
|
||||
if(shaderID == NULL) return false;
|
||||
if(shaderID == NULL) return;
|
||||
|
||||
*shaderID = rend->BuildTargetShader(entry, source, compileFlags, type, errors);
|
||||
|
||||
return (*shaderID != ResourceId());
|
||||
}
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_ReplaceResource(ReplayRenderer *rend, ResourceId from, ResourceId to)
|
||||
{ return rend->ReplaceResource(from, to); }
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
struct ReplayRenderer;
|
||||
|
||||
struct ReplayOutput
|
||||
struct ReplayOutput : public IReplayOutput
|
||||
{
|
||||
public:
|
||||
bool SetOutputConfig(const OutputConfig &o);
|
||||
@@ -123,7 +123,7 @@ private:
|
||||
friend struct ReplayRenderer;
|
||||
};
|
||||
|
||||
struct ReplayRenderer
|
||||
struct ReplayRenderer : public IReplayRenderer
|
||||
{
|
||||
public:
|
||||
ReplayRenderer();
|
||||
@@ -185,6 +185,9 @@ struct ReplayRenderer
|
||||
bool GetCBufferVariableContents(ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array<ShaderVariable> *vars);
|
||||
|
||||
ReplayOutput *CreateOutput(void *handle);
|
||||
|
||||
void ShutdownOutput(ReplayOutput *output);
|
||||
void Shutdown();
|
||||
private:
|
||||
ReplayCreateStatus PostCreateInit(IReplayDriver *device);
|
||||
|
||||
|
||||
@@ -200,12 +200,12 @@ namespace renderdoc
|
||||
private static extern bool ReplayRenderer_GetGLPipelineState(IntPtr real, IntPtr mem);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool ReplayRenderer_BuildCustomShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem);
|
||||
private static extern void ReplayRenderer_BuildCustomShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem);
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool ReplayRenderer_FreeCustomShader(IntPtr real, ResourceId id);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool ReplayRenderer_BuildTargetShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem);
|
||||
private static extern void ReplayRenderer_BuildTargetShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem);
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool ReplayRenderer_ReplaceResource(IntPtr real, ResourceId from, ResourceId to);
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
@@ -353,14 +353,11 @@ namespace renderdoc
|
||||
IntPtr entry_mem = CustomMarshal.MakeUTF8String(entry);
|
||||
IntPtr source_mem = CustomMarshal.MakeUTF8String(source);
|
||||
|
||||
bool success = ReplayRenderer_BuildCustomShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem);
|
||||
ReplayRenderer_BuildCustomShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem);
|
||||
|
||||
CustomMarshal.Free(entry_mem);
|
||||
CustomMarshal.Free(source_mem);
|
||||
|
||||
if (!success)
|
||||
ret = ResourceId.Null;
|
||||
|
||||
errors = CustomMarshal.TemplatedArrayToString(mem, true);
|
||||
|
||||
CustomMarshal.Free(mem);
|
||||
@@ -380,14 +377,11 @@ namespace renderdoc
|
||||
IntPtr entry_mem = CustomMarshal.MakeUTF8String(entry);
|
||||
IntPtr source_mem = CustomMarshal.MakeUTF8String(source);
|
||||
|
||||
bool success = ReplayRenderer_BuildTargetShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem);
|
||||
ReplayRenderer_BuildTargetShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem);
|
||||
|
||||
CustomMarshal.Free(entry_mem);
|
||||
CustomMarshal.Free(source_mem);
|
||||
|
||||
if (!success)
|
||||
ret = ResourceId.Null;
|
||||
|
||||
errors = CustomMarshal.TemplatedArrayToString(mem, true);
|
||||
|
||||
CustomMarshal.Free(mem);
|
||||
|
||||
Reference in New Issue
Block a user