# Calling Windows API from Julia

**URL:** <https://discourse.julialang.org/t/calling-windows-api-from-julia/25123>\
**Category:** General Usage\
**Tags:** question, windows\
**Created:** [June 10, 2019, 5:59pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123 "2019-06-10T17:59:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 10, 2019, 5:59pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/1 "2019-06-10T17:59:27Z")

</div>

Hi Julians,

I am trying to implement a script that will list all Fonts installed on Windows using Gdi32.dll.

First of all, here is the full script so you can make sense of what i’m about to write below: [https://github.com/gabrielfreire/Fonts/blob/master/fonts.jl](https://github.com/gabrielfreire/Fonts/blob/master/fonts.jl)

All my C calls are working fine,

my problem is that when i receive ENUMLOGFONTA in the callback i pass to `EnumFontFamiliesW` and try to `unsafe_string` the `lplf.elfFullName` property it throws an `EXCEPTION_ACCESS_VIOLATION` exception, even though i am using `Ref{ENUMLOGFONTA}` to declare my callback `@cfunction`, i’m not sure if i understood the documentation correctly, but i believe `Ref` is supposed to avoid C from freeing that pointer and let me load it later, right?

same happens for `lplf.elfLogFont.lfFaceName`.

```julia
function enum_fam_callback(lplf::ENUMLOGFONTA, lpntm::NEWTEXTMETRICA, font_type::DWORD, afont_count::LPARAM)
    # Store true type fonts
    if Int32(font_type) == FontType.TrueType
        if lplf != C_NULL
            font = Dict(
                "name"=>unsafe_string(lplf.elfFullName), # this throws EXCEPTION_ACCESS_VIOLATION 
                "quality"=>lplf.elfLogFont.lfQuality, 
                "weight"=>lplf.elfLogFont.lfWeight,
                "faceName"=>lplf.elfLogFont.lfFaceName,
                "fontPitchAndFamily"=>lplf.elfLogFont.lfPitchAndFamily,
                "charSet"=>lplf.elfLogFont.lfCharSet
            )
            push!(fontnames, font)
        end
    end
    # dump(lplf)
    return convert(Cint, 1)::Cint
end

```

My Julia struct

```julia
struct LOGFONTA
    lfHeight::Clong
    lfWidth::Clong
    lfEscapement::Clong
    lfOrientation::Clong
    lfWeight::Clong
    lfItalic::UInt8
    lfUnderline::UInt8
    lfStrikeOut::UInt8
    lfCharSet::UInt8
    lfOutPrecision::UInt8
    lfClipPrecision::UInt8
    lfQuality::UInt8
    lfPitchAndFamily::UInt8
    lfFaceName::Cstring
end

struct ENUMLOGFONTA
    elfLogFont::LOGFONTA
    elfFullName::Cstring
    elfStyle::Cstring
end

```

Windows API C++ struct

```cpp
typedef struct tagLOGFONTA {
  LONG lfHeight;
  LONG lfWidth;
  LONG lfEscapement;
  LONG lfOrientation;
  LONG lfWeight;
  BYTE lfItalic;
  BYTE lfUnderline;
  BYTE lfStrikeOut;
  BYTE lfCharSet;
  BYTE lfOutPrecision;
  BYTE lfClipPrecision;
  BYTE lfQuality;
  BYTE lfPitchAndFamily;
  CHAR lfFaceName[LF_FACESIZE];
} LOGFONTA, *PLOGFONTA, *NPLOGFONTA, *LPLOGFONTA;

typedef struct tagENUMLOGFONTA {
  LOGFONTA elfLogFont;
  BYTE elfFullName[LF_FULLFACESIZE];
  BYTE elfStyle[LF_FACESIZE];
} ENUMLOGFONTA, *LPENUMLOGFONTA;

```

I am pretty sure i am doing something wrong, but i can’t find where.  
Please, help.

Full error message

```bash
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 0x7ffeb535d4e0 -- strlen at C:\Windows\System32\msvcrt.dll (unknown line)
in expression starting at C:\Users\gabrielfreiredev\Documents\workspace\Fonts\fonts.jl:158
strlen at C:\Windows\System32\msvcrt.dll (unknown line)
jl_cstr_to_string at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\array.c:496
unsafe_string at .\strings\string.jl:57 [inlined]
unsafe_string at .\c.jl:193 [inlined]
enum_fam_callback at C:\Users\gabrielfreiredev\Documents\workspace\Fonts\fonts.jl:134
unknown function (ip: 000000002936C362)
EnumFontFamiliesExW at C:\Windows\System32\gdi32full.dll (unknown line)
EnumFontFamiliesW at C:\Windows\System32\gdi32full.dll (unknown line)
top-level scope at C:\Users\gabrielfreiredev\Documents\workspace\Fonts\fonts.jl:158
jl_toplevel_eval_flex at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\toplevel.c:808
jl_parse_eval_all at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\ast.c:873
jl_load at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\toplevel.c:878 [inlined]
jl_load_ at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\toplevel.c:885
include at .\boot.jl:328 [inlined]
include_relative at .\loading.jl:1094
include at .\Base.jl:31
_jl_invoke at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\gf.c:2043 [inlined]
jl_apply_generic at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\gf.c:2213
exec_options at .\client.jl:295
_start at .\client.jl:464
_jl_invoke at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\gf.c:2043 [inlined]
jl_apply_generic at /home/Administrator/buildbot/worker/package_win64/build/src/home/Administrator/buildbot/worker/package_win64/build/src\gf.c:2213
jl_apply at /home/Administrator/buildbot/worker/package_win64/build/ui/home/Administrator/buildbot/worker/package_win64/build/src\julia.h:1624 [inlined]
true_main at /home/Administrator/buildbot/worker/package_win64/build/ui/home/Administrator/buildbot/worker/package_win64/build/ui\repl.c:96
wmain at /home/Administrator/buildbot/worker/package_win64/build/ui/home/Administrator/buildbot/worker/package_win64/build/ui\repl.c:217
__tmainCRTStartup at /usr/src/debug/mingw64-x86_64-runtime-6.0.0-1/usr/src/debug/mingw64-x86_64-runtime-6.0.0-1/crt\crtexe.c:334
mainCRTStartup at /usr/src/debug/mingw64-x86_64-runtime-6.0.0-1/usr/src/debug/mingw64-x86_64-runtime-6.0.0-1/crt\crtexe.c:223
BaseThreadInitThunk at C:\Windows\System32\KERNEL32.DLL (unknown line)
RtlUserThreadStart at C:\Windows\SYSTEM32\ntdll.dll (unknown line)
Allocations: 2732207 (Pool: 2731174; Big: 1033); GC: 5

```

Thank you.

---

<div class="post-metadata">

**Author:** ![ihnorton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ihnorton/32/26_2.png) [@ihnorton](https://discourse.julialang.org/u/ihnorton)\
**Post date:** [June 11, 2019, 2:12am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/2 "2019-06-11T02:12:21Z")

</div>

The callback function should accept pointers as the first two arguments:

> **[EnumFontFamProc callback function (Windows)](https://learn.microsoft.com/en-us/previous-versions/dd162621(v=vs.85))**

(you could then use [`Base.fieldoffset`](https://docs.julialang.org/en/v1/base/base/#Base.fieldoffset) to get the offset to pass to `unsafe_load` in order to dereference a given field – though there may be a simpler way these days)

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 12, 2019, 8:07am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/3 "2019-06-12T08:07:19Z")

</div>

Thank you @ihnorton, i haven’t had the chance to properly try this yet, only tried once really quickly and didn’t manage to load the field, but i’ll try more and let you know.

Thanks =)

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 12, 2019, 7:19pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/4 "2019-06-12T19:19:20Z")

</div>

Hi @ihnorton, thank you again for your response, but i didn’t manage to make that work

the offset index for the `elfFullName` in `ENUMLOGFONTA` is `2`.

i get this with `fieldoffset`

```julia
fieldoffset(ENUMLOGFONTA, 2) => 0x0000000000000028

```

`unsafe_load` does’t seem to be able to receive this kind of input, so i am using the field index

```julia
fullname = unsafe_load(lplf, 2)

```

But this returns the whole `ENUMLOGFONTA` object with the wrong values, maybe only right from `elfFullName` field forward, but not loaded, something like `Cstring(0x0000000000610072)`

and i keep getting `EXCEPTION_ACCESS_VIOLATION ` when i try to dereference it using `unsafe_load` or `unsafe_string`

Thank you again, i hope you or somebody else can help me, i believe this should be very straight forward but i am doing something totally wrong.

P.S. i pushed the changes to github [https://github.com/gabrielfreire/Fonts/blob/master/fonts.jl](https://github.com/gabrielfreire/Fonts/blob/master/fonts.jl)

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [June 13, 2019, 3:45am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/5 "2019-06-13T03:45:31Z")

</div>

I think your problem here is that the “string” parts of your C and julia structs don’t match. For example, in the C case, you’ve got

```julia
CHAR lfFaceName[LF_FACESIZE];

```

Which means that `lfFaceName` is an array of `LF_FACESIZE` windows `CHAR`s which are _embedded within_ the `tagLOGFONTA` struct. The equivalent thing on the julia side would be an NTuple of the appropriate character type ([\_\_wchar\_t](https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741230(v%3dvs.85))?)

```julia
    lfFaceName::NTuple{LF_FACESIZE,Cwchar_t}

```

You can then load this `NTuple` of windows characters which will then need to be converted to UTF-8 to create a valid `String` (presumably using [transcode](https://docs.julialang.org/en/v1.1/base/strings/#Base.transcode)).

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 13, 2019, 10:37am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/6 "2019-06-13T10:37:46Z")

</div>

Hi @c42f, wooooow!! Thank you so much… it worked \<3 \<3  
I haven’t updated github yet because i’m not at home, but the code changes were

types

```julia
const LF_FACESIZE = 32
const LF_FULLFACESIZE = 64

struct LOGFONTA
    lfHeight::Clong
    lfWidth::Clong
    lfEscapement::Clong
    lfOrientation::Clong
    lfWeight::Clong
    lfItalic::UInt8
    lfUnderline::UInt8
    lfStrikeOut::UInt8
    lfCharSet::UInt8
    lfOutPrecision::UInt8
    lfClipPrecision::UInt8
    lfQuality::UInt8
    lfPitchAndFamily::UInt8
    lfFaceName::NTuple{LF_FACESIZE, Cwchar_t}
end

struct ENUMLOGFONTA
    elfLogFont::LOGFONTA
    elfFullName::NTuple{LF_FULLFACESIZE, Cwchar_t}
    elfStyle::NTuple{LF_FACESIZE, Cwchar_t}
end

```

the callback stays the same

```julia
            fn = unsafe_load(lplf)
            font = Dict(
                "fullName"=>fn.elfFullName,
                "style"=>fn.elfStyle,
                "faceName"=>fn.elfLogFont.lfFaceName,
                "quality"=>fn.elfLogFont.lfQuality, 
                "weight"=>fn.elfLogFont.lfWeight,
                "fontPitchAndFamily"=>fn.elfLogFont.lfPitchAndFamily,
                "charSet"=>fn.elfLogFont.lfCharSet
            )

```

small function to decode stuff

```julia
using StringEncodings
function decode_str(encoded::NTuple)::String
    encoded_ = Vector{UInt8}([d for d in encoded])
    utf8enc = transcode(UInt8, encoded_)
    decoded = decode(utf8enc, enc"UTF-8")
    return replace(decoded, "\0"=>"")
end

```

and the display part looks like this

```julia
println("-----------------------------------------")
            @show decode_str(f["fullName"])
            @show decode_str(f["style"])
            @show decode_str(f["faceName"])
            haskey(FontPitchAndFamily, f["fontPitchAndFamily"]) && @show FontPitchAndFamily[f["fontPitchAndFamily"]]
            haskey(FontQuality, f["quality"]) && @show FontQuality[f["quality"]]
            haskey(FontCharSet, f["charSet"]) && @show FontCharSet[f["charSet"]]
            haskey(FontWeight, f["weight"]) && @show FontWeight[f["weight"]]

```

Some output

```bash
-----------------------------------------
decode_str(f["fullName"]) = "Marlett"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Marlett"
FontPitchAndFamily[f["fontPitchAndFamily"]] = "VARIABLE_PITCH"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "SYMBOL_CHARSET"
FontWeight[f["weight"]] = "FW_MEDIUM"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arabic Transparent"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial Baltic"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "BALTIC_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial CE"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "EASTEUROPE_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial CYR"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "RUSSIAN_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial Greek"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "GREEK_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial TUR"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "TURKISH_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Arial Black"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Arial Black"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_HEAVY"
-----------------------------------------
decode_str(f["fullName"]) = "Calibri"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Calibri"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Calibri Light"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Calibri Light"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_LIGHT"
-----------------------------------------
decode_str(f["fullName"]) = "Cambria"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Cambria"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Cambria Math"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Cambria Math"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Candara"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Candara"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Comic Sans MS"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Comic Sans MS"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Consolas"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Consolas"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Constantia"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Constantia"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Corbel"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Corbel"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Courier New"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Courier New"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "ANSI_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"
-----------------------------------------
decode_str(f["fullName"]) = "Courier New"
decode_str(f["style"]) = "Regular"
decode_str(f["faceName"]) = "Courier New Baltic"
FontQuality[f["quality"]] = "DRAFT_QUALITY"
FontCharSet[f["charSet"]] = "BALTIC_CHARSET"
FontWeight[f["weight"]] = "FW_NORMAL"

```

Thank you so much guys, really appreciate it.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [June 13, 2019, 12:17pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/7 "2019-06-13T12:17:40Z")

</div>

You’re welcome, glad it worked 😃

I think your `decode_str` would need tweaking for non-ascii chars, and the `replace` probably isn’t quite correct because there may be trailing garbage in the C buffer after the first null character. Perhaps the following would work:

```julia
function decode_str(encoded)
    firstnull = findfirst(c->c==0, encoded)
    transcode(String, collect(encoded[1:(firstnull !== nothing ? firstnull-1 : end)]))
end

```

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 13, 2019, 2:58pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/8 "2019-06-13T14:58:29Z")

</div>

Wow, awesome, it worked perfectly indeed, thank you again @c42f, i’m very happy with Julia.

getting more familiar with it each day

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 23, 2019, 1:12pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/9 "2019-06-23T13:12:25Z")

</div>

Hi guys,

I need your help one more time, not sure if i should create another post, but it is related, it’s not really an issue, but it is related to variable declaration.

This is c++ code to call a Windows API method from `Psapi.dll`

```cpp
HMODULE lphModule;
DWORD lpcbNeeded;
EnumProcessModules( hProcess, &lphModule, sizeof(lphModule), 
             &lpcbNeeded)

```

Here is the method signature

```cpp
BOOL EnumProcessModules(
  HANDLE hProcess,
  HMODULE *lphModule,
  DWORD cb,
  LPDWORD lpcbNeeded // Here, LPDWORD == *DWORD, that's why &cdNeeded is passed above
);

```

Great, i managed to reproduce the same call in Julia like so

```julia
const HANDLE = Ptr{Cvoid}
const HMODULE = Ptr{HANDLE}

const DWORD = Clong
const LPDWORD = Ptr{DWORD}

# the [] acts like a pointer for some reason, it was totally accidental, it worked
init(t::Type{LPDWORD}) = [zero(DWORD)] # the [] acts like a pointer for some reason
init(t::Type{DWORD}) = [zero(DWORD)] # the [] acts like a pointer for some reason
init(t::Type{HMODULE}) = [C_NULL]

lphModule = init(HMODULE) # HMODULE <=> *HANDLE
lpcbNeeded = init(LPDWORD) # LPDWORD <=> *DWORD
hProcess = # this HANDLE is being received from other method call
ccall((:EnumProcessModules, "Psapi"), stdcall, Cint, 
                            (HANDLE, HMODULE, DWORD, LPDWORD), 
                            hProcess, lphModule, sizeof(lphModule), lpcbNeeded)

```

The code above works great, i get the `lphModule::HMODULE` value and can do stuff with it, the Vector syntax […] acts like a pointer for some reason, it makes sense of course, but i really don’t like how i am declaring `lphModule` and `lpcbNeeded` having to use this kind of syntax, and i couldn’t find any other way to do so.

```julia
lphModule = Ptr{HANDLE}(C_NULL) # this doesn't work
lpcbNeeded = Ptr{DWORD}(zero(DWORD)) # or this

```

if you know an elegant way to declare variables in Julia like it was done in c++ i would really appreciate your help.

So, in summary, i really want to do this

```cpp
HMODULE lphModule;
DWORD lpcbNeeded;

```

In Julia, but in a more elegant way.

Thank you guys.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 23, 2019, 1:52pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/10 "2019-06-23T13:52:26Z")

</div>

> [@gabrielfreire](#):
>
> acts like a pointer for some reason

It doesn’t act as a pointer and you don’t want a pointer. You want a piece of memory to get the address of. That’s what you do with

> [@gabrielfreire](#):
>
> ```julia
> HMODULE lphModule;
> DWORD lpcbNeeded;
> 
> ```

in C. That’s why using array works, since the array contains the memory you need but it’s not the best way.

Please read [the document](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Passing-Pointers-for-Modifying-Inputs-1).

Note that there’s no way you can define `lphModule = <initial NULL pointer value>` and expect it to be assigned the pointer value later. It is strictly forbidden in julia and will **never** be possible to do. If you are looking for a `ccall` syntax so that you can do that then you’ll not find it. You can only find alternative to using a vector (see the doc link above). There’s also no reason to use your `init`. It doesn’t really make it more clear especially for anyone that have done similar `ccall`s. You are much better off leaving the creation of the memory as is.

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 23, 2019, 3:49pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/11 "2019-06-23T15:49:12Z")

</div>

Hi @yuyichao, thank you for your reply, you helped me a lot.

i made it work using `Ref{}` like so

```julia
const HANDLE = Ptr{Cvoid}
const HMODULE = Ptr{HANDLE}

const DWORD = Clong
const LPDWORD = Ref{DWORD}

lpcbNeeded = LPDWORD(0) # LPDWORD <=> *DWORD
lphModule = Ref{HMODULE}(0) # HMODULE <=> *HANDLE

ccall((:EnumProcessModules, "Psapi"), stdcall, Cint, 
                            (HANDLE, Ref{HMODULE}, DWORD, LPDWORD), 
                            hProcess, lphModule, sizeof(lphModule.x), lpcbNeeded)

```

It looks much better, but i’m not sure about the correctness of this code.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 23, 2019, 4:58pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/12 "2019-06-23T16:58:23Z")

</div>

> [@gabrielfreire](#):
>
> `sizeof(lphModule.x)`

You should never use `lphModule.x`. You should at least replace it with `lphModule[]`. And in this case you should replace it with the size of the type instead.

---

<div class="post-metadata">

**Author:** ![gabrielfreire](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gabrielfreire/32/8799_2.png) [@gabrielfreire](https://discourse.julialang.org/u/gabrielfreire)\
**Post date:** [June 23, 2019, 5:02pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/13 "2019-06-23T17:02:16Z")

</div>

Done, it works fine and looks much better, thank you 🙂

---

<div class="post-metadata">

**Author:** ![Jesus\_Gomez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jesus_gomez/32/18316_2.png) [@Jesus\_Gomez](https://discourse.julialang.org/u/Jesus_Gomez)\
**Post date:** [October 16, 2020, 10:16pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/14 "2020-10-16T22:16:21Z")

</div>

> [@c42f](#):
>
> transcode

Hello Chris,

Newbie on Julia. After many tries I found this post on windows API ‘ccall’ refering to Julia String.

Have nailed it down to an argument on either ReportEventA or ReportEventW that refers to LPCSTR \*lpStrings and LPCWSTR \*lpStrings respectively.

How do we convert a Julia String to either LPCSTR or LPCWSTR to make it work?

I have been trying to send only one string, but both functions support an array of such messages on the given pointer.

Thanks in advance for the help !

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 18, 2020, 6:55am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/15 "2020-10-18T06:55:44Z")

</div>

> [@Jesus\_Gomez](#):
>
> How do we convert a Julia String to either LPCSTR or LPCWSTR to make it work?

First I suggest you use @musm’s new WinTypes.jl to make it easier to read the windows types: [Home · WinTypes.jl](https://musm.github.io/WinTypes.jl/stable/#Usage-and-Examples)

Then have a look at the following which describes how to pass pointer-to-a-thing [Calling C and Fortran Code · The Julia Language](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Passing-Pointers-for-Modifying-Inputs-1). As a simple example of passing a pointer-to-pointer, we can consider `strtod`:

```julia
julia> x = Ref(Ptr{UInt8}(0))
Base.RefValue{Ptr{UInt8}}(Ptr{UInt8} @0x0000000000000000)

julia> @ccall strtod("12abc"::Cstring, x::Ref{Ptr{UInt8}})::Cdouble
12.0

julia> unsafe_string(x[])
"abc"

```

According to ReportEventW docs at [ReportEventW function (winbase.h) - Win32 apps | Microsoft Learn](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-reporteventw), you need `lpStrings` to be a _pointer_ to LPCWSTR, so that can be annotated as type `Ptr{LPCWSTR}` in the ccall.

Furthermore, to get the LPCWSTR, use `transcode`. I believe it’s like this:

```julia
julia> utf16_str = transcode(UInt16, "ab α")
4-element Array{UInt16,1}:
 0x0061
 0x0062
 0x0020
 0x03b1

julia> lpStrings = Ref(pointer(utf16_str))
Base.RefValue{Ptr{UInt16}}(Ptr{UInt16} @0x00007f61b9a4b4f0)

```

Now you need to pass the `lpStrings` to `ReportEventW`.

Also, be sure to prefix your ccall as `GC.@preserve utf16_str ccall(...)` so that the Julia compiler knows to preserve the object `utf16_str` during the ccall.

---

<div class="post-metadata">

**Author:** ![Jesus\_Gomez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jesus_gomez/32/18316_2.png) [@Jesus\_Gomez](https://discourse.julialang.org/u/Jesus_Gomez)\
**Post date:** [October 19, 2020, 4:45pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/16 "2020-10-19T16:45:51Z")

</div>

Thanks Chris, definitively it was out of my short experience to get to this level.

Will do so and share my results !

Have a great day !

---

<div class="post-metadata">

**Author:** ![Jesus\_Gomez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jesus_gomez/32/18316_2.png) [@Jesus\_Gomez](https://discourse.julialang.org/u/Jesus_Gomez)\
**Post date:** [October 19, 2020, 10:05pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/17 "2020-10-19T22:05:27Z")

</div>

> [@c42f](#):
>
> [Home · WinTypes.jl](https://musm.github.io/WinTypes.jl/stable/#Usage-and-Examples)

Worked like a charm !

Your code snippet should be part of WinTypes.jl examples definitely, specially the GC.preserve() note, that I was not aware of.

Thanks again for the help ! Regards !

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 20, 2020, 6:12am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/18 "2020-10-20T06:12:11Z")

</div>

> [@Jesus\_Gomez](#):
>
> Your code snippet should be part of WinTypes.jl examples definitely

If you could make a fully working example and contribute it to the WinTypes.jl docs, I’m sure that would be appreciated. Feel free to take the code I wrote and adapt it as necessary.

---

<div class="post-metadata">

**Author:** ![Jesus\_Gomez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jesus_gomez/32/18316_2.png) [@Jesus\_Gomez](https://discourse.julialang.org/u/Jesus_Gomez)\
**Post date:** [October 28, 2020, 6:45pm UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/19 "2020-10-28T18:45:11Z")

</div>

Thanks Chris, I will do so.

I found that I have to add “\0” to some string variables before the transcode, else I get additional undesired characters on the event logger.

Seems Julia’s strings do not enforce a terminating null. Am I right or is something else, is it OK to do what I’m doing or a more correct way to fix it?

Thanks again !

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 30, 2020, 3:54am UTC](https://discourse.julialang.org/t/calling-windows-api-from-julia/25123/20 "2020-10-30T03:54:12Z")

</div>

> [@Jesus\_Gomez](#):
>
> Seems Julia’s strings do not enforce a terminating null. Am I right or is something else, is it OK to do what I’m doing or a more correct way to fix it?

Actually the builtin UTF-8 encoded `String` does have a terminating null so that it can be passed as a C string to `ccall` without allocations. But it seems that the result of `transcode` omits this. If the windows APIs typically need null-terminated UTF-16 it could be a reasonable feature request to have an option like `transcode(T, str, null_terminate=true)` — maybe worth opening a github issue.

But in the meantime, it seems that yes, you should use `push!(utf16_str, 0)` if you need null-terminated strings.
