Ccall with a C struct containing a pointer

Not really - the difference is just that you wouldn’t pass a Ptr/Ref in the ccall but just the struct directly, without the need for pointer_from_objref and the like at all.

If the size/type of the individual items in the struct is different, you’ll want/need to make sure to convert the data to that type. So from julian Int64 to a Cint, by storing the data in a new bit of memory.

That should be something like

function Base.cconvert(::Type{DenseMatrix{T}}, m::Matrix{T}) where T
    rowCount, colCount = size(m)
    stride = 1 # not 100% sure on this - check that row/column majorness aligns! Julia is column major!
    dm = DenseMatrix{T}(rowCount, colCount, strig, #= the attribute type object =#, C_NULL)
    return (m, dm)
end

function Base.unsafe_convert(::Type{DenseMatrix{T}}, tup::Tuple{Matrix{T}, DenseMatrix{T}}) where T
    m, dm = tup
    dm.data = pointer(m) # m is GC-preserved in this function, so this is safe
    dm
end

Yes, the types you end up passing to C must match exactly in terms of layout. You can check Base.allocated_inline, which should help with that. The important thing is that the outermost struct you pass is mutable (either because the struct itself is mutable, or it’s a Ref, which is just a mutable struct with a single field), so that any modification C makes into that memory is visible again on the julia side. To Julia this would be “as if” the entire content was replaced, even though C just performed a partial write.