When generating R wrapper code from Swig, it doesn't handle pointers to pointers correct (or if I don't use Swig/R correct). It passes a pointer to a pointer even if it shouldn't (in the second function call, fnRDllTestCopy)

This must be a bug when generating R code (or I use it incorrectly).

(Full project to reproduce the problem https://umetrics.sharefile.com/d/s4aa392c862a49adb)

This how it's created and the result

Swig command to create the wrapper:
swig.exe -r -c++ -o rfile.cpp RDllTest.i

The exported code looks like
typedef struct tagTestHandle
{
void* pReserved;
TestHandle;
RDLLTEST_API int RCDECL fnRDllTestPointer(TestHandle
 pHandle);
RDLLTEST_API int RCDECL fnRDllTestCopy(TestHandle pHandle);

and from R I call

dyn.load ("C:\Projects\RDllTest\Debug\RTest.dll")
source("C:\Projects\RDllTest\RTest.R")
handle <- tagTestHandle()
fnRDllTestPointer(handle)
fnRDllTestCopy(handle) // Returns -1 which indicates an error

The C code looks like

class TestClass
{
public:
TestClass() : miTest(1234) {}
int miTest;
};

// This is an example of an exported function.
RDLLTEST_API int fnRDllTestPointer(TestHandle* pHandle)
{
*pHandle = reinterpret_cast(new TestClass());
return 42;
}

RDLLTEST_API int fnRDllTestCopy(TestHandle pHandle)
{
TestClass* pClass = reinterpret_cast(pHandle);
if (pClass->miTest != 1234) // Should be 1234 or there is an error
return -1;
return 42;
}

Generated R code

fnRDllTestPointer = function(pHandle, .copy = FALSE)
{
if (inherits(pHandle, "ExternalReference")) pHandle = slot(pHandle,"ref") 
;.Call('R_swig_fnRDllTestPointer', pHandle, as.logical(.copy), PACKAGE='RTest');
}

attr(fnRDllTestPointer, 'returnType') = 'integer'
attr(fnRDllTestPointer, "inputTypes") = c('_p_p_tagTestHandle')
class(fnRDllTestPointer) = c("SWIGFunction", class('fnRDllTestPointer'))

Start of fnRDllTestCopy

fnRDllTestCopy = function(pHandle, .copy = FALSE)
{
if (inherits(pHandle, "ExternalReference")) pHandle = slot(pHandle,"ref") 
;.Call('R_swig_fnRDllTestCopy', pHandle, as.logical(.copy), PACKAGE='RTest'); 
}
attr(fnRDllTestCopy, 'returnType') = 'integer'
attr(fnRDllTestCopy, "inputTypes") = c('_p_tagTestHandle')
class(fnRDllTestCopy) = c("SWIGFunction", class('fnRDllTestCopy'))

Generated C++ code

SWIGEXPORT SEXP
R_swig_fnRDllTestPointer ( SEXP pHandle, SEXP s_swig_copy)
{
int result;
TestHandle *arg1 = (TestHandle *) 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
unsigned int r_nprotect = 0;
SEXP r_ans = R_NilValue ;
VMAXTYPE r_vmax = vmaxget() ;

res1 = SWIG_R_ConvertPtr(pHandle, &argp1, SWIGTYPE_p_p_tagTestHandle, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "fnRDllTestPointer" "', argument " "1"" of type '" "TestHandle ""'"); 
}
arg1 = reinterpret_cast< TestHandle * >(argp1);
{
try {
result = (int)fnRDllTestPointer(arg1);

} catch(std::string& stringReason) {
const char
 sData = (char*)stringReason.c_str();
SWIG_exception(SWIG_RuntimeError, sData);
} catch(...) {
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}
r_ans = Rf_ScalarInteger(result);

vmaxset(r_vmax);
if(r_nprotect) Rf_unprotect(r_nprotect);

return r_ans;
}

SWIGEXPORT SEXP
R_swig_fnRDllTestCopy ( SEXP pHandle, SEXP s_swig_copy)
{
int result;
TestHandle arg1 = (TestHandle) 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
unsigned int r_nprotect = 0;
SEXP r_ans = R_NilValue ;
VMAXTYPE r_vmax = vmaxget() ;

res1 = SWIG_R_ConvertPtr(pHandle, &argp1, SWIGTYPE_p_tagTestHandle, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "fnRDllTestCopy" "', argument " "1"" of type '" "TestHandle""'"); 
}
arg1 = reinterpret_cast< TestHandle >(argp1);
{
try {
result = (int)fnRDllTestCopy(arg1);

} catch(std::string& stringReason) {
const char* sData = (char*)stringReason.c_str();
SWIG_exception(SWIG_RuntimeError, sData);
} catch(...) {
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}
r_ans = Rf_ScalarInteger(result);

vmaxset(r_vmax);
if(r_nprotect) Rf_unprotect(r_nprotect);

return r_ans;
}