There are several things going on here.
- szPname is not a Ptr{Uint8}. It is an inline 32 char array, so
sizeof(MidiOutCaps) is wrong. Unfortunately, there isn't a great way to
represent such a struct in Julia 0.3 (it is doable but really hacky). I
would suggest to use 0.4 pre-release binaries unless you have a strong
reason not to do so. In 0.4 you can use an NTuple{32,UInt8} which will be
inlined in the struct.
- unsafe_load is not the right function to do what you want there. In
principle, `unsafe_load`ing a Ptr{Uint8} would just give you back a single
Uint8 -- not a string -- but there is an access violation likely because
the struct size is wrong. `bytestring` is used for a Ptr{Uint8}
- the "&" operator in a Julia ccall doesn't work like C. In 0.4 you should
use a Ref, see:
http://docs.julialang.org/en/latest/manual/calling-c-and-fortran-code/#passing-pointers-for-modifying-inputs
Here is some minimally tested example code that does not crash on the
latest 0.4-dev nightly (`midiOutGetNumDevs` says I have one device, so I'm
not sure why the return value indicates a bad device id):
julia> immutable MidiOutCaps
wMid::Uint16
wPid::Uint16
vDriverVersion::Uint32
szPname::NTuple{32,Uint8}
wTechnology::Uint16
wVoices::Uint16
wNotes::Uint16
wChannelMask::Uint16
dwSupport::Uint32
MidiOutCaps() = new(0, 0, 0, ntuple(i->0,32), 0, 0, 0, 0, 0)
end
julia> output_struct = Ref{MidiOutCaps}()
1-element Array{MidiOutCaps,1}:
MidiOutCaps(0x0000,0x0000,0x00000000,(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0
x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0
x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),0x0000,0x0000,0x0000,0x0000,0x00000000)
julia> devid = Ref{Uint32}(0)
julia> err = ccall( (:midiOutGetDevCapsA, :Winmm), Uint32, (Ref{Uint32},
Ref{Mid
iOutCaps}, Uint32), devid, output_struct, sizeof(output_struct))
0x00000002
julia> bytestring(convert(Ptr{UInt8},pointer(output_struct)+31))
""
Doing pointer math (see `fieldoffsets` function) is obviously not ideal,
nor word size-portable as written above. Hopefully someone else will have a
better suggestion for getting the string data out of the inlined NTuple.
On Sun, Sep 6, 2015 at 12:33 PM, Joel Hobson <[email protected]> wrote:
> Hi all,
>
> I'm trying to use some C functions, but I'm running into trouble using the
> results.
>
> This is the function I'm trying to call:
> https://msdn.microsoft.com/en-us/library/dd798469(v=vs.85).aspx
> And this is the struct that it's expecting a pointer to:
> https://msdn.microsoft.com/en-us/library/dd798467(v=vs.85).aspx
>
> Here's my struct definition in Julia:
>
> type MidiOutCaps
> wMid::Uint16
> wPid::Uint16
> vDriverVersion::Uint32
> szPname::Ptr{Uint8}
> wTechnology::Uint16
> wVoices::Uint16
> wNotes::Uint16
> wChannelMask::Uint16
> dwSupport::Uint32
>
> MidiOutCaps() = new(0, 0, 0, Array(Uint8, 32), 0, 0, 0, 0, 0)
> end
>
> And the function for loading it:
>
> function getoutputdeviceswindows()
> numberofdevices = ccall( (:midiOutGetNumDevs, :Winmm), Int32, ())
>
> for i in [0:numberofdevices-1]
> output_struct = MidiOutCaps()
>
> err = ccall( (:midiOutGetDevCapsA, :Winmm), Uint32, (Ptr{Uint32},
> Ptr{MidiOutCaps}, Uint32), i, &output_struct, sizeof(output_struct))
>
> println("Err is $(err)")
> println("Result is $(output_struct)")
>
> println("Result name is $(unsafe_load(output_struct.szPname, 0))")
> end
> end
>
> Both ccalls execute without error, and it appears to populate the struct
> correctly, but when I try to do an unsafe load on the szPname, Julia
> crashes and I get this:
>
> Please submit a bug report with steps to reproduce this fault, and any
> error messages that follow (in their entirety). Thanks.
> Exception: EXCEPTION_ACCESS_VIOLATION at 0xdbc6d34 -- unsafe_load at
> pointer.jl:45
> unsafe_load at pointer.jl:45
> jlcall_unsafe_load_1323 at (unknown line)
> jl_apply_generic at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> jl_interpret_toplevel_expr at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> jl_interpret_toplevel_thunk_with at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> jl_eval_with_compiler_p at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> jl_f_top_eval at C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll
> (unknown line)
> eval_user_input at REPL.jl:53
> jlcall_eval_user_input_1054 at (unknown line)
> jl_apply_generic at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> anonymous at task.jl:95
> jl_handle_stack_switch at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> julia_trampoline at
> C:\Users\Joel\AppData\Local\Julia-0.3.9\bin\libjulia.dll (unknown line)
> unknown function (ip: 4202784)
> unknown function (ip: 4199370)
> unknown function (ip: 4199672)
> BaseThreadInitThunk at C:\WINDOWS\system32\KERNEL32.DLL (unknown line)
> RtlUserThreadStart at C:\WINDOWS\SYSTEM32\ntdll.dll (unknown line)
> RtlUserThreadStart at C:\WINDOWS\SYSTEM32\ntdll.dll (unknown line)
>
> I suspect that it's a problem with my code and not Julia, which is why I
> haven't submitted a bug report yet.
>
> I've tried just setting szPname to 0 instead of an array, and I've tried
> different index values for unsafe_load, but no luck. Any ideas where I'm
> going wrong? The only other issue I can see is that MSDN defines szPname to
> be an array of TCHARs, but according to the MSDN, TCHAR is just a char.
> https://msdn.microsoft.com/en-us/library/office/cc842072.aspx
>
> Thanks!
>
>
>
>