- Troubleshooting calls in the Your Phone app
- Some apps may be interfering with making calls. What does this mean?
- Why doesn’t calls doesn’t work after changing my Android device name?
- Why can’t I use my Bluetooth headphone on my PC to get calls from the Your Phone app?
- Can I choose which SIM to use with calling if I have dual SIM capability on my Android device?
- I’m experiencing audio quality issues while making calls
- Call a phone number from Teams
- Breaking all the rules: Using Go to call Windows API
- The “syscall” package
- Let’s talk about “unsafe”
- The Windows API
- Loading DLLs
- Calling Procedures
- API Call Signatures
- C Structs & Go Structs
- Strings
- Calling the API
- Raw Memory
- Working with ANY_SIZE arrays
- Now you can Win32!
Troubleshooting calls in the Your Phone app
There are a few common issues that can prevent calling from working. To troubleshoot, start by trying this:
Make sure F ocus assist is turned off. To do this: right click the Action Center icon on the taskbar, select Focus Assist, then Off.
Close the Your Phone app and reopen it.
If none of above work, please reboot your PC.
On your Android device:
Turn Bluetooth off and on again. To do this, swipe downward from the top of your screen to reveal the Android Notification panel, tap the Bluetooth icon to turn it off/on.
If calling still isn’t working, continue on to additional troubleshooting below.
Your Android device and PC may have failed to automatically connect via Bluetooth. From your Android device, try to connect your devices manually by:
Swiping downwards from the top of your screen to reveal the Android Notification panel. Tap and hold the Bluetooth icon.
A list of nearby devices will be displayed. Locate the name of your PC in this list and tap on it.
You should see notifications on both your Android device and Windows 10 PC. Tap or click on these toasts to confirm.
The connection process should now be complete, and you’ll be able to use the Calls feature.
If you’re still unable to use Calls, make sure the Your Phone app on your PC is closed, then do the following:
On your Android device:
Open your device Settings.
Tap Connected devices > Connection preferences > Bluetooth.
Make sure Bluetooth is turned On.
Next to the paired device that you’d like to change, tap Settings.
Select Unpair (or ‘forget’).
Select Start > Settings > Devices > Bluetooth & other devices.
Select your Android device from the list.
Select Remove device.
Confirm the removal.
If there’s another entry for your Android device, make sure you unpair it, too, by following steps 2-4. Make sure your Android device is not on the list.
Open the Your Phone app and set up Calls again.
For some Android devices, your Battery Optimization settings may interrupt your connection. We recommend turning it off for the companion app on your Android device (either Your Phone Companion or Link to Windows). Here’s how to turn it off based on which companion app you have:
If you have Your Phone Companion*:
Open Android Settings > Apps & notifications > App info > Your Phone Companion > Advanced > Battery > Manage Battery Usage > Battery optimization. Scroll down to Your Phone Companion and select Don’t optimize.
If you have Link to Windows*:
Open Android Settings > Apps > Link to Windows Service > Battery > Optimize battery usage. Select All from the drop-down list, scroll to find Link to Windows service, and turn the toggle Off.
*Note: These steps may vary based on your Android device model.
Some apps may be interfering with making calls. What does this mean?
This error is appearing because you may have paired your Android device to your PC with a third-party app, or your devices may be paired through a pre-installed app from your hardware manufacturer (like Dell Mobile Connect or Virtoo by LG). Some of these apps conflict with being able to make calls, so we recommend uninstalling them, then unpairing your Android device and pairing it again with Calls.
To uninstall apps, go to Windows Settings > Apps > Apps & features. Select the app you want, then Uninstall.
To unpair your Android device from your PC, go to your Windows Settings > Devices > Bluetooth & other devices > Other devices. Select your device from the list, then Remove device. Then, in the Your Phone app, go to Calls and pair your devices again.
Why doesn’t calls doesn’t work after changing my Android device name?
Start by unpairing your Android device from your PC. Go to Start > Settings > Devices > Bluetooth & other devices > Other devices). In your Android device settings (typically under the About your device page), change the name to the one you want. Then, go back to your PC’s Bluetooth settings and pair your phone again to establish the connection with your phone’s updated name.
Why can’t I use my Bluetooth headphone on my PC to get calls from the Your Phone app?
The Your Phone app does not currently support relaying a phone call from your Android device to a headset over Bluetooth.
Can I choose which SIM to use with calling if I have dual SIM capability on my Android device?
The Your Phone app doesn’t support dual SIM options. Your call will be placed or received using your primary SIM.
I’m experiencing audio quality issues while making calls
There are a few things you can do to improve your audio connection while making calls:
If you’re using a Bluetooth mouse or accessory and experiencing poor quality during a call, try temporarily disconnecting it to see if your audio quality improves.
If you’re experiencing a bad echo, try using a wired headset to improve the experience.
Call a phone number from Teams
To dial a number from Teams, go to Calls , click Dial a number, and then enter the number of the person you want to reach by using the dial pad. Then click Call
.
Important: You won’t be able to make a 911 emergency call if Teams isn’t connected to the internet.
Note: If you don’t see the option to dial a number, your org may not have purchased a calling plan. But you can still make calls to other people in Teams.
Here are a few other ways to make a call:
If the person you want to reach is in your contacts list, click Contacts, find the person you want to call, and then click Call .
If you’ve called people before (or if they’ve called you), they’ll be in your call history. In History, select More actions to the right of the person’s name, then click Call back.
You can also access your voicemail and call people from that list. In Voicemail, select More actions to the right of the person’s name, then click Call back.
To access your dial pad during a call, go to your call controls and select Keypad .
To make a call, tap Calls >
and enter a phone number. If you’ve enabled the setting to allow access to your phone contacts, tap Calls
> Contacts
and select the person you want to call.
Use the dial pad on your mobile device to dial numbers from your personal phone number and to make emergency calls to your country-specific emergency number.
Note: If you don’t see the option to dial a number, your org may not have purchased a calling plan. But you can still make calls to other people in Teams.
Important: You won’t be able to make a 911 emergency call if Teams isn’t connected to the internet.
To call a phone number (PSTN) from the Surface Hub, touch Call from the welcome screen, and then tap Dial Pad.
Once you’ve accessed the dial pad, just enter the number you want to call.
Breaking all the rules: Using Go to call Windows API
Jan 15, 2019 · 10 min read
In creating Damon, the supervisor application that constrains Jet’s Windows microservices in Nomad, we had to interact directly with the Windows API. The Windows API grants access to the more advanced features of the OS, including creation and configuration of JobObjects and Security Token manipulation. Fortunately, Go provides a way to talk to the OS via the syscall package. Unfortunately, in order to make use of most of the APIs, we need to rely on unsafe memory management.
What I’ll try to do in this post is document some patterns that we discovered when writing Damon for interacting with the Windows API, so that you have a starting point if you find yourself in this situation.
The “syscall” package
The Go syscall library is different depending on the OS / architecture which the Go compiler is targeting. Because the functions and types available change depending on the compilation target, you MUST ALWAYS use Conditional Compilation with either build tags or special file name suffixes when importing syscall . Dave Cheney has a nice Blog Post explaining this feature in depth, but in short:
- If your file name follows the structure name_
_ .go or simply name_ .go , then it will be compiled only under the target OS+architecture or OS+any architecture respectively without needing a special comment. For example; myfile_windows_amd64.go will only be compiled for binaries targeting Windows OS on amd64 CPU architectures, whereas a file named myfile_windows.go will be compiled for binaries targeting the Windows OS regardless of CPU architecture. - If you add // +build windows,amd64 at the top of your go file, it will only build this source file when GOOS=windows and GOARCH=amd64 . This supports more complicated boolean logic than the file suffix variant, although that complexity is usually not warranted.
Let’s talk about “unsafe”
Actually, lets have Rob Pike talk about it first:
With the unsafe package there are no guarantees.
What does “no guarantees” mean?
- Go (the runtime) does not guarantee go built-in types such as slices and strings will have the same in-memory structure between releases. As a Garbage-collected language, Go also hides memory management details from the developer. unsafe exposes some of the inner-workings and actual memory addresses, and can do unexpected things like move the values that a raw pointer address may point to if you are not careful (and some times — even if you are).
- Go (the language) does not guarantee that versions of Go will have the same behavior or function signatures between releases. In other words, unsafe is not covered by the Go 1.x compatibility promise.
Warning: Avoid unsafe like the plague; if you can help it.
Both of these things mean that, when using features of the unsafe package, we have to be very careful about how we use it. We must read what is and is not allowed by Go when interacting with memory in an unsafe way; and this may even change between versions of Go! The Godoc page has a lot of examples of what IS and IS NOT valid that should be heeded always.
Note: Technically, syscall is also outside the Go 1.x compatibility promise, since it is impossible to guarantee that an OS will never change in a backwards-incompatible way. However, as of Go 1.4 — the library is frozen and should only change if an underlying OS change forces it. Calling exported Windows DLL procedures is unlikely to change, so we should be reasonably safe.
Any evolution of Windows OS system calls in Go 1.x is now done in golang.org/x/sys/windows . This package defines a variety of API functions that allow you to take advantage of the collective work & knowledge of the Go team and contributors. However, using this package comes with a few caveats:
- It is also not under the go1compat promise, and so may break your code if you depend on it. Still, you can pin to a specific git revision if you want to remain stable.
- The stated goal of the package is not to expose every Windows API function, but serve as a dependency for OS-specific implementations needed in standard library packages such as os and net since syscall is frozen. Therefore, neither this package, nor syscall will likely be feature-complete with respect to all OS functionality you may require.
That being said, if it has implemented all the functions and types you need, Fantastic! Use It, but know the risks.
The Windows API
Microsoft provides documentation for much of the Windows API. APIs are published via DLLs delivered with each installation of the Windows OS. The specific DLLs and API Functions available depend on the version of Windows, but the API documentation will list when the API was introduced and also when the API was deprecated/removed.
Loading DLLs
To Load a DLL in Go, you can use syscall.NewLazyDLL or syscall.LoadLibrary . The “Lazy” variant returns a *LazyDLL which only loads the library the first time a call is made to one of its functions; whereas LoadLibrary immediately loads the DLL. There also exists safe DLL loading methods in golang.org/x/sys/windows such as windows.NewLazySystemDLL which ensures that the DLL search path is constrained to the Windows System directory.
Calling Procedures
After the DLL is loaded (or lazy-loaded), you then must get a reference to the the Procedure using dll.NewProc(«ProcName») .
Once you have some variable that references the DLL procedure, you can make the API call using either the Call method on the procedure itself, or using the syscall.Syscall function (and variants thereof). I find the Call method more convenient, but for performance it might be better to use syscall.Syscall directly. There are variants of this function depending on how many parameters the procedure requires (its “arity”).
- syscall.Syscall : less than 4 arguments
- syscall.Syscall6 : 4 to 6 arguments
- syscall.Syscall9 : 7 to 9 arguments
- syscall.Syscall12 : 10 to 12 arguments
- syscall.Syscall15 : 13 to 15 arguments
As recent as Go v1.11, it is not possible to call a procedure with more than 15 arguments. I’ve never encountered one, but they do exist in OpenGL at least.
API Call Signatures
Before you can actually make a call to a DLL procedure, you must first understand the arguments, types, and sizes of the arguments the procedure expects. Microsoft describes this as part of the Windows API Documentation. For example, the call signature for CreateJobObjectA is:
This means, that CreateJobObjectA expects a pointer to a SECURITY_ATTRIBUTES structure, and a pointer to a C-String (ASCII-encoded, Technically Windows-1252 encoded; which is ASCII-compatible).
C Structs & Go Structs
The SECURITY_ATTRIBUTES structure is defined as:
So we have to make a Go structure that mirrors that. Fortunately, the syscall package already made one for us.
From this, we know that a DWORD is a Go uint32, and a LPVOID (*void) is a Go uintptr. For structures that do not exist, you have to look up what the type definitions are and fill in the correct go type. You can find many examples in the syscall and go.sys libraries to help you out. Windows has a types reference available which I’ve found quite useful in determining the analogous Go types for a few of the more common Windows C-Types:
Strings
In Windows, some procedures which take string arguments have two variants: one for ANSI-encoded, and one for UTF-16 encoded strings. For example, there are two CreateProcess procedures in kernel32.dll :
Regardless of which you choose, neither of these string types are directly compatible with Go strings. In order to use them, you’ll need to construct compatible strings. Fortunately, this is relatively easy.
For ANSI-encoded C strings, it is the raw string bytes with an addition null value appended to the end. With UTF-16 Strings, you have to ensure it is encoded properly to UTF-16 runes, and add a null rune as well; but it’s pretty much the same thing for both.
Calling the API
Putting it all together, creating a JobObject using the Windows API looks like this:
Calling any API follows this same formula.
The syscall.Syscall function always returns (r1,r2,err uintptr) . Near as I can tell, for windows_amd64 : r1 is always the return value of the syscall, r2 is unused, and err refers to the Windows error code returned by GetLastError , which is automatically called as part of the Syscall function.
You must pass each argument in casted to a uintptr . No matter what the primitive type, every argument has to be treated this way. However, pointers are special.
Since Go is garbage collected, Standard Go pointers do not directly point to a place in memory. The go runtime is free to change the physical memory location pointed at by a Go pointer, such as when it grows the stack. When a pointer is converted into a raw uintptr via unsafe.Pointer — it becomes just a number untracked by the Go runtime. That number may or may not point to a valid location in memory like it once did, even after the very next instruction!
Because of this, you have to call Syscalls with pointers to memory in certain way. By using the uintptr(unsafe.Pointer(&x)) construction in the argument list, you signal to the compiler that it can’t change the memory location for the duration of the syscall; thereby giving the C function the ability to treat the pointer like any other pointer to unmanaged memory until the Syscall returns.
The ways in which you can and cannot use unsafe.Pointers are documented in the godoc for unsafe.Pointer. In this instance, we are using use-case (4) “Conversion of a Pointer to a uintptr when calling syscall.Syscall ”
Raw Memory
Some times, the syscalls will fill a block of memory for you with C structures. In order to work with it, you’ll have to convert it into a usable type.
The general pattern for many of these API calls are as follows:
- Allocate a byte buffer
- Make an API call with a pointer to that buffer, and a pointer to the variable containing the length of the buffer
- API returns ERROR_INSUFFICIENT_LENGTH, having updated the value of the length parameter to the required size.
- Extend the buffer to meet the new length requirement, and retry the syscall
- Repeat until Success
Here is a concrete example calling GetExtendedTcpTable
Once you have this buffer, You need to unsafe cast it into a structure of the appropriate type, depending on what the API documentation says. In this example, the type of the bytes returned depends heavily on what the input parameters were. For example, if the input parameters were AF_INET + TCP_TABLE_OWNER_PID_ALL, then the buffer returned would be a MIB_TCPTABLE_OWNER_PID structure:
Which is a structure with a first element containing the number of Rows in the structure, and the rest is an in-line array of arbitrary size. Oh boy… how do we represent that in Go?
Working with ANY_SIZE arrays
We can create a compatible Go structure for casting this arbitrary array of bytes by using a property of arrays: they are laid out as contiguous blocks of memory with no envelope.
First, we need to cast our buffer into this go type, in order to know the length of the table. We do this using unsafe.Pointer
What I’ve done here is get a pointer to the first byte of memory. Since I now have a pointer type, I can convert it into an unsafe.Pointer which can be coerced into a pointer of ANY ARBITRARY TYPE. This is extremely dangerous to do without knowing why you are allowed to do it. I’m allowed to do it in this case because I’m using the established pointer conversion pattern documented in unsafe.Pointer
(1) Conversion of a *T1 to Pointer to *T2.
Provided that T2 is no larger than T1 and that the two share an equivalent memory layout, this conversion allows reinterpreting data of one type as data of another type.
Now, I know what you’re thinking: The table [1]_MIB_TCPROW_OWNER_PID is obviously not the correct size. But that is OK: [1]_MIB_TCPROW_OWNER_PID is indeed no larger than [1+N]_MIB_TCPROW_OWNER_PID and does have the same memory layout. We’ll be using another unsafe.Pointer pattern to traverse the array, already knowing the size from dwNumEnties field.
(3) Conversion of a Pointer to a uintptr and back, with arithmetic.
In this code fragment, we’re using the 3rd acceptable unsafe.Pointer rule to iterate through an array of known length since we know the location of the first element, the size of each element, how many elements exist in the array, and also that each structure is laid out contiguously in memory.
This allows us to construct a more useful slice data structure, or work with each row directly in the for loop.
There is also a more direct way of getting a slice of the correct length
This technique unsafe-casts the pointer to the first table entry into a pointer to a very large array of the same type. It then creates a slice backed by that array using the correct length & capacity. The benefit of this method is that this all happens in-place; there is no need to copy the structs into a new slice. The drawback is that it is not as portable as the other method; since maximum array size differs depending on the target platform.
You can play around with a toy example of this in the Go Playground.
Now you can Win32!
This is not all you need to know to interact with every Windows API, but this should be a good starting point for learning more about inter-operating with the Windows API using Go. If you’d like to apply what you’ve learned, the Damon project could use another contributor 😀.
If you like the challenges of building complex & reliable systems and are interested in solving complex problems, check out our job openings.