I have created the following test case to show how to preserve null (\0) characters during Perl/C string conversion. You need to use newSVpvn to convert C char * to Perl string while preserving '\0' in the char *. I suspect the Win32::API module uses newSVpvf or similar that does not preserve the null characters. I would roll my own ShareMem in XS instead of creating a separate DLL and accessing it via Win32::API.
# ----- Makefile.PL -----
use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'StringTest',
'VERSION_FROM' => 'StringTest.pm',
'PREREQ_PM' => {},
'LIBS' => [],
'DEFINE' => '',
'INC' => '',
);
# ----- StringTest.pm -----
package StringTest;
require 5.00503;
use strict;
use warnings;
require Exporter;
require DynaLoader;
our @ISA = qw(Exporter DynaLoader);
our @EXPORT_OK = qw(set);
our $VERSION = '1.00';
bootstrap StringTest $VERSION;
1;
# ------ StringTest.xs ------
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
MODULE = StringTest PACKAGE = StringTest
SV *set(SV *s, IV l)
CODE:
{
char *str = malloc(l);
int i;
memcpy(str, SvPVX(s, l), l); // OK
// debug the copy
printf("(l=%d) ", l);
for (i=0;i<l;i++) { printf("%02x ", str[i]); }
printf("\n");
RETVAL = newSVpvn(str, l); // newSVpvn preserves null
free(str);
}
OUTPUT:
RETVAL
# ----- stest.pl ------
use strict;
use StringTest qw/set/;
my $str = "A\0B\0C\0"; # a string with nulls
print "OLD: $str\n";
my $new_str = set($str, length($str)); # create a new string
print "NEW: $new_str\n";
# ------ OUTPUT ------
OLD: A B C
(l=6) 41 00 42 00 43 00
NEW: A B C
|