I'm using waveOutWrite to write several small buffers (80ms each). As they are playing, I'm calling this function to get the playback position:
uint GetWaveOutPosInMS()
{
WinMM.MMTIME mmtime = new WinMM.MMTIME();
mmtime.wType = 1;
WinMM.MMRESULT ret = WinMM.waveOutGetPosition(WaveOut, ref mmtime, (uint)Marshal.SizeOf(typeof(WinMM.MMTIME)));
return (mmtime.val);
}
Here are the relative extras as well:
[DllImport("winmm.dll")]
public static extern MMRESULT waveOutGetPosition(IntPtr hwo, ref MMTIME info, uint cbi);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MMTIME
{
public uint wType;
public uint val;
}
The waveOutGetPosition returns 0 (no error), but mmtime.val is always zero. MSDN isn't really clear on what "playback position" is relative to, just that it is reset on waveOutOpen and waveOutReset.. but does it always continue to increase across multiple waveOutWrite() calls? Any ideas as to why it would always be returning zero for me?
I had the MMTIME struct declared incorrectly. Odd that the function didn't report error, but based on other stuff I've read this function is dependant on the OEM so could see various weird results. It also appears asking for MS isn't as well tested as asking for SAMPLES, so I'll just ask for samples instead, and calculate MS myself.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MMTIME
{
public uint wType;
public uint val;
// Padding because val is actually a union
public uint pad;
}
Related
If I create a File handle using CreateFile for a path like "\\?\NUL" or "\\?\pipe\", the handle is mapped to a File object that's opened for the "\Device\Null" or "\Device\NamedPipe" kernel Device object. Since the GetFinalPathNameByHandle function supports the VOLUME_NAME_NT property, which already returns strings like "\Device\HarddiskVolume1\", I thought I would be able to obtain a similar path for a device handle. However, the call always fails, either with ERROR_INVALID_FUNCTION, or ERROR_INVALID_PARAMETER, depending on the access flags the file was opened with.
In fact, almost any call to similar functions fails -- like GetFileInformationByHandle, GetFileInformationByHandleEx, and even calls to NT functions like NtQueryInformationFile -- returning STATUS_INVALID_PARAMETER. The only functions that don't fail are GetFileType (able to identify a pipe), GetVolumeInformationByHandle (able to identify the driver), and NtQueryInformationFile with FileModeInformation.
All these functions work when used on any standard file, but they are not supported for device file handles. How can I obtain path information from a device handle? Are there some Nt or Io functions that would work? Is there some other way to identify a device if the only thing I have is the handle?
As RbMm and eryksun have pointed out, the driver which implements the object must be able to handle IRP_MJ_QUERY_INFORMATION, but if it doesn't, the name of the object can be obtained via NtQueryObject, passing ObjectNameInformation (1) to it, which will obtain the OBJECT_NAME_INFORMATION structure with the object name.
Since I intended to call it with C#, here is the P/Invoke code for it:
static class Ntdll
{
[DllImport("ntdll.dll")]
static extern int NtQueryObject(
IntPtr Handle, int ObjectInformationClass,
IntPtr ObjectInformation, int ObjectInformationLength,
out int ReturnLength
);
public static int NtQueryObject(IntPtr Handle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength)
{
int length;
int status = NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, out length);
if(status != 0) throw new Win32Exception(RtlNtStatusToDosError(status));
return length;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct OBJECT_NAME_INFORMATION
{
public ushort Length;
public ushort MaximumLength;
public string Buffer;
}
[DebuggerStepThrough]
public static void NtQueryObject(IntPtr Handle, out OBJECT_NAME_INFORMATION ObjectNameInformation)
{
IntPtr buffer = Marshal.AllocHGlobal(1024);
try{
Ntdll.NtQueryObject(Handle, 1, buffer, 1024);
ObjectNameInformation = Marshal.PtrToStructure<Ntdll.OBJECT_NAME_INFORMATION>(buffer);
}finally{
Marshal.FreeHGlobal(buffer);
}
}
}
The path can be then constructed by prepending "\\?\GlobalRoot" to the Buffer member.
I'm writing a profiler that queries a timer whenever a function enters or exits. So it's possible that it's queried thousands of times a second.
Initially I used QueryPerformanceCounter, despite the fact it's high resolution, it turned out to be quite slow. According to What happens when QueryPerformanceCounter is called? question I also got a noticeable slowdown when I use QPC in the profiler, but probably not that bad 1-2ms figure. If I replace it with GetTickCount I don't notice any slowdown, but that function is inaccurate for the profiling.
The mentioned question mention affinity masks. I tried to use SetProcessAffinityMask(GetCurrentProcess(), 1) to bind it but it doesn't improve the performance at all.
I don't know whether it matters or not, but so far I tested it on Windows that runs in VirtualBox on a Linux host. Could it be the problem?
The highest resolution timers I'm aware of on Windows are the multimedia timers available via winmm.dll
Here's a class I've had lying around for my own perf testing needs - give 'er a whirl:
public class HighResTimer
{
private delegate void TimerEventHandler(int id, int msg, IntPtr user, int dw1, int dw2);
private const int TIME_PERIODIC = 1;
private const int EVENT_TYPE = TIME_PERIODIC;
[System.Runtime.InteropServices.DllImport("winmm.dll")]
private static extern int timeSetEvent( int delay, int resolution, TimerEventHandler handler, IntPtr user, int eventType);
[System.Runtime.InteropServices.DllImport("winmm.dll")]
private static extern int timeKillEvent(int id);
[System.Runtime.InteropServices.DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int msec);
[System.Runtime.InteropServices.DllImport("winmm.dll")]
private static extern int timeEndPeriod(int msec);
private int _timerId;
private TimerEventHandler _handler = delegate {};
public event EventHandler OnTick;
public HighResTimer(int delayInMs)
{
timeBeginPeriod(1);
_handler = new TimerEventHandler(timerElapsed);
_timerId = timeSetEvent(delayInMs, 0, _handler, IntPtr.Zero, EVENT_TYPE);
}
public void Stop()
{
int res = timeKillEvent(_timerId);
timeEndPeriod(1);
_timerId = 0;
}
private void timerElapsed(int id, int msg, IntPtr user, int dw1, int dw2)
{
OnTick(this, new EventArgs());
}
}
Ended up using the RDTSC instruction directly. So I wrote a wrapper for it in GCC:
static inline unsigned long long rdtsc(void)
{
unsigned hi, lo;
asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
No slowdowns and apparently have quite higher resolution than QueryPerformanceCounter.
The code based on this answer.
The Window-Procedure in the Win32 API must be static \ global function since it cannot take a class-object (the this) parameter. One can of-course use workarounds like a hWnd->object dictionary and such.
I wonder if D has a way to elegantly solve it, like create a tiny member function copy for each object (to call the object's real handler) or anonymous function that I can assign to WNDCLASS.lpfnWndProc (I know there are anonymous functions, but I cannot use the extern(Windows) property on them) ?
Can I do something like this :
class Window {
extern (Windows)
LRESULT delegate (HWND hWnd, UINT msg, WPARAM w, LPARAM l) MyWinProcDelegate;
this() {
MyWinProcDelegate = &Events;
}
extern (Windows)
LRESULT Events (HWND hWnd, UINT msg, WPARAM w, LPARAM l) {
MessageBoxA(null , "Success!!!" , null ,0);
return DefWindowProcA(hWnd, message, wParam, lParam);
}
}
(Omitting the registration\creation\msg-loop...)
The Events() doesn't seem to fire... am I missing something ?
Here I made this for you (based on BCS' answer):
version (Windows)
{
import std.c.windows.windows;
void makeExecutable(ubyte[] code)
{
DWORD old;
VirtualProtect(code.ptr, code.length, PAGE_EXECUTE_READWRITE, &old);
}
}
else
version (linux)
{
import core.sys.posix.sys.mman;
import core.sys.posix.unistd;
static if (!is(typeof(&mprotect)))
extern(C) int mprotect(void*, size_t, int);
void makeExecutable(ubyte[] code)
{
auto pageSize = sysconf(_SC_PAGE_SIZE);
auto address = ((cast(size_t)code.ptr) & ~(pageSize-1));
int pageCount =
(address/pageSize == (address+code.length)/pageSize) ? 1 : 2;
mprotect(cast(void*)address, pageSize * pageCount,
PROT_READ | PROT_WRITE | PROT_EXEC);
}
}
else
static assert(0, "TODO");
R function(A) delegate2function(R, A...)(R delegate(A) d)
{
enum size_t TEMPLATE1 = cast(size_t)0x01234567_01234567;
enum size_t TEMPLATE2 = cast(size_t)0x89ABCDEF_89ABCDEF;
static R functionTemplate(A args)
{
R delegate(A) d;
d.ptr = cast(typeof(d.ptr ))TEMPLATE1;
d.funcptr = cast(typeof(d.funcptr))TEMPLATE2;
return d(args);
}
static void functionTemplateEnd() {}
static void replaceWord(ubyte[] a, size_t from, size_t to)
{
foreach (i; 0..a.length - size_t.sizeof + 1)
{
auto p = cast(size_t*)(a.ptr + i);
if (*p == from)
{
*p = to;
return;
}
}
assert(0);
}
auto templateStart = cast(ubyte*)&functionTemplate;
auto templateEnd = cast(ubyte*)&functionTemplateEnd;
auto templateBytes = templateStart[0 .. templateEnd - templateStart];
// must allocate type with pointers, otherwise GC won't scan it
auto functionWords = new void*[(templateBytes.length / (void*).sizeof) + 3];
// store context in word-aligned boundary, so the GC can find it
functionWords[0] = d.ptr;
functionWords[1] = d.funcptr;
functionWords = functionWords[2..$];
auto functionBytes = (cast(ubyte[])functionWords)[0..templateBytes.length];
functionBytes[] = templateBytes[];
replaceWord(functionBytes, TEMPLATE1, cast(size_t)d.ptr );
replaceWord(functionBytes, TEMPLATE2, cast(size_t)d.funcptr);
makeExecutable(functionBytes);
return cast(typeof(return)) functionBytes.ptr;
}
void main()
{
import std.stdio;
auto context = 42;
void del(string s)
{
writeln(s);
writeln(context);
}
auto f = delegate2function(&del);
f("I am a pretty function");
}
Tested on Windows 32-bit and Linux 64-bit.
How about storing this in the window itself, with SetWindowLong?
One very un-portable solution would be to dynamically create a function that wraps the call. I would do this by writing a function that looks like this:
extern(C) RetType TestFn(Arg arg /* and any others */) {
Class c = cast(Class)(0xDEAD_BEEF);
return c.Method(arg);
}
You can then compile this function as un-optimized PIC, de-compile it, and find a byte sequence that can be mashed into what you need. The end result would be a type (likely a struct) that has a methoud returning a function pointer and that, when constructed, populates an internal void array with the bytes you found from the above step and pokes the object in question into the appropriate places.
A slightly more advanced solution would populate a delegate with both the object and the method pointer so both can be provided to the constructor. An even more advanced solution would template the type and take advantage of knowledge of the C and D calling conventions to dynamically generate the argument forwarding code.
I have got following code:-
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char ay[256]={0};//HWND hwnd= GetForegroundWindow();
if( GetClassName(hwnd,ay,256))
{
char x[70]={0};
GetWindowText(hwnd,x,70);
if(IsWindowVisible(hwnd))
{
// CaptureAnImage(hwNd,hwnd);
HINSTANCE hins= (HINSTANCE) GetWindowLong(hwnd,GWL_HINSTANCE);
WNDCLASSEX lpwcx;
GetClassInfoEx(hins,ay,&lpwcx);
if (MessageBox(0,
strcat(strcat(x, "\r\n"), lpwcx.lpszClassName),
"Info", 0x06L) == IDTRYAGAIN)
{
return false;
}
}
}
return true;
}
void cstm()
{
EnumWindows(EnumWindowsProc,0);
}
This runs fine on Codeblocks (with VS 2010 compiler(cl)) but VS2010 gives a corrupted lpwcx value, I have tried the Unicode as well as Ascii to tackle this but no good result at
all. The first lpwcx is correct but later they return class not found(1411) ,although the hinstance and class name is correct.
Please help.
strcat(strcat(x, "\r\n"), lpwcx.lpszClassName),
The odds that this will overflow the x buffer and stomp some local variable values, like *lpwcx", are very high. 70 chars is unreasonably frugal. If you don't want to use strcat_s() then at least make it bigger. And yes, initialize lpwcx.cbSize
Always fill in the cbSize member of data blocks before calling any API functions. Many of them rely upon this value to know which version of the data structure they should fill in.
I can display and select a single file in windows explorer like this:
explorer.exe /select, "c:\path\to\file.txt"
However, I can't work out how to select more than one file. None of the permutations of select I've tried work.
Note: I looked at these pages for docs, neither helped.
https://support.microsoft.com/kb/314853
http://web.archive.org/web/20100716112458/http://www.infocellar.com:80/Win98/explorer-switches.htm
This should be possible with the shell function SHOpenFolderAndSelectItems
EDIT
Here is some sample code showing how to use the function in C/C++, without error checking:
//Directory to open
ITEMIDLIST *dir = ILCreateFromPath(_T("C:\\"));
//Items in directory to select
ITEMIDLIST *item1 = ILCreateFromPath(_T("C:\\Program Files\\"));
ITEMIDLIST *item2 = ILCreateFromPath(_T("C:\\Windows\\"));
const ITEMIDLIST* selection[] = {item1,item2};
UINT count = sizeof(selection) / sizeof(ITEMIDLIST);
//Perform selection
SHOpenFolderAndSelectItems(dir, count, selection, 0);
//Free resources
ILFree(dir);
ILFree(item1);
ILFree(item2);
The true way of selecting multiple files in Explorer is the next
Unmanaged code looks like this (compiled from China code posts with fixing its bugs)
static class NativeMethods
{
[DllImport("shell32.dll", ExactSpelling = true)]
public static extern int SHOpenFolderAndSelectItems(
IntPtr pidlFolder,
uint cidl,
[In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
uint dwFlags);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ILCreateFromPath([MarshalAs(UnmanagedType.LPTStr)] string pszPath);
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
public interface IShellLinkW
{
[PreserveSig]
int GetPath(StringBuilder pszFile, int cch, [In, Out] ref WIN32_FIND_DATAW pfd, uint fFlags);
[PreserveSig]
int GetIDList([Out] out IntPtr ppidl);
[PreserveSig]
int SetIDList([In] ref IntPtr pidl);
[PreserveSig]
int GetDescription(StringBuilder pszName, int cch);
[PreserveSig]
int SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
[PreserveSig]
int GetWorkingDirectory(StringBuilder pszDir, int cch);
[PreserveSig]
int SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
[PreserveSig]
int GetArguments(StringBuilder pszArgs, int cch);
[PreserveSig]
int SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
[PreserveSig]
int GetHotkey([Out] out ushort pwHotkey);
[PreserveSig]
int SetHotkey(ushort wHotkey);
[PreserveSig]
int GetShowCmd([Out] out int piShowCmd);
[PreserveSig]
int SetShowCmd(int iShowCmd);
[PreserveSig]
int GetIconLocation(StringBuilder pszIconPath, int cch, [Out] out int piIcon);
[PreserveSig]
int SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
[PreserveSig]
int SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
[PreserveSig]
int Resolve(IntPtr hwnd, uint fFlags);
[PreserveSig]
int SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), BestFitMapping(false)]
public struct WIN32_FIND_DATAW
{
public uint dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
public static void OpenFolderAndSelectFiles(string folder, params string[] filesToSelect)
{
IntPtr dir = ILCreateFromPath(folder);
var filesToSelectIntPtrs = new IntPtr[filesToSelect.Length];
for (int i = 0; i < filesToSelect.Length; i++)
{
filesToSelectIntPtrs[i] = ILCreateFromPath(filesToSelect[i]);
}
SHOpenFolderAndSelectItems(dir, (uint) filesToSelect.Length, filesToSelectIntPtrs, 0);
ReleaseComObject(dir);
ReleaseComObject(filesToSelectIntPtrs);
}
private static void ReleaseComObject(params object[] comObjs)
{
foreach (object obj in comObjs)
{
if (obj != null && Marshal.IsComObject(obj))
Marshal.ReleaseComObject(obj);
}
}
}
it cannot be done through explorer.exe
Depending on what you actually want to accomplish you may be able to do it with AutoHotKey. It is an amazing free tool for automating things you normally can't do. It should come with Windows. This script will select your file and highlight the next two files below it when you hit F12.
F12::
run explorer.exe /select`, "c:\path\to\file.txt"
SendInput {Shift Down}{Down}{Down}{Shift Up}
return
It is also possible to just put those two middle lines in a text file and then pass it is a parm to autohotkey.exe. They have an option to compile the script also, which would make it a standalone exe that you could call. Works great with a great help file.
#Orion, It is possible to use autohotkey from C#. You can make an autohotkey script into a standalone executable (about 400k) that can be launched by your C# app (just the way you are launching explorer). You can also pass it command line parameters. It does not have any runtime requirements.
There are COM Automation LateBinding IDispatch interfaces, these are easy to use from PowerShell, Visual Basic.NET and C#, some sample code:
$shell = New-Object -ComObject Shell.Application
function SelectFiles($filesToSelect)
{
foreach ($fileToSelect in $filesToSelect)
{
foreach ($window in $shell.Windows())
{
foreach ($folderItem in $window.Document.Folder.Items())
{
if ($folderItem.Path -eq $fileToSelect)
{
$window.Document.SelectItem($folderItem, 1 + 8)
}
}
}
}
}
-
Option Strict Off
Imports Microsoft.VisualBasic
Public Class ExplorerHelp
Shared ShellApp As Object = CreateObject("Shell.Application")
Shared Sub SelectFile(filepath As String)
For Each i In ShellApp.Windows
For Each i2 In i.Document.Folder.Items()
If i2.Path = filepath Then
i.Document.SelectItem(i2, 1 + 8)
Exit Sub
End If
Next
Next
End Sub
End Class
https://learn.microsoft.com/en-us/windows/win32/shell/shellfolderview-selectitem
This is one of those questions where it may be good to consider what you're trying to achieve, and whether there's a better method.
To add some more context -
Our company develops a C# client application, which allows users to load files and do stuff with them, kind of like how iTunes manages your MP3 files without showing you the actual file on disk.
It's useful to select a file in the application, and do a 'Show me this file in Windows Explorer` command - this is what I'm trying to achieve, and have done so for single files.
We have a ListView which allows users to select multiple files within the application, and move/delete/etc them. It would be nice to have this 'show me this file in windows' command work for multiple selected files - at least if all the source files are in the same directory, but if it's not possible then it's not a major feature.
I suppose you can use FindWindowEx to get the SysListView32 of Windows Explorer, then use SendMessage with LVM_SETITEMSTATE to select the items. The difficulty being to know the position of the items... Perhaps LVM_FINDITEM can be used for this.
Grr i would like to do this as well. Media Player does it when you select 2+ files and right click and do "open file location" but not exactly sure how (nor do i really feel like spending the time w/ procmon to figure it out).