Using Windows API File functions c++ - c++

New to windows programming, there are several examples all over the internet of what i am about to ask however none of them show the comparison which i think is failing.
I'm using several windows api calls throughout my C++ Program and just need some guidence on how to use them correctly.
For example below i have GetFileAttributes() which returns anything from File Attribute Constants.
DWORD dwAttributes = GetFileAttributes(strPathOfFile.c_str());
if ( dwAttributes != 0xffffffff )
{
if ( dwAttributes == FILE_ATTRIBUTE_NORMAL )
{
pkFileInfoList->Add( strPathOfFile + "\t" +"FILE_ATTRIBUTE_NORMAL");
}
else if ( dwAttributes == FILE_ATTRIBUTE_ARCHIVE )
{
pkFileInfoList->Add( strPathOfFile + "\t" + "FILE_ATTRIBUTE_ARCHIVE");
}
}
[/CODE]
The if/else statement continues with everything from File Attribute Constants.
Am i using this correctly, i have a directory with over 2500 files which i am feeding the path recusivly. It is always returning FILE_ATTRIBUTE_ARCHIVE.
Thanks,

GetFileAttributes returns a set of attributes, not a single attribute, so to test correctly you should do:
DWORD dwAttributes = GetFileAttributes(strPathOfFile.c_str());
if ( dwAttributes != 0xffffffff )
{
if ( dwAttributes & FILE_ATTRIBUTE_NORMAL )
{
pkFileInfoList->Add( strPathOfFile + "\t" +"FILE_ATTRIBUTE_NORMAL");
}
else if ( dwAttributes & FILE_ATTRIBUTE_ARCHIVE )
{
pkFileInfoList->Add( strPathOfFile + "\t" + "FILE_ATTRIBUTE_ARCHIVE");
}
}
I.e. use bitwise & instead of ==

Related

c++ folder only search

I need to get a list of folders in the directory, but only the folders. No files are needed. Only folders. I use filters to determine if this is a folder, but they do not work and all files and folders are output.
string root = "D:\\*";
cout << "Scan " << root << endl;
std::wstring widestr = std::wstring(root.begin(), root.end());
const wchar_t* widecstr = widestr.c_str();
WIN32_FIND_DATAW wfd;
HANDLE const hFind = FindFirstFileW(widecstr, &wfd);
In this way, I check that it is a folder.
if (INVALID_HANDLE_VALUE != hFind)
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
How to solve a problem?
There are two ways to do this: The hard way, and the easy way.
The hard way is based on FindFirstFile and FindNextFile, filtering out directories as needed. You will find a bazillion samples that outline this approach, both on Stack Overflow as well as the rest of the internet.
The easy way: Use the standard directory_iterator class (or recursive_directory_iterator, if you need to recurse into subdirectories). The solution is as simple as1:
for ( const auto& entry : directory_iterator( path( L"abc" ) ) ) {
if ( is_directory( entry.path() ) ) {
// Do something with the entry
visit( entry.path() );
}
}
You will have to include the <filesystem> header file, introduced in C++17.
Note: Using the latest version of Visual Studio 2017 (15.3.5), this is not yet in namespace std. You will have to reference namespace std::experimental::filesystem instead.
1 Note in particular, that there is no need to filter out the . and .. pseudo-directories; those aren't returned by the directory iterators.
This function collects folders into given vector. If you set recursive to true, it will be scanning folders inside folders inside folders etc.
// TODO: proper error handling.
void GetFolders( std::vector<std::wstring>& result, const wchar_t* path, bool recursive )
{
HANDLE hFind;
WIN32_FIND_DATA data;
std::wstring folder( path );
folder += L"\\";
std::wstring mask( folder );
mask += L"*.*";
hFind=FindFirstFile(mask.c_str(),&data);
if(hFind!=INVALID_HANDLE_VALUE)
{
do
{
std::wstring name( folder );
name += data.cFileName;
if ( ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
// I see you don't want FILE_ATTRIBUTE_REPARSE_POINT
&& !( data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
{
// Skip . and .. pseudo folders.
if ( wcscmp( data.cFileName, L"." ) != 0 && wcscmp( data.cFileName, L".." ) != 0 )
{
result.push_back( name );
if ( recursive )
// TODO: It would be wise to check for cycles!
GetFolders( result, name.c_str(), recursive );
}
}
} while(FindNextFile(hFind,&data));
}
FindClose(hFind);
}
Modified from https://stackoverflow.com/a/46511952/8666197

ToUnicodeEx not printing "Greater Than"

I wrote a function which processes the user keyboard in order to write text in an app.
In order to do that I use the ToUnicodeEx function which uses an array of Key states.
The function is working perfectly fine for every possible input, except for one : I cannot display the ">" sign, which is supposed to be the combination of "SHIFT + <" : it displays the "<" sign instead, as if the SHIFT key was not pressed, whereas it knows it it pressed.
Has somebody already experienced the same and knows what the problem is?
You will find my function code below :
void MyFunction(bool bCapsLockDown)
{
IOClass io = GetMyIOInstance();
HKL layout = GetKeyboardLayout( 0 );
uchar uKeyboardState[256];
WCHAR oBuffer[5] = {};
//Initialization of KeyBoardState
for (uint i = 0; i < 256; ++i)
{
uKeyBoardState[i] = 0;
}
// Use of my ConsultKeyState to get the status of pressed keys
if ( ConsultKeyState( VK_SHIFT ) || bCapsLockDown )
{
uKeyboardState[VK_CAPITAL] = 0xff;
}
if ( ConsultKeyState( VK_CONTROL ) )
{
uKeyboardState[VK_CONTROL] = 0xff;
}
if ( ConsultKeyState( VK_MENU ) )
{
uKeyboardState[VK_MENU] = 0xff;
}
if ( ConsultKeyState( VK_RMENU ) )
{
uKeyboardState[VK_MENU] = 0xff;
uKeyboardState[VK_CONTROL] = 0xff;
}
for ( uint iVK = 0; iVK < 256; ++iVK )
{
bool bKeyDown = ConsultKeyState( iVK ) != 0;
uint iSC = MapVirtualKeyEx( iVK, MAPVK_VK_TO_VSC, layout );
bool bKeyAlreadyDown = io.KeysDown[iVK];
io.KeysDown[iVK] = bKeyDown;
if ( io.KeysDown[iVK] && bKeyAlreadyDown == false )
{
int iRet = ToUnicodeEx( iVK, iSC, uKeyboardState, (LPWSTR)oBuffer, 4, 0, layout );
if( iRet > 0 && (iswgraph( (unsigned short) oBuffer[0] ) || oBuffer[0] == ' ') )
io.AddInputCharacter( (unsigned short) oBuffer[0] );
}
}
}
Edit :
To summarize, my question is :
What would be the good combination VirtualKey + KeyBoardState to get a ">" displayed?
The problem is that shift and caps lock do not have the same effect on a keyboard. For example, (on a UK keyboard) pressing shift+1 = !, but pressing 1 with caps lock on still give you 1.
Your code currently treats them the same, though, and it is using VK_CAPITAL in both cases. This will give you the same effect as if caps lock were on, which is not what you want in this case.
The solution is therefore to break out your logic and use VK_SHIFT when you really want shift to be pressed and VK_CAPITAL when you want caps lock to be active.

Why is this Haxe try-catch block still crashing, when using Release mode for C++ target

I have a HaxeFlixel project, that is working OK in Debug mode for misc targets, including flash, neko and windows. But Targeting Windows in Release mode, I'm having an unexpected crash, and surprisingly it's happening inside a try-catch block. Here's the crashing function:
/**
* Will safely scan a parent node's children, search for a child by name, and return it's text.
* #param parent an Fast object that is parent of the `nodeNamed` node
* #param nodeName the node's name or a comma-separated path to the child (will scan recursively)
* #return node's text as String, or null if child is not there
*/
public static function getNodeText(parent:Fast, nodeName:String):String {
try {
var _node : Fast = getNodeNamed(parent, nodeName);
//if (_node == null)
// return null;
// next line will crash if _node is null
var it :Iterator<Xml> = _node.x.iterator();
if ( it == null || !it.hasNext() )
return null;
var v = it.next();
var n = it.next();
if( n != null ) {
if( v.nodeType == Xml.PCData && n.nodeType == Xml.CData && StringTools.trim(v.nodeValue) == "" ) {
var n2 = it.next();
if( n2 == null || (n2.nodeType == Xml.PCData && StringTools.trim(n2.nodeValue) == "" && it.next() == null) )
return n.nodeValue;
}
//does not only have data (has children)
return null;
}
if( v.nodeType != Xml.PCData && v.nodeType != Xml.CData )
//does not have data";
return null;
return v.nodeValue;
}catch (err:Dynamic) {
trace("Failed parsing node Text [" + nodeName+"] " + err );
return null;
}
}
By enabling if (_node == null) return null; line, It's working safely again. By catching errors as Dynamic I thought I was supposed to catch every possible error type! Why is this happening? And why is it appearing in release mode?
My IDE is FlashDevelop, and I'm using HaxeFlixel 3.3.6, lime 0.9.7 and openFL 1.4.0, if that makes any difference
EDIT: I suspect this has to do with how the translated C++ code missed the Dynamic Exception. The equivalent generated C++ code is:
STATIC_HX_DEFINE_DYNAMIC_FUNC2(BaxXML_obj,_getNodeNamed,return )
::String BaxXML_obj::getNodeText( ::haxe::xml::Fast parent,::String nodeName){
HX_STACK_FRAME("bax.utils.BaxXML","getNodeText",0x4a152f07,"bax.utils.BaxXML.getNodeText","bax/utils/BaxXML.hx",56,0xf6e2d3cc)
HX_STACK_ARG(parent,"parent")
HX_STACK_ARG(nodeName,"nodeName")
HX_STACK_LINE(56)
try
{
HX_STACK_CATCHABLE(Dynamic, 0);
{
HX_STACK_LINE(57)
::haxe::xml::Fast _node = ::bax::utils::BaxXML_obj::getNodeNamed(parent,nodeName); HX_STACK_VAR(_node,"_node");
HX_STACK_LINE(63)
Dynamic it = _node->x->iterator(); HX_STACK_VAR(it,"it");
// ... Let's skip the irrelevant code
}
catch(Dynamic __e){
{
HX_STACK_BEGIN_CATCH
Dynamic err = __e;{
HX_STACK_LINE(82)
::String _g5 = ::Std_obj::string(err); HX_STACK_VAR(_g5,"_g5");
HX_STACK_LINE(82)
::String _g6 = (((HX_CSTRING("Failed parsing node Text [") + nodeName) + HX_CSTRING("] ")) + _g5); HX_STACK_VAR(_g6,"_g6");
HX_STACK_LINE(82)
::haxe::Log_obj::trace(_g6,hx::SourceInfo(HX_CSTRING("BaxXML.hx"),82,HX_CSTRING("bax.utils.BaxXML"),HX_CSTRING("getNodeText")));
HX_STACK_LINE(83)
return null();
}
}
}
HX_STACK_LINE(56)
return null();
}
What haxedefs do you have defined?
Adding these to your project.xml might help:
<haxedef name="HXCPP_CHECK_POINTER"/> <!--makes null references cause errors-->
<haxedef name="HXCPP_STACK_LINE" /> <!--if you want line numbers-->
<haxedef name="HXCPP_STACK_TRACE"/> <!--if you want stack traces-->
You might also try the crashdumper library:
https://github.com/larsiusprime/crashdumper
(Crashdumper will turn on HXCPP_CHECK_POINTER by default as part of it's include.xml, and will set up hooks for both hxcpp's errors and openfl/lime's uncaught error events)
I guess this boils down to how C++ handles null-pointer Exceptions. It doesn't!
More info here or here
That seems odd, some questions that may help solving it.
It looks like you are doing quite some assumptions on how the xml looks (doing some manual it.next()), why is that?
Why are you using this big-ass try-catch block?
How does getNodeNamed look, it seems it can return null.
Do you have an example xml to test with?

creating file for shell output redirection

This is a school assignment.
So basically I have written a C code for a shell that handles terminating the command with &, and input / output redirection using > or <. using pipes and fork(), execvp().
The problem is my input/output redirection only handles that for files that already exist.
What i need to know is how would I go about redirecting output to a file that doesn't exist - I know I would have to create the file, but I'm not sure how that works.
For example: ls -a < test.txt
If test.txt is not in the directory, i need to create it and redirect output to that.
So how do I create this file?
here is some basic example code which does not create a new file:
else if( '>' == buff[i] ){
i++;
j=0;
if( ' ' == buff[i] )
i++;
while( ' ' != buff[i] && i < len )
out_file[j++]=buff[i++];
out_file[j]='\0';
if ( ( ofd = open(out_file,1) ) < 0 ){
perror("output redirected file");
exit( 1 );
}
close(1);
dup(ofd);
}
Any help with how I can output and create a new file would be much appreciated! Thanks!
You need to tell open to create the file, if necessary:
if ( ( ofd = open(out_file, O_WRONLY | O_CREAT) ) < 0 ) {
Note that your code will be more readable if you use the named constants for the flags to open. Compare with the functionally equivalent
if ( ( ofd = open(out_file, 513) ) < 0 ) {
or even
if ( ( ofd = open(out_file, 0x0201) ) < 0 ) {

Windows Installer, Error 2896 from Custom Action after successful execution

I have a custom action dll, written in C++, which is invoked using a button during install. The purpose of the custom action is to capture the clipboard contents and evaluate whether or not the contents is in the format of a valid product key. If it is, then the 'PRODUCTKEY' property is updated, as is another property which lets me know that we have been successful.
<Control Id="PasteButton" Type="PushButton" X="25" Y="176" Width="25" Height="16" Default="yes" Text="Paste" >
<Publish Event="DoAction" Value="MsiCheckClipboardForKey" Order="1">1</Publish>
<Publish Property="PRODUCTKEY" Value="[PRODUCTKEY]" Order="2">ClipboardSuccess = 1</Publish>
</Control>
Unfortunately, the install is failing after this custom action has been called. However, from looking at the install log my properties have been changed which tends to suggest that my custom action code is running successfully.
MSI (c) (20:4C) [12:04:55:281]: Invoking remote custom action. DLL:
C:\Users\xxxxx\AppData\Local\Temp\MSI5652.tmp, Entrypoint:
msiCheckClipboardForKey
MSI (c) (20!C4) [12:04:57:746]: PROPERTY CHANGE: Modifying
ClipboardSuccess property. Its current value is '0'. Its new value:
'1'.
MSI (c) (20!C4) [12:04:57:746]: PROPERTY CHANGE: Adding PRODUCTKEY
property. Its value is 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'.
Action ended 12:04:57: MsiCheckClipboardForKey. Return value 3.
DEBUG: Error 2896: Executing action MsiCheckClipboardForKey failed.
This is the custom action code:
#include "StdAfx.h"
#include "Debug.h"
#pragma comment(linker, "/EXPORT:msiCheckClipboardForKey=_msiCheckClipboardForKey#4")
BOOL GetClipboardText ( IN OUT CString& strClipBoardText)
{
strClipBoardText = _T("");
BOOL bOK = FALSE;
UINT uFormat = 0;
// We need to explicitly query the clipboard for UNICODE text
// if we have a UNICODE application
#ifdef _UNICODE
uFormat = CF_UNICODETEXT;
#else
uFormat = CF_TEXT;
#endif
if ( ::IsClipboardFormatAvailable ( uFormat ) )
{
if ( ::OpenClipboard ( NULL ) )
{
HANDLE hClipBrdData = NULL;
if ( HANDLE hClipBrdData = ::GetClipboardData ( uFormat ) )
{
if ( LPTSTR lpClipBrdText = ( LPTSTR ) ::GlobalLock ( hClipBrdData ) )
{
MessageBox("Clipboard Text",lpClipBrdText,NULL,NULL);
strClipBoardText = lpClipBrdText;
::GlobalUnlock ( hClipBrdData );
bOK = TRUE;
}
}
::CloseClipboard();
}
}
return bOK;
}
extern "C" UINT __stdcall msiCheckClipboardForKey(MSIHANDLE hMSI)
{
CString strClipboardText ( _T("") );
if ( GetClipboardText ( strClipboardText ) )
{
DebugMsg ( hMSI, _T("Found clipboard text") );
strClipboardText.Trim();
// Look at the length. Is it 25 (wih no dashes/slashes) or 29 (with dashes/slashes)?
BOOL bValidLength = strClipboardText.Find ( '-' ) != -1 || strClipboardText.Find ( '/' ) != -1 ? strClipboardText.GetLength() == 29 : strClipboardText.GetLength() == 25;
DebugMsg ( hMSI, _T("Is it a product key? %b",bValidLength) );
if ( bValidLength )
{
//strClipboardText.Remove ( '-' );
//strClipboardText.Remove ( '/' );
MessageBox("Formatted Clipboard Text",strClipboardText,NULL,NULL);
MsiSetProperty(hMSI, "ClipboardSuccess", "1");
MsiSetProperty(hMSI, "PRODUCTKEY", strClipboardText);
return 0;
}
}
return 1; // None-zero is error state
}
Not sure what the problem could be, even more so as the custom action does seem to be executed as the properties are set correctly.
After tidying the code to add to this question and rebuilding I found that I was only getting the error when I had a string on the clipboard which wasn't evaluated as a product key format. Therefore the custom action was returning 1. I believe this to be the reason that my install failed. A return value of 1 obviously causing the install error.
Please correct me if I am wrong but this has fixed the issue.