I'm trying to utilize the Win32 API function DsGetSiteName() using Perl's Win32::API module. According to the Windows SDK, the function prototype for DsGetSiteName is:
DWORD DsGetSiteName(LPCTSTR ComputerName, LPTSTR *SiteName)
I successfully wrote a small C++ function using this API to get a better understanding of how it would actually work (I'm learning C++ on my own, but I digress).
Anyhow, from my understanding of the API documentation, the second parameter is supposed to be a pointer to a variable that receives a pointer to a string. In my C++ code, I wrote that as:
LPSTR site;
LPTSTR *psite = &site;
and have successfully called the API using the psite pointer.
Now my question is, is there a way to do the same using Perl's Win32::API? I've tried the following Perl code:
my $site = " " x 256;
my $computer = "devwin7";
my $DsFunc = Win32::API->new("netapi32","DWORD DsGetSiteNameA(LPCTSTR computer, LPTSTR site)");
my $DsResult = $DsFunc->Call($computer, $site);
print $site;
and the result of the call in $DsResult is zero (meaning success), but the data in $site is not what I want, it looks to be a mixture of ASCII and non-printable characters.
Could the $site variable be holding the pointer address of the allocated string? And if so, is there a way using Win32::API to dereference that address to get at the string?
Thanks in advance.
Win32::API can't handle char**. You'll need to extract the string yourself.
use strict;
use warnings;
use feature qw( say state );
use Encode qw( encode decode );
use Win32::API qw( );
use constant {
NO_ERROR => 0,
ERROR_NO_SITENAME => 1919,
ERROR_NOT_ENOUGH_MEMORY => 8,
};
use constant PTR_SIZE => $Config{ptrsize};
use constant PTR_FORMAT =>
PTR_SIZE == 8 ? 'Q'
: PTR_SIZE == 4 ? 'L'
: die("Unrecognized ptrsize\n");
use constant PTR_WIN32API_TYPE =>
PTR_SIZE == 8 ? 'Q'
: PTR_SIZE == 4 ? 'N'
: die("Unrecognized ptrsize\n");
# Inefficient. Needs a C implementation.
sub decode_LPCWSTR {
my ($ptr) = #_;
return undef if !$ptr;
my $sW = '';
for (;;) {
my $chW = unpack('P2', pack(PTR_FORMAT, $ptr));
last if $chW eq "\0\0";
$sW .= $chW;
$ptr += 2;
}
return decode('UTF-16le', $sW);
}
sub NetApiBufferFree {
my ($Buffer) = #_;
state $NetApiBufferFree = Win32::API->new('netapi32.dll', 'NetApiBufferFree', PTR_WIN32API_TYPE, 'N')
or die($^E);
$NetApiBufferFree->Call($Buffer);
}
sub DsGetSiteName {
my ($ComputerName) = #_;
state $DsGetSiteName = Win32::API->new('netapi32.dll', 'DsGetSiteNameW', 'PP', 'N')
or die($^E);
my $packed_ComputerName = encode('UTF-16le', $ComputerName."\0");
my $packed_SiteName_buf_ptr = pack(PTR_FORMAT, 0);
$^E = $DsGetSiteName->Call($packed_ComputerName, $packed_SiteName_buf_ptr)
and return undef;
my $SiteName_buf_ptr = unpack(PTR_FORMAT, $packed_SiteName_buf_ptr);
my $SiteName = decode_LPCWSTR($SiteName_buf_ptr);
NetApiBufferFree($SiteName_buf_ptr);
return $SiteName;
}
{
my $computer_name = 'devwin7';
my ($site_name) = DsGetSiteName($computer_name)
or die("DsGetSiteName: $^E\n");
say $site_name;
}
All but decode_LPCWSTR is untested.
I used the WIDE interface instead of the ANSI interface. Using the ANSI interface is needlessly limiting.
PS — I wrote the code to which John Zwinck linked.
I think you're right about $site holding the address of a string. Here's some code that demonstrates the use of an output parameter with Perl's Win32 module:
http://www.perlmonks.org/?displaytype=displaycode;node_id=890698
Related
I want to replace email variable into a hyperlink using template processor and I have used two way to solved this issue but didn't work and here is our below code for replacing email variable into hyperlink but when I used setValue or setComplexValue function for replacement value then document is corrupted.
We have tried below two scenarios for adding hyperlink but didn't work for us.
1. First Way
$pw = new \PhpOffice\PhpWord\PhpWord();
$section = $pw->addSection();
$textrun = $section->addTextRun();
$textrun->addTextBreak(2);
$section->addLink('mailto:demo1#gmail.com?subject=DEMO','demo1#gmail.com', array('color' => 'FF0000', 'underline' =>
\PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE));
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($pw, 'Word2007');
$fullXml = $objWriter->getWriterPart('Document')->write();
$templateProcessor->setValue($var, $this->getBodyBlock($fullXml));
2. Second Way
$pw = new \PhpOffice\PhpWord\PhpWord();
$section = $pw->addSection();
$convertResult = 'demo1#gmail.com';
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $convertResult, false,false);
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($pw, 'Word2007');
$fullXml = $objWriter->getWriterPart('Document')->write();
$templateProcessor->setValue($var, $this->getBodyBlock($fullXml));
protected function getBodyBlock($string) {
if (preg_match('%(?i)(?<=<w:body>)[\s|\S]*?(?=</w:body>)%', $string, $regs)) {
return $regs[0];
} else {
return '';
}
}
Please help us thank in advance.
I need to be able to validate various formats of international email addresses in C++. I've been finding many of the answers online don't cut it and I found a solution that works well for me that I thought I would share for anyone that is using ATL Server Library
Some background. I started with this post: Using a regular expression to validate an email address. Which pointed to http://emailregex.com/ that had a regular expression in various languages that supports the RFC 5322 Official Standard of the internet messaging format.
The regular expression provided is
(?:[a-z0-9!#$%&'+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'+/=?^_`{|}~-]+)|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])")#(?:(?:a-z0-9?.)+a-z0-9?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])
I'm using C++ with ATL Server Library which once upon a time used to be part of Visual Studio. Microsoft has since put it on CodePlex as open source. We use it still for some of the template libraries. My goal is to modify this regular expression so it works with CAtlRegEx
The regular expression engine (CAtlRegExp) in ATL is pretty basic. I was able to modify the regular expression as follows:
^{([a-z0-9!#$%&'+/=?^_`{|}~\-]+(\.([a-z0-9!#$%&'+/=?^_`{|}~\-]+))*)#(((a-z0-9?\.)+a-z0-9?)|(\[(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\.)((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\]))}$
The only thing that appears to be lost is Unicode support in domain names which I was able to solve by following the C# example in the How to: Verify that Strings Are in Valid Email Format article on MSDN by using IdnToAscii.
In this approach the user name and domain name are extracted from the email address. The domain name is converted to Ascii using IdnToAscii and then the two are put back together and then ran through the regular expression.
Please be aware that error handling was omitted for readability. Code is needed to make sure there are no buffer overruns and other error handling. Someone passing an email address over 255 characters will cause this example to crash.
Code:
bool WINAPI LocalLooksLikeEmailAddress(LPCWSTR lpszEmailAddress)
{
bool bRetVal = true ;
const int ccbEmailAddressMaxLen = 255 ;
wchar_t achANSIEmailAddress[ccbEmailAddressMaxLen] = { L'\0' } ;
ATL::CAtlRegExp<> regexp ;
ATL::CAtlREMatchContext<> regexpMatch ;
ATL::REParseError status = regexp.Parse(L"^{.+}#{.+}$", FALSE) ;
if (status == REPARSE_ERROR_OK) {
if (regexp.Match(lpszEmailAddress, ®expMatch) && regexpMatch.m_uNumGroups == 2) {
const CAtlREMatchContext<>::RECHAR* szStart = 0 ;
const CAtlREMatchContext<>::RECHAR* szEnd = 0 ;
regexpMatch.GetMatch(0, &szStart, &szEnd) ;
::wcsncpy_s(achANSIEmailAddress, szStart, (size_t)(szEnd - szStart)) ;
regexpMatch.GetMatch(1, &szStart, &szEnd) ;
wchar_t achDomainName[ccbEmailAddressMaxLen] = { L'\0' } ;
::wcsncpy_s(achDomainName, szStart, (size_t)(szEnd - szStart)) ;
if (bRetVal) {
wchar_t achPunycode[ccbEmailAddressMaxLen] = { L'\0' } ;
if (IdnToAscii(0, achDomainName, -1, achPunycode, ccbEmailAddressMaxLen) == 0)
bRetVal = false ;
else {
::wcscat_s(achANSIEmailAddress, L"#") ;
::wcscat_s(achANSIEmailAddress, achPunycode) ;
}
}
}
}
if (bRetVal) {
status = regexp.Parse(
L"^{([a-z0-9!#$%&'*+/=?^_`{|}~\\-]+(\\.([a-z0-9!#$%&'*+/=?^_`{|}~\\-]+))*)#((([a-z0-9]([a-z0-9\\-]*[a-z0-9])?\\.)+[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)|(\\[(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\]))}$"
, FALSE) ;
if (status == REPARSE_ERROR_OK) {
bRetVal = regexp.Match(achANSIEmailAddress, ®expMatch) != 0;
}
}
return bRetVal ;
}
One thing worth mentioning is this approach did not agree with the results in the C# MSDN article for two of the email addresses. Looking the original regular expression listed on http://emailregex.com suggests that the MSDN Article got it wrong, unless the specification has recently been changed. I decided to go with the regular expression mentioned on http://emailregex.com
Here's my unit tests using the same email addresses from the MSDN Article
#include <Windows.h>
#if _DEBUG
#define TESTEXPR(expr) _ASSERTE(expr)
#else
#define TESTEXPR(expr) if (!(expr)) throw ;
#endif
void main()
{
LPCWSTR validEmailAddresses[] = { L"david.jones#proseware.com",
L"d.j#server1.proseware.com",
L"jones#ms1.proseware.com",
L"j#proseware.com9",
L"js#internal#proseware.com",
L"j_9#[129.126.118.1]",
L"js*#proseware.com", // <== according to https://msdn.microsoft.com/en-us/library/01escwtf(v=vs.110).aspx this is invalid
// but according to http://emailregex.com/ that claims to support the RFC 5322 Official standard it's not.
// I'm going with valid
L"js#proseware.com9",
L"j.s#server1.proseware.com",
L"js#contoso.中国",
NULL } ;
LPCWSTR invalidEmailAddresses[] = { L"j.#server1.proseware.com",
L"\"j\\\"s\\\"\"#proseware.com", // <== according to https://msdn.microsoft.com/en-us/library/01escwtf(v=vs.110).aspx this is valid
// but according to http://emailregex.com/ that claims to support the RFC 5322 Official standard it's not.
// I'm going with Invalid
L"j..s#proseware.com",
L"js#proseware..com",
NULL } ;
for (LPCWSTR* emailAddress = validEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
{
TESTEXPR(LocalLooksLikeEmailAddress(*emailAddress)) ;
}
for (LPCWSTR* emailAddress = invalidEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
{
TESTEXPR(!LocalLooksLikeEmailAddress(*emailAddress)) ;
}
}
While calling getInsights() method,it gives an object.so i want to access some data from it.
Here is the api call
$account->getInsights($fields, $params);
echo '<pre>';print_r($resultArr);die;
it will gives result like
FacebookAds\Cursor Object
(
[response:protected] => FacebookAds\Http\Response Object
(
[request:protected] => FacebookAds\Http\Request Object
(
[client:protected] => FacebookAds\Http\Client Object
(
[requestPrototype:protected] => FacebookAds\Http\Request Object
(
Thanks in advance.
The following should work:
$resultArr = $account->getInsights($fields, $params)[0]->getData();
echo '<pre>';
print_r($resultArr);
die;
If you have more than one object in the cursor, you can just loop over it:
foreach ($account->getInsights($fields, $params) as $obj) {
$resultArr = $obj->getData();
echo '<pre>';
print_r($resultArr);
}
die;
In this case, if you set the implicitFetch option to true by default with:
Cursor::setDefaultUseImplicitFetch(true);
you will be sure you are looping over all the results.
I using this piece of code and It works for me, I hope works for you ...
$adset_insights = $ad_account->getInsights($fields,$params_c);
do {
$adset_insights->fetchAfter();
} while ($adset_insights->getNext());
$adsets = $adset_insights->getArrayCopy(true);
Maybe try:
$insights = $account->getInsights($fields, $params);
$res = $insights->getResponse()->getContent();
and then go for the usual stuff:
print_r($res['data']);
Not sure if my method differs from Angelina's because it's a different area of the SDK or if it's because it's been changed since her answer, but below is the code that works for me, and hopefully will be useful for someone else:
$location_objects = $cursor->getArrayCopy();
$locations = array();
foreach($location_objects as $loc)
{
$locations[] = $loc->getData();
}
return $locations;
Calling getArrayCopy returns an array of AbstractObjects and then calling getData returns an an array of the objects props.
Hi all!
In Turkish one of the letters of alphabet has a different behaviour, it's I -and i-. In English I and i are upper & lower cases. In Turkish lowercase of I is not i, instead ı.
So in Turkish environment (ie Windows) "DOMAIN.COM" and "domain.com" are not equal. Since email transport & DNS are completely in English, if mail addresses contain uppercase I, there might be a problem.
In C# we may use InvariantCultureIgnoreCase flag to correct the issue:
// Mock
string localDomain = "domain.com";
string mailAddress = "USER#DOMAIN.COM";
string domainOfAddress = mailAddress.Split('#')[1];
string localInbox = "";
//
// Local inbox check
//Case insensitive method
bool ignoreCase = true; // Equal to StringComparison.CurrentCultureIgnoreCase
if (System.String.Compare(localDomain, domainOfAddress, ignoreCase) == 0)
{
// This one fails in Turkish environment
localInbox = mailAddress.Split('#')[0];
}
//Culture-safe version
if (System.String.Compare(localDomain, domainOfAddress, StringComparison.InvariantCultureIgnoreCase) == 0)
{
// This one is the correct/universal method
localInbox = mailAddress.Split('#')[0];
}
Since I'm not experienced at C++ what would be the C++ equivalents of these two examples?
If you are programming in Windows, you may change locale of your thread to en_US and then use _stricmp, or create a locale object for en_US and then use _stricmp_l:
setlocale( LC_CTYPE, "English" );
assert( _stricmp("DOMAIN", "domain") == 0 );
_locale_t l = _create_locale( LC_CTYPE, "English" );
assert( _stricmp_l("DOMAIN", "domain", l) == 0 );
If boost is an option for you, a more portable and C++ friendly solution is to use boost::locale library
I have a little console application that among other things checks the status of another operation. Once a second it checks for keypresses using Term::ReadKey. If the 'r' key has been pressed, it refreshes the display:
{ # generate display ...
print "Press 'r' to refresh, any other key to exit: ";
my $resp = readkey();
print $resp;
redo if $resp =~ /r/i;
}
exit;
sub readkey {
my $key;
ReadMode('cbreak');
while (not defined $key) {
if (defined ($key = ReadKey(-1)) ) {
exit if $key =~ /\cC/i; # allow Ctrl-C to behave normally
return $key;
} else {
sleep 1;
}
}
ReadMode('normal');
}
This all works exactly as intended. However, I also use Caffeine to keep my Win 7 display from going to sleep. This utility works by simulating a press of F15 every 59 seconds, thereby never allowing the screensaver to kick in. Although Caffeine's approach is pretty kludgy it has worked very well for me for years. However, like Windows my console app also reads the simulated press of F15 as a real keypress, causing the console app to exit. If I could match against F15, I could filter it out. So, my question:
How can I determine if F15 has been pressed, using Term::ReadKey?
This is on Windows 7 Pro, Strawberry 5.12.3, Term::ReadKey v. 2.30.02.
(I am aware that there may be a significant x-y problem component to my question, and I welcome other solutions. However, I am curious about how one would do this. I can see why I might want to see when a function key has been pressed in other situations.)
[It's good that you recognize that this is very xy :)]
You're using a unix-centric module. Use a more appropriate module: Win32::Console, for example.
[My earlier answer got converted to a comment. Apparently, the Stack Overflow mods wants my answer to be 99% repeated content?!?]
my $con_in = Win32::Console->new(STD_INPUT_HANDLE);
for (;;) {
my #event = $con_in->Input();
my $event_type = shift(#event);
next if !defined($event_type) || $event_type != 1; # 1: Keyboard
my ($key_down, $repeat_count, $vkcode, $vscode, $char, $ctrl_key_state) = #event;
if ($vkcode == VK_F15 && ($ctrl_key_state & SHIFTED_MASK) == 0) {
if ($key_down) {
say "<Up> pressed/held down" for 1..$repeat_count;
} else {
say "<Up> released";
}
}
}
See KEY_EVENT_RECORD for more information about keyboard events.
See Virtual-Key Codes to identify keys.
Headers and definitions for above code:
use strict;
use warnings;
use feature qw( say );
use Win32::Console qw( STD_INPUT_HANDLE );
use constant {
RIGHT_ALT_PRESSED => 0x0001,
LEFT_ALT_PRESSED => 0x0002,
RIGHT_CTRL_PRESSED => 0x0004,
LEFT_CTRL_PRESSED => 0x0008,
SHIFT_PRESSED => 0x0010,
VK_F15 => 0x7E,
};
use constant SHIFTED_MASK =>
RIGHT_ALT_PRESSED |
LEFT_ALT_PRESSED |
RIGHT_CTRL_PRESSED |
LEFT_CTRL_PRESSED |
SHIFT_PRESSED;