I guess the question is pretty straight forward itself.
Is there any way of detecting the memory (or getting he memory map) and framebuffer (or Graphics Output Protocol) after using ExitBootServices in UEFI in 64-bit mode? If so then how and is there any documentation?
I know that after using ExitBootServices, you the the sole owner of the entire machine.
There are many ways of getting the memory map but they all take help of the bootloader. I want to get the memory map directly from the kernel. Many websites such as OSDev and github sources use bootloaders to get the memory map and framebuffer.
After using ExitBootServices, I'm left in 64-bit mode and the only page on OSDev wiki about getting the memory map works on 32-bit architecture.
I have no language preferences, it may be in C, assembly or whatever and please don't say that it's useless or complicated or difficult to do. I just want an answer.
First, (Probably in (U)EFI) U cannot call boot services which is the only way to get what you want, you can get the memory map & Frame Buffer before ExitBootServices() and pass them to the kernel, you're lucky cause I'm not always on this platform, I've a Hybrid Boot Mechanism with LEGACY BIOS & UEFI Support, and here is an example of how to do that (I'm working on EDK2 Which is the Official Implementation of EFI)
This is how you get the frame buffer from G.O.P ( UGA documentation is removed ):
FRAME_BUFFER_DESCRIPTOR* GraphicsOutputProtocolInitialize(){
// First, we need to query the firmware of all G.O.P Protocol Instances
// (Each instance may represent a GPU or a monitor, GOP features multiple-screens
// U have asked for a simple implementation so we will use only 1 frame buffer
EFI_STATUS status = 0;
EFI_HANDLE* HandleBuffer = NULL;
UINTN NumProtocolHandles = 0;
if(EFI_ERROR(gBS->LocateHandleBuffer(
ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL,
&NumProtocolHandles, &HandleBuffer
)) || !NumProtocolHandles) return NULL;
// Then u need to create a structure that you can pass to the kernel containing information about frame buffers
FRAME_BUFFER_DESCRIPTOR* FrameBuffer = NULL;
if(EFI_ERROR(gBS->AllocatePool(
EfiLoaderData, sizeof(FRAME_BUFFER_DESCRIPTOR), (void**)&FrameBuffer
))) ALLOCATION_PROBLEM;
ZeroMemory((void*)FrameBuffer, sizeof(FRAME_BUFFER_DESCRIPTOR));
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop = NULL;
status = gBS->OpenProtocol(
HandleBuffer[0], // Get first Graphics Output Protocol Instance
&gEfiGraphicsOutputProtocolGuid,
(void**)&gop,
NULL,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if(EFI_ERROR(status) || !gop)
{
return NULL;
}
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ginfo = NULL;
UINTN info_size = 0;
// if mode is not yet set by firmware, then set first mode
if(status == EFI_NOT_STARTED || !gop->Mode){
status = gop->SetMode(gop, 0);
if(EFI_ERROR(status) || !gop->Mode->Mode)
{
return NULL;
}
}
// Now we will ask firmware for the current Video Mode
status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &ginfo);
if(status != EFI_SUCCESS || !ginfo){
return NULL;
}
// You can also list availaible video modes
for(UINTN i = 0;i<gop->Mode->MaxMode;i++) {
status = gop->QueryMode(gop, i, &info_size, &ginfo);
if(status != EFI_SUCCESS || !ginfo){
return NULL;
}
// To set the mode :
status = gop->SetMode(gop, i);
if(EFI_ERROR(status))
{
return NULL;
}
}
FrameBuffer->FrameBufferSize = gop->Mode->FrameBufferSize;
FrameBuffer->HorizontalResolution = gop->Mode->Info->HorizontalResolution;
FrameBuffer->VerticalResolution = gop->Mode->Info->VerticalResolution;
FrameBuffer->FrameBufferBase = (char*)gop->Mode->FrameBufferBase;
ZeroMemory((void*)FrameBuffer, sizeof(FRAME_BUFFER_DESCRIPTOR));
}
return FrameBuffer;
}
This is how you get the memory map :
On the first Call you will get the size of the memory map (Status must be EFI_BUFFER_TOO_SMALL)
Then you add 2 * descriptor size coz there is always 2 additional entries, then you allocate buffer for memory map
On the second call, you will get the actual memory map (Status must be EFI_SUCCESS)
Then u can list memory map entries normally
This is how u make a call to GetMemoryMap() :
EFI_MEMORY_DESCRIPTOR* memory_map = NULL;
UINTN map_size = 0, map_key = 0, descriptor_size = 0;
// Must return EFI_BUFFER_TOO_SMALL on First Call
// map_size will contain buffer size needed
EFI_STATUS s = SystemTable->BootServices->GetMemoryMap(&map_size,memory_map,&map_key,&descriptor_size,&descriptor_version);
map_size+=2*descriptor_size; // this padding must be added since there is 2 additionnal entries
However, u can always ask for a code sample, the previous code of (G.O.P) is just copy-pasted and modified to make it a little bit easier to understand, it is not compiled so it may contain some faults.
Related
I have a FTDI USB3 development board and some FTDI provided code for accessing it. The code works fine for things like the Device number, VID/PID etc. but always returns zero for the 'ftHandle'. As the handle is required for driving the board, this is not helpful! Can anyone see why this should happen?
static FT_STATUS displayDevicesMethod2(void)
{
FT_STATUS ftStatus;
FT_HANDLE ftHandle = NULL;
// Get and display the list of devices connected
// First call FT_CreateDeviceInfoList to get the number of connected devices.
// Then either call FT_GetDeviceInfoList or FT_GetDeviceInfoDetail to display device
info.
// Device info: Flags (usb speed), device type (600 e.g.), device ID (vendor,
product),
handle for subsequent data access.
DWORD numDevs = 0;
ftStatus = FT_CreateDeviceInfoList(&numDevs); // Build a list and return number
connected.
if (FT_FAILED(ftStatus))
{
printf("Failed to create a device list, status = %d\n", ftStatus);
}
printf("Successfully created a device list.\n\tNumber of connected devices: %d\n",
numDevs);
// Method 2: using FT_GetDeviceInfoDetail
if (!FT_FAILED(ftStatus) && numDevs > 0)
{
ftHandle = NULL;
DWORD Flags = 0;
DWORD Type = 0;
DWORD ID = 0;
char SerialNumber[16] = { 0 };
char Description[32] = { 0 };
for(DWORD i = 0; i <numDevs; i++)
{
ftStatus = FT_GetDeviceInfoDetail(i, &Flags, &Type, &ID, NULL, SerialNumber,
Description, &ftHandle);
if (!FT_FAILED(ftStatus))
{
printf("Device[%d] (using FT_GetDeviceInfoDetail)\n", i);
printf("\tFlags: 0x%x %s | Type: %d | ID: 0x%08X | ftHandle=0x%p\n",
Flags,
Flags & FT_FLAGS_SUPERSPEED? "[USB 3]":
Flags & FT_FLAGS_HISPEED? "[USB 2]":
Flags & FT_FLAGS_OPENED? "[OPENED]": "",
Type,
ID,
ftHandle);
printf("\tSerialNumber=%s\n", SerialNumber);
printf("\tDescription=%s\n", Description);
}
}
}
return ftStatus;
}
This is indeed not super straight forward, but a short peek in the FTDI Knowledgebase yields:
This function builds a device information list and returns the number of D2XX devices connected to the system. The list contains information about both unopen and open devices.
A handle only exists for an opened device. Thus, I assume that your code does not already include that step. If so you need to open it first, e.g. using FT_Open. There are plenty of examples available. You can check their page or stackoverflow for a working example.
I work on an electron application, and we would like to support dragging and dropping .msg files from our app into Outlook (or the Windows shell, or wherever, but primarily Outlook). The files will not necessarily be available before the user starts the drag and drop operation, and will need to be downloaded once the user begins the drag and drop. This means we can't use electron's inbuilt startDrag as it requires that the files are already in the filesystem, so I have implemented a node c++ addon to handle it using the OLE Drag and Drop API.
The data extraction (from my app to Outlook) needs to occur asynchronously, otherwise node's event loop will be blocked, halting the download. This means that the data extraction has to occur on another thread so that the event loop can continue actually downloading the data (currently doing the download in c++ is not an option, it has to occur in node). So I have implemented IDataObjectAsyncCapability on my DataObject, to indicate that I support asynchronous data extraction (it would be even nicer to be able to indicate that I don't support synchronous), but Outlook won't even query for the Interface, let alone do the data extraction asynchronously. The Windows shell does however query for the interface, but after the call to GetData, it still performs the extraction synchronously inside DoDragDrop, without even invoking any of the IDataObjectAsyncCapability methods. Is there something lacking in my implementation, or a specific way to encourage the drop target to start up a new thread?
Here is the meat of my DataObject implementation, if there's anything else that could be of use, I can provide.
STDMETHODIMP DataObject::QueryInterface(REFIID iid, LPVOID* ppvObject) {
if (ppvObject == nullptr) {
return E_INVALIDARG;
} else if (iid == IID_IUnknown) {
AddRef();
*ppvObject = reinterpret_cast<LPUNKNOWN>(this);
return S_OK;
} else if (iid == IID_IDataObject) {
AddRef();
*ppvObject = reinterpret_cast<LPDATAOBJECT>(this);
return S_OK;
} else if (iid == IID_IDataObjectAsyncCapability) {
AddRef();
*ppvObject = reinterpret_cast<IDataObjectAsyncCapability*>(this);
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
STDMETHODIMP DataObject::GetData(LPFORMATETC queryFormat,
LPSTGMEDIUM outputStorage) {
if (queryFormat->cfFormat == CF_FILEDESCRIPTOR &&
(queryFormat->tymed & TYMED_HGLOBAL) && queryFormat->lindex <= 0 &&
queryFormat->dwAspect == DVASPECT_CONTENT) {
outputStorage->tymed = TYMED_HGLOBAL;
outputStorage->pUnkForRelease = nullptr;
outputStorage->hGlobal =
lockAndDuplicateHGLOBAL(this->groupDescriptorStorage.hGlobal);
return S_OK;
} else if (queryFormat->cfFormat == CF_FILECONTENTS &&
(queryFormat->tymed & TYMED_ISTREAM) &&
queryFormat->dwAspect == DVASPECT_CONTENT &&
queryFormat->lindex >= 0 &&
queryFormat->lindex < this->files.size()) {
// files is vector<pair<FILEDESCRIPTOR, STGMEDIUM>>
// where the STGMEDIUM is set to IStream
// Am I doing something wrong here?
auto file = this->files[queryFormat->lindex].second;
*outputStorage = file;
return S_OK;
}
return DV_E_FORMATETC;
}
STDMETHODIMP DataObject::QueryGetData(LPFORMATETC queryFormat) {
if (queryFormat->cfFormat == CF_FILEDESCRIPTOR ||
(queryFormat->cfFormat == CF_FILECONTENTS &&
(queryFormat->tymed & TYMED_HGLOBAL))) {
return S_OK;
}
return DATA_E_FORMATETC;
}
STDMETHODIMP DataObject::EnumFormatEtc(DWORD dwDirection,
LPENUMFORMATETC* ppEnumFormatEtc) {
if (dwDirection == DATADIR_GET) {
// basic implementation of IEnumFormatEtc (not mine)
return EnumFormat::Create(this->supportedFormats, this->numFormats,
ppEnumFormatEtc);
}
return E_INVALIDARG;
}
// Do the actual drag drop
// files is a list of STGMEDIUMS with IStreams. I'm using data that's readily available while
// implementing this, could that be somehow interfering and causing this problem in the first place?
DWORD dwEffect;
auto dataObject = new DataObject(groupDescriptorStorage, files);
auto dropSource = new DropSource();
// Do these DROPEFFECTS have an effect?
auto result = DoDragDrop(dataObject, dropSource,
DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
// By the time we get here, the data extraction would already have occured
// because it's happening inside DoDragDrop. of course, isAsyncOperation will be false
BOOL isInAsyncOperation;
dataObject->InOperation(&isInAsyncOperation);
I've followed the instructions from here as well as various forum posts I've found, but I can't seem to find anything about what to do when the drop target doesn't play ball.
I'm really stuck for ideas as to how to make this work. If the drop target isn't even querying for IDataObjectAsyncCapability then is it hopeless? Should I be returning something other than the file contents when it's first requested?
I have a web app running on Azure shared web site mode. A simple method where I add items to a list and sort this list, when the list size is about 300 items, takes 0.3s on my machine and 10s after deploy (on azure machine).
Does anybody has any idea why Azure is so slow?
Is any configuration I do it wrong? I use default one but replaced FREE mode with SHARED mode because I thought this would help but it seems it does not.
UPDATE:
public ActionResult GetPosts(String selectedStreams, int implicitSelectedVisualiserId, int userId)
{
DateTime begin = DateTime.UtcNow;
List<SearchQuery> selectedSearchQueries = searchQueryRepository.GetSearchQueriesOfStreamsIds(selectedStreams == String.Empty ? new List<int>() : selectedStreams.Split(',').Select(n => int.Parse(n)).ToList());
var implicitSelectedVisualiser = VisualiserModel.ToVisualiserModel(visualiserRepository.GetVisualiser(implicitSelectedVisualiserId));
var twitterSearchQueryOfImplicitSelectedVisualiser = searchQueryRepository.GetSearchQuery(implicitSelectedVisualiser.Stream.Name, Service.Twitter, userId);
var instagramSearchQueryOfImplicitSelectedVisualiser = searchQueryRepository.GetSearchQuery(implicitSelectedVisualiser.Stream.Name, Service.Instagram, userId);
var facebookSearchQueryOfImplicitSelectedVisualiser = searchQueryRepository.GetSearchQuery(implicitSelectedVisualiser.Stream.Name, Service.Facebook, userId);
var manualSearchQueryOfImplicitSelectedVisualiser = searchQueryRepository.GetSearchQuery(implicitSelectedVisualiser.Stream.Name, Service.Manual, userId);
List<SearchResultModel> approvedSearchResults = new List<SearchResultModel>();
if (twitterSearchQueryOfImplicitSelectedVisualiser != null || instagramSearchQueryOfImplicitSelectedVisualiser != null || facebookSearchQueryOfImplicitSelectedVisualiser != null
|| manualSearchQueryOfImplicitSelectedVisualiser != null)
{
// Define search text to be displayed during slideshow;
SearchModel searchModel = new SearchModel();
// Set slideshow settings from implicit selected visualiser.
ViewBag.CurrentVisualiser = implicitSelectedVisualiser;
// Load search results from selected visualisers.
foreach (SearchQuery searchQuery in selectedSearchQueries)
{
approvedSearchResults.AddRange(
SearchResultModel.ToSearchResultModel(
searchResultRepository.GetSearchResults
(searchQuery.Id,
implicitSelectedVisualiser.Language)));
// Add defined query too.
searchModel.SearchValue += " " + searchQuery.Query;
}
// Add defined query for implicit selected visualiser.
if (twitterSearchQueryOfImplicitSelectedVisualiser != null)
searchModel.SearchValue += " " + twitterSearchQueryOfImplicitSelectedVisualiser.Query;
if (instagramSearchQueryOfImplicitSelectedVisualiser != null)
searchModel.SearchValue += " " + instagramSearchQueryOfImplicitSelectedVisualiser.Query;
if (facebookSearchQueryOfImplicitSelectedVisualiser != null)
searchModel.SearchValue += " " + facebookSearchQueryOfImplicitSelectedVisualiser.Query;
ViewBag.Search = searchModel;
// Also add search results from implicit selected visualiser
if (twitterSearchQueryOfImplicitSelectedVisualiser != null)
approvedSearchResults.AddRange(SearchResultModel.ToSearchResultModel(searchResultRepository.GetSearchResults(twitterSearchQueryOfImplicitSelectedVisualiser.Id, implicitSelectedVisualiser.Language)));
if (instagramSearchQueryOfImplicitSelectedVisualiser != null)
approvedSearchResults.AddRange(SearchResultModel.ToSearchResultModel(searchResultRepository.GetSearchResults(instagramSearchQueryOfImplicitSelectedVisualiser.Id, implicitSelectedVisualiser.Language)));
if (facebookSearchQueryOfImplicitSelectedVisualiser != null)
approvedSearchResults.AddRange(SearchResultModel.ToSearchResultModel(searchResultRepository.GetSearchResults(facebookSearchQueryOfImplicitSelectedVisualiser.Id, implicitSelectedVisualiser.Language)));
if (manualSearchQueryOfImplicitSelectedVisualiser != null)
approvedSearchResults.AddRange(SearchResultModel.ToSearchResultModel(searchResultRepository.GetSearchResults(manualSearchQueryOfImplicitSelectedVisualiser.Id, implicitSelectedVisualiser.Language)));
// if user selected to show only posts from specific number of last days.
var approvedSearchResultsFilteredByDays = new List<SearchResultModel>();
if (implicitSelectedVisualiser.ShowPostsFromLastXDays != 0)
{
foreach (SearchResultModel searchResult in approvedSearchResults)
{
var postCreatedTimeWithDays = searchResult.PostCreatedTime.AddDays(implicitSelectedVisualiser.ShowPostsFromLastXDays + 1);
if (postCreatedTimeWithDays >= DateTime.Now)
approvedSearchResultsFilteredByDays.Add(searchResult);
}
}
else
{
approvedSearchResultsFilteredByDays = approvedSearchResults;
}
// Order search results (posts to be displayed by created datetime).
var approvedSearchResultsOrdered = new List<SearchResultModel>();
if (implicitSelectedVisualiser.PostsSortOrder == PostsSortOrder.CREATED_DATE_ASC)
{
approvedSearchResultsOrdered = approvedSearchResultsFilteredByDays.OrderBy(s => s.PostCreatedTime).ToList(); ;
}
else if (implicitSelectedVisualiser.PostsSortOrder == PostsSortOrder.CREATED_DATE_DESC)
{
approvedSearchResultsOrdered = approvedSearchResultsFilteredByDays.OrderByDescending(s => s.PostCreatedTime).ToList(); ;
}
else if (implicitSelectedVisualiser.PostsSortOrder == PostsSortOrder.RANDOM)
{
var rnd = new Random();
approvedSearchResultsOrdered = approvedSearchResultsFilteredByDays.OrderBy(x => rnd.Next()).ToList();
}
// Load background images;
var visualiserImages = visualiserImageRepository.GetImages(implicitSelectedVisualiser.Id);
//foreach (SearchResultModel searchResultModel in approvedSearchResultsOrdered)
//{
// searchResultModel.BackgroundImagePath = TwitterUtils.GetRandomImageBackgroundForDisplay(visualiserImages);
//}
ViewBag.BackgroundImagePath = TwitterUtils.GetRandomImageBackgroundForDisplay(visualiserImages);
approvedSearchResults = approvedSearchResultsOrdered;
}
DateTime end = DateTime.UtcNow;
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(String.Format("User {0}: Preparing {1} posts for visualiser took {2} seconds", MySession.Current.LoggedInUserName, approvedSearchResults.Count(), (end - begin).TotalMilliseconds / 1000)));
return PartialView("_DisplayPostsNew", approvedSearchResults);
}
This isn't surprising actually. The servers used in Windows Azure are currently mostly 1.6 GHz machines. The larger sized machine you use the more cores you get, but they are all the same speed. This likely is a much slower CPU than the development machine you use.
On Windows Azure Web Sites when you move to Shared mode you are still in a multi-tenant environment, so you could be seeing some noisy neighbors here. The difference between Free and Shared is that many of the quotas for free are removed since you are paying. When you move to Standard then you are assigned a Virtual Machine dedicated to your web sites (up to 100 of them), so that is the best case scenario since you are the only one using the resources at that point.
There was a thread on this on the MSDN forums a while back : http://social.msdn.microsoft.com/Forums/windowsazure/en-US/0d0a3a88-eac4-4b9e-8b10-4a547cbf653b/performance-of-azure-servers-slow-cpus?forum=windowsazuredevelopment
They have started offering different hardware configurations with more memory for Virtual Machines and Cloud Services and such, but I'm not sure the CPUs have been changed. It's hard to find the CPU stated on WindowsAzure.com anymore, but on the pricing calculator for Web Sites it references 1.6Ghz machines when you move the slider to Standard.
Actually I found the issue.
Locally, I tested with a few hundreds of records in my DB while in Azure DB I have over 70 000 records in that table which affects performance of the algorithm...
One mistake I did in the code above: I have filtered records from DB by specific date AFTER taking all out. By filtering directly in Linq, I increased the performance from 10s to 0.3s in Azure too.
Currently we're implementing Libspotify in a win 7 64 bit system. Everything seems to work fine except the playback. We get data from the callback , but even using audicity on the saved audio, is filled with abnormalities. So to research further we took the win32 sample (spshell ) and modified it to save the music data to file. Same problem, definitely music with these ticks in it. I'm sure there's something simple I'm missing here, but I'm at a loss as to what could be the problem. Any help would be great since as it stands our project is at a stand still until we can resolve this.
The audio saved can be viewed here
http://uploader.crestron.com/download.php?file=8001d80992480280dba365752aeaca81
Below are the code changes I made to save the file ( for testing only )
static FILE *pFile;
int numBytesToWrite=0;
CRITICAL_SECTION m_cs;
int SP_CALLCONV music_delivery(sp_session *s, const sp_audioformat *fmt, const void *frames, int num_frames)
{
if ( num_frames == 0 )
return;
EnterCriticalSection(&m_cs);
numBytesToWrite = ( num_frames ) * fmt->channels * sizeof(short);
if (numBytesToWrite > 0 )
fwrite(frames, sizeof(short), numBytesToWrite, pFile);
LeaveCriticalSection(&m_cs);
return num_frames;
}
static void playtrack_test(void)
{
sp_error err;
InitializeCriticalSection(&m_cs);
pFile = fopen ("C:\\zzzspotify.pcm","wb");
test_start(&playtrack);
if((err = sp_session_player_load(g_session, stream_track)) != SP_ERROR_OK) {
test_report(&playtrack, "Unable to load track: %s", sp_error_message(err));
return;
}
info_report("Streaming '%s' by '%s' this will take a while", sp_track_name(stream_track),
sp_artist_name(sp_track_artist(stream_track, 0)));
sp_session_player_play(g_session, 1);
}
void SP_CALLCONV play_token_lost(sp_session *s)
{
fclose(pFile);
DeleteCriticalSection(&m_cs);
stream_track_end = 2;
notify_main_thread(g_session);
info_report("Playtoken lost");
}
static int check_streaming_done(void)
{
if(stream_track_end == 2)
test_report(&playtrack, "Playtoken lost");
else if(stream_track_end == 1)
test_ok(&playtrack);
else
return 0;
fclose(pFile);
stream_track_end = 0;
return 1;
}
It looks like this is the problem:
fwrite(frames, sizeof(short), numBytesToWrite, pFile);
The fwrite documentation states that the second argument is the "size in bytes of each element to be written", and the third is this "number of elements, each one with a size of size bytes".
The way you're calling frwritewill tell it to write numBytesToWrite * sizeof(short) bytes, which will run right off the end of the given buffer. I'm actually surprised it doesn't crash!
I'd suggest changing your fwrite call to something like:
fwrite(frames, sizeof(char), numBytesToWrite, pFile);
or:
int numSamplesToWrite = num_frames * fmt->channels;
fwrite(frames, sizeof(short), numSamplesToWrite, pFile);
Edit:
After looking at your audio in detail, I'm more convinced that this is the case. The song seems to be playing at half speed (i.e., 2x as much data is being written) and the artefacts seem to look like buffer overrun into random memory.
I needed to enumerate running processes and wondered for a while why my code wasn't working:
PROCESSENTRY32 ProcEntry;
ZeroMemory (&ProcEntry, sizeof (PROCESSENTRY32)); //problem
ProcEntry.dwFlags = sizeof(PROCESSENTRY32);
HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Snapshot == INVALID_HANDLE_VALUE)
return false;
if (Process32First(Snapshot, &ProcEntry))
....
Problem was that Process32First always returned FALSE because of ERROR_BAD_LENGTH error.
Once I removed ZeroMemory line, everything started working fine. So the question is, why ZeroMemory caused it? It should just fill memory at the address of X for Z bytes. I use it a lot for winapi pointer-like structures, this time I didnt realise its a local variable but that doesn't explain the problem or does it?
Thanks,
Kra
EDIT: plus I found out code works fine only in Debug version, once I compile it as Release version, its bugged again :/
You should set dwSize, not dwFlags.
ProcEntry.dwFlags = sizeof(PROCESSENTRY32);
should be
ProcEntry.dwSize = sizeof(PROCESSENTRY32);
You cannot zero out the entire PROCESSENTRY32 structure as it is self-describing - you have to set dwSize. From the sample here:
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
printError( TEXT("Process32First") ); // show cause of failure
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}