UWP: waveInOpen returns WAVERR_BADFORMAT - c#

I am trying to record audio in UWP using Winmm.dll. After I execute waveInOpen method (https://msdn.microsoft.com/en-us/library/dd743847(v=vs.85).aspx) I always get WAVERR_BADFORMAT no matter the data I use (it also takes a long time abut 5s). My code looks as follows:
Recorder.cs:
Win32.WAVEFORMATEX waveFormatEx = new Win32.WAVEFORMATEX();
waveFormatEx.wFormatTag = (ushort)Win32.WaveFormatFlags.WAVE_FORMAT_PCM;
waveFormatEx.nChannels = 1;
waveFormatEx.nSamplesPerSec = 8000;
waveFormatEx.wBitsPerSample = 16;
waveFormatEx.nBlockAlign = 2;
waveFormatEx.nAvgBytesPerSec = 16000;
Win32.MMRESULT hr = Win32.waveInOpen(ref hWaveIn, deviceId, ref waveFormatEx, delegateWaveInProc, 0, (int)Win32.WaveProcFlags.CALLBACK_FUNCTION);
Win32.cs:
[StructLayout(LayoutKind.Sequential)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
[DllImport("winmm.dll")]
public static extern MMRESULT waveInOpen(ref IntPtr hWaveIn, int deviceId, ref WAVEFORMATEX wfx, DelegateWaveInProc dwCallBack, int dwInstance, int dwFlags);
The same code with the same parameters works just fine in Windows Forms app (and executes in split second), but in UWP app it does't and i have no idea why. What is the correct format i could use in UWP?

While working with UWP projects, you could keep in mind: it is a limited subset of features (for the sake of security and cross-device compatibility). So, UWP project has nothing to do with Win32 API. And even if your code is compiling/running on the emulator, it will:
Fail on ARM devices (as they have no Win32 DLLs for sure)
Fail on app submission to Microsoft Store
So, if we're talking namely about audio, you have to consider WASAPI as it's 100% compatible with UWP https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx

Related

Coredll not found error in Windows 10 mobile enterprise application

We are developing a mobile application which works in Windows 10 mobile enterprise. Now there is a requirement to change the system time to a specific value. We tried the below
[DllImport("coredll.dll", SetLastError = true)]
public static extern bool SetSystemTime(ref SYSTEMTIME st);
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
SYSTEMTIME st = new SYSTEMTIME();
st.wYear = 2018; // must be short
st.wMonth = 6;
st.wDay = 21;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0;
SetSystemTime(ref st);
But it throws coredll is not found. We are using uwp and C# as language.
You could not set the system time in UWP app, And DateTimeSettings API only available in IoT device. I found you want to import coredll.dll static method. Unfortunately, it is not available in UWP . For setting system time within UWP app, there are many roundabout way. For example, you could launch system date setting page then setting time.
var uriDateSetting = new Uri(#"ms-settings:dateandtime");
// Set the option to show a warning
var promptOptions = new Windows.System.LauncherOptions();
promptOptions.TreatAsUntrusted = true;
// Launch the URI
var success = await Windows.System.Launcher.LaunchUriAsync(uriDateSetting, promptOptions);
Using DllImport in UWP app to call Win32 API is kind of hack.
I have found this stackoverflow answer and this blog post.
Firstly, is that you can only call a set of selected API. SetSystemTime is not in the list. Setting system time is a restricted permission, my guess is that the system doesn't grant such a permission to the app.
Secondly, according to the linked answer, the signature of the DllImport API is importing from something like api-ms-win-core-sysinfo-l1-2-0.dll, weird, right?

Can using UnmanagedMemory.LPTStr instead of .ByValTStr result in memory corruption? Why?

We have a tree view in a windows forms app that shows files using the appropriate file icon using the following code. My problem is that call to GetIcon() appears to corrupt my memory as I start getting various program crashes that I can't catch with a debugger after this call.
The program work when I change managedType.LPTStr to managedType.ByValTStr. Is this a true fix or just masking the problem?
This code appeared to be working in our last product release and I can't see anything that has changed. Using .NET 4.0. I only see the issue in Release mode.
[DllImport("Shell32.dll")]
private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbfileInfo, SHGFI uFlags);
[StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
public SHFILEINFO(bool b)
{
hIcon=IntPtr.Zero;
iIcon=0;
dwAttributes=0;
szDisplayName = "";
szTypeName = "";
}
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 260)]//works if .ByValTStr is used instead
public string szDisplayName;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 80)]//works if .ByValTStr is used instead
public string szTypeName;
};
public static Icon GetIcon(string strPath, bool bSmall)
{
SHFILEINFO info = new SHFILEINFO(true);
int cbFileInfo = Marshal.SizeOf(info);
SHGFI flags;
if (bSmall)
flags = SHGFI.Icon|SHGFI.SmallIcon|SHGFI.UseFileAttributes;
else
flags = SHGFI.Icon|SHGFI.LargeIcon|SHGFI.UseFileAttributes;
SHGetFileInfo(strPath, 256, out info,(uint)cbFileInfo, flags);
return Icon.FromHandle(info.hIcon);
}
Well, it's not a proper LPStr in the struct, so you can't try to marshal it as one and expect it to work:
typedef struct _SHFILEINFO {
HICON hIcon;
int iIcon;
DWORD dwAttributes;
TCHAR szDisplayName[MAX_PATH];
TCHAR szTypeName[80];
} SHFILEINFO;
LPTStr you use when you've allocated a special block of memory just to hold this string (usually in a Marshal.AllocHGlobal or similar), then you've copied over your string to that unmanaged memory area.
ByValTStr you use when you are literally passing in the actual string by value, not by reference to another area in memory.
The struct wants the proper value, not a pointer.
I realize this is an old question, but this helped me solve a crash that seemed to suddenly start popping up more often than not. It appears that I started running into these issues after a .NET 4.5.2 update was rolled out via Windows Update. LPTStr worked before the update and ByValTStr worked after.

How do I P/Invoke the dnsapi.dll method: DnsValidateServerStatus

I am not all that familiar with unmanaged code but have been using some of the methods in dnsapi.dll in my C# application. There are lots of examples on how to use DnsQuery, or DnsFlushResolverCache for example, but the method DnsValidateServerStatus seems to be new (requiring Win 7 or Server 2008 R2). I would like to use this method from my C# application but I can't seem to get the Marshaling and structures to work correctly. The documentation for this method can be found at:
http://msdn.microsoft.com/en-us/library/windows/desktop/ee837436(v=VS.85).aspx
Please help!
The difficult part of this Win32 API is the SOCKADDR structure. On PINVOKE.NET there is an implementation of the SOCKADDR structure. The following example is based on this implementation:
[DllImport("Dnsapi.dll")]
private static extern int DnsValidateServerStatus(IntPtr sockaddr, string queryName, ref uint serverStatus);
WinsockSockAddr addr = new WinsockSockAddr(IPAddress.Parse("127.0.0.1"), 0);
uint serverStatus = 0;
int status = DnsValidateServerStatus(addr.PinnedSockAddr, "fqdn server name", ref serverStatus);
Console.Out.WriteLine(status);
Console.Out.WriteLine(serverStatus);
Hope, this helps.
Not sure does it work:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
public struct sockaddr {
/// u_short->unsigned short
public ushort sa_family;
/// char[14]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=14)]
public byte[] sa_data;
}
/// Return Type: DWORD->unsigned int
///server: PSOCKADDR->sockaddr*
///queryName: PCWSTR->WCHAR*
///serverStatus: PDWORD->DWORD*
[System.Runtime.InteropServices.DllImportAttribute("dnsapi.dll", EntryPoint="DnsValidateServerStatus")]
public static extern uint DnsValidateServerStatus([System.Runtime.InteropServices.InAttribute()] ref sockaddr server, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string queryName, [System.Runtime.InteropServices.OutAttribute()] out uint serverStatus) ;
}

C++ DLL function does not seem to work in C#

I have developed a small program using C# and bird.dll, but the birdRS232WakeUp() function seem not to be working.
When I call the birdRS232WakeUp() function in C++ the program will stop for a while (8-10 seconds). It looks like it is beginning to do the process connecting with the hardware (Flock of bird).
But in C#, it does not stop when calling birdRS232WakeUp(). How do I fix this problem?
The C# code is like the following.
[DllImport(#"Bird.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool birdRS232WakeUp(int nGroupID, Boolean bStandAlone, int nNumDevices,
ref ushort[] pwComport, uint dwBaudRate,
uint dwReadTimeout, uint dwWriteTimeout);
ushort[] COM_port = new ushort[]{0,16,0,0,0};
if ((!birdRS232WakeUp(GROUP_ID, false, DEVCOUNT, ref COM_port, BAUD_RATE, READ_TIMEOUT, WRITE_TIMEOUT)))
{
LWakeUpStatus.Text = "Failde to wake up FOB";
}
And the C++ code is looking like the following.
WORD COM_port[5] = {0,15,0,0,0}
if ((!birdRS232WakeUp(GROUP_ID,
FALSE, // Not stand-alone
DEVCOUNT, // Number of Devices
COM_port, // COM Port
BAUD_RATE, // BAUD
READ_TIMEOUT,WRITE_TIMEOUT, // Reponses timeouts
GMS_GROUP_MODE_ALWAYS)))
{
printf("Can't Wake Up Flock!\n");
Sleep(3000);
exit(-1);}
C++ header file for this function:
birdRS232WakeUp(int nGroupID, BOOL bStandAlone, int nNumDevices,
WORD *pwComport, DWORD dwBaudRate, DWORD dwReadTimeout,
DWORD dwWriteTimeout, int nGroupMode = GMS_GROUP_MODE_ALWAYS);
And the manual states that "pwComport" points to an array of words, each of which is the number of the COM port attached to one of the birds (for example, COM1 = 1, COM2 = 2, etc.)
Update 1:
I have taken a suggestion from elder_george, but the problem still exist. I had to change the C# code to the following.
public static extern bool birdRS232WakeUp(int nGroupID, Boolean bStandAlone, int nNumDevices,
ushort[] pwComport, uint dwBaudRate, uint dwReadTimeout,
uint dwWriteTimeout,int nGroupMode);
if ((!birdRS232WakeUp(GROUP_ID, false, DEVCOUNT, COM_port, BAUD_RATE, READ_TIMEOUT, WRITE_TIMEOUT,2)))
{
LWakeUpStatus.Text = "Failde to wake up FOB";
}
BTW, the int nGroupMode is equal to 2, based on the enum type below .
enum GroupModeSettings
{
// GMS_DEFAULT, // Driver will determine whether or not to use RS232 group mode.
GMS_GROUP_MODE_NEVER, // RS232 group mode will never be used
GMS_GROUP_MODE_ALWAYS, // RS232 group mode will always be used
NUM_GROUP_MODE_SETTINGS
};
Not sure if these points will solve your problem, but:
1) pwComport should be declared as ushort[] pwComport, not ref ushort[] pwComport
2) you need to pass nGroupMode parameter from C#. You can set it to default value if you use C#4, but don't ignore it at all.

Using Microsoft Virtual Server from C#: CoSetProxyBlanket does nothing

I'm attempting to write a couple of NAnt tasks for interacting with Microsoft Virtual Server 2005 R2 SP1, and I've lifted the code found on "Virtual PC Guy's WebLog", in the "Controlling Virtual Server through PowerShell" post.
It doesn't work: I always get a failure when calling CreateVirtualMachine:
System.Runtime.InteropServices.COMException (0x80070542): Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
at Microsoft.VirtualServer.Interop.VMVirtualServerClass.CreateVirtualMachine(String configurationName, String configurationPath)
My code is as follows:
var virtualServer = new VMVirtualServerClass();
SetSecurity(virtualServer);
var virtualMachine = virtualServer.CreateVirtualMachine("TEST",
#"D:\Virtual Server\TEST.vmc");
...where SetSecurity is defined as follows:
private static void SetSecurity(object dcomObject)
{
IntPtr pProxy = Marshal.GetIUnknownForObject(dcomObject);
int hr = CoSetProxyBlanket(pProxy,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_DEFAULT,
IntPtr.Zero,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
IntPtr.Zero,
EOAC_DYNAMIC_CLOAKING);
Marshal.ThrowExceptionForHR(hr);
}
private const uint RPC_C_AUTHN_NONE = 0;
private const uint RPC_C_AUTHN_WINNT = 10;
private const uint RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF;
private const uint RPC_C_AUTHZ_NONE = 0;
private const uint RPC_C_AUTHZ_DEFAULT = 0xFFFFFFFF;
private const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0;
private const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6;
private const uint RPC_C_IMP_LEVEL_IDENTIFY = 2;
private const uint RPC_C_IMP_LEVEL_IMPERSONATE = 3;
private const uint EOAC_NONE = 0;
private const uint EOAC_DYNAMIC_CLOAKING = 0x40;
private const uint EOAC_DEFAULT = 0x0800;
[DllImport("Ole32.dll")]
public static extern int CoSetProxyBlanket(IntPtr pProxy,
UInt32 dwAuthnSvc,
UInt32 dwAuthzSvc,
IntPtr pServerPrincName,
UInt32 dwAuthnLevel,
UInt32 dwImpLevel,
IntPtr pAuthInfo,
UInt32 dwCapabilities);
If I write a standalone program and add a call to CoInitializeSecurity, then it works. However, I don't want a standalone program -- I want a set of NAnt tasks (so a DLL), and I don't want to call CoInitializeSecurity, because there's no way of guaranteeing that some other NAnt task won't have called it already.
Has anyone got this working?
It's possible you're running into a fundamental problem with respect to using CoSetProxyBlanket from managed code. Unfortunately, there is no reiable way to interop with this method in managed code due to the way the CLR marshals interfaces.
Here are a couple of blogs entries that describe this problem
http://blogs.msdn.com/mbend/archive/2007/04/18/cosetproxyblanket-not-supported-from-managed-code.aspx
http://blogs.msdn.com/jaredpar/archive/2007/04/19/cosetproxyblanket-and-managed-code.aspx
For what it's worth, it looks like .NET 4.0 will add a new method GetObjectForIUnknownWithBlanket (under System.Runtime.InteropServices.Marshal) to help address this issue. From the (Beta) MSDN article:
GetObjectForIUnknownWithBlanket wraps
IUnknown in a unique managed object
and calls the CoSetProxyBlanket
function on all requested interfaces.
It ensures that a unique object is
returned instead of looking in the
cache to match the given IUnknown to
an existing object.
I haven't tried it yet, but it looks promising.
And by the way, great question and great accepted answer! I just encountered the same problem, and this was the only place I found a proper explanation.

Categories