http://www.perlmonks.org?node_id=981427

xiaoyafeng has asked for the wisdom of the Perl Monks concerning the following question:

Hi, monks

I've been writing a watchdog with Win32::Process::List. the script itself is extremely simple, monitor processes running and spawn a new one if the process which was monitor quit.

the interesting is where I browse in the W::P::L XS code

.......... pe32.dwSize = sizeof( PROCESSENTRY32 ); if( !Process32First( hProcessSnap, &pe32 ) ) { printError(wszMsgBuff,&err ); sv_upgrade(perror,SVt_PVIV); sv_setpvn(perror, (char*)wszMsgBuff, strlen(wszMsgBuff)); sv_setiv(perror,(IV) err); SvPOK_on(perror); XPUSHs(sv_2mortal(newSViv(-1))); CloseHandle( hProcessSnap ); } else { do { sprintf(temp, "%d", pe32.th32ProcessID); if(debug==1) { printf("Temp: %s\n",pe32.szExeFile); } if(hv_store(rh,temp,strlen(temp),newSVpv(pe32.szExeF +ile, strlen(pe32.szExeFile)), 0)==NULL) //if(hv_store(rh,pe32.szExeFile,strlen(pe32.szExeFil +e),newSVuv(pe32.th32ProcessID), 0)==NULL) { printf("can not store %s in hash!\n", pe32.szExe +File); } } while( Process32Next( hProcessSnap, &pe32 ) ); CloseHandle( hProcessSnap ); .....
and here is the definition of structure PROCESSENTRY32
typedef struct tagPROCESSENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; TCHAR szExeFile[MAX_PATH]; } PROCESSENTRY32, *PPROCESSENTRY32;
As above szExeFile is a TCHAR arary, and actually, in my computer, it's a WCHAR array. the author of W::P::L put a wchar_t into a sv directly by sv_setpv. and it seems right when I check typemap under ExtUtils:
wchar_t * T_PV ....... ....... T_PV sv_setpv((SV*)$arg, $var);
But wield is, when I put the similar c code in VS2010, it complains:
: error C2664: 'Perl_sv_setpv' : cannot convert parameter 3 from 'WCHA +R [260]' to 'const char *const ' (I think it more makes sense tho)

So what is perl/XS does to make building this module correctly?





I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Replies are listed 'Best First'.
Re: wchar_t*, char* and perl XS
by BrowserUk (Patriarch) on Jul 13, 2012 at 06:18 UTC

    With a couple of minor changes, your code compiles and runs for me:

    ///#include "stdafx.h" #include <windows.h> #include <tlhelp32.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "perl.h" #include "EXTERN.h" #include "XSUB.h" PerlInterpreter *my_perl; BOOL GetProcessList( ); int main(int argc, TCHAR* argv[]) { PERL_SYS_INIT3(NULL, NULL, NULL); my_perl = perl_alloc(); perl_construct(my_perl); GetProcessList( ); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); return 0; } BOOL GetProcessList( ) { HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS +, 0 ); PROCESSENTRY32 pe32; pe32.dwSize = sizeof( PROCESSENTRY32 ); while( Process32Next( hProcessSnap, &pe32 ) ) { SV* name_sv = newSV(0); printf("process name is %s \n", pe32.szExeFile); sv_setpv((SV*)name_sv, pe32.szExeFile); } CloseHandle( hProcessSnap ); return( TRUE ); }

    Compile & link:

    C:\test>cl /W3 /I C:\perl64\lib\CORE junk.c C:\perl64\lib\CORE\perl510 +.lib Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64 Copyright (C) Microsoft Corporation. All rights reserved. junk.c Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:junk.exe junk.obj C:\perl64\lib\CORE\perl510.lib

    And run:

    C:\test>junk.exe process name is [System Process] process name is System process name is smss.exe process name is csrss.exe process name is wininit.exe process name is csrss.exe process name is services.exe process name is lsass.exe process name is lsm.exe process name is svchost.exe process name is winlogon.exe process name is svchost.exe process name is svchost.exe process name is svchost.exe process name is svchost.exe process name is audiodg.exe process name is SLsvc.exe process name is svchost.exe process name is svchost.exe process name is spoolsv.exe process name is dwm.exe process name is taskeng.exe process name is Core Temp.exe process name is speedfan.exe process name is taskeng.exe process name is procexp64.exe process name is SearchIndexer.exe process name is svchost.exe process name is cmd.exe process name is mobsync.exe process name is TextPad.exe process name is LogonUI.exe process name is cmd.exe process name is cmd.exe process name is calc.exe process name is opera.exe process name is explorer.exe process name is TOTALCMD.EXE process name is firefox.exe process name is cmd.exe process name is junk.exe

    See how you get on with my version?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      AH!! I use cl.exe in command prompt, it compiles fine! So it means visual studio does many things underground?! Besides, I find using wcstombs can eliminate this error (in Visual studio).




      I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

        I've never tried use the VS GUI to compile a XS DLL since VS doesn't know what xsubpp is, plus there are many macros that are defined at the cmd line. You can compile on the command line then debug the DLL in the VS GUI. In the makefile.pl put "XSOPT => ' -nolinenumbers '," in the %config EUMM hash so you see the original C file in the debugger and not the XS file which isn't valid C code.

        On second thought, you are not using XS and are not making a DLL and have no makefile, you are embedding the Perl Interp. Choice 1, switch the project in the VS GUI from UNICODE mode to MBCS mode . See http://www.d3dcoder.net/Data/Book2/Book2Setup.pdf#5

        Choice 2, is to manually define a PROCESSENTRY32A that MS never created. From my around 2003 platform sdk.
        typedef struct tagPROCESSENTRY32W { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; // this process ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; // associated exe DWORD cntThreads; DWORD th32ParentProcessID; // this process's parent process LONG pcPriClassBase; // Base priority of process's thre +ads DWORD dwFlags; WCHAR szExeFile[MAX_PATH]; // Path } PROCESSENTRY32W; typedef PROCESSENTRY32W * PPROCESSENTRY32W; typedef PROCESSENTRY32W * LPPROCESSENTRY32W; ......................... typedef struct tagPROCESSENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; // this process ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; // associated exe DWORD cntThreads; DWORD th32ParentProcessID; // this process's parent process LONG pcPriClassBase; // Base priority of process's thre +ads DWORD dwFlags; CHAR szExeFile[MAX_PATH]; // Path } PROCESSENTRY32; typedef PROCESSENTRY32 * PPROCESSENTRY32; typedef PROCESSENTRY32 * LPPROCESSENTRY32; #ifdef UNICODE #define Process32First Process32FirstW #define Process32Next Process32NextW #define PROCESSENTRY32 PROCESSENTRY32W #define PPROCESSENTRY32 PPROCESSENTRY32W #define LPPROCESSENTRY32 LPPROCESSENTRY32W #endif // !UNICODE
        Choice 3 is to undef those last 3 lines and use the A postfix functions. Choice 4, if you HAVE to have use the wide APIs, and pass unicode into Perl language, that is a completely different topic, I suggest doing exactly what is done here https://github.com/jandubois/win32/blob/841409b37dea45266c2afb68919d80c4e5dea657/Win32.xs#L174 for converting UTF16 into "Perl Unicode".

        You can also rethink your design and make a XS module instead of embedding Perl into your own application. There has to be some Perl language code you want to run right?
        So it means visual studio does many things underground?!

        Probably. I don't know because I've never used it.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: wchar_t*, char* and perl XS
by bulk88 (Priest) on Jul 12, 2012 at 19:51 UTC
    Perl is always compiled in ANSI mode, all TCHAR and T____ things in C are ANSI/ASCII. You can not define _UNICODE. How did you determine that szExeFile is a WCHAR? Win32::Process::List compiled without errors or warnings for me. Win32::Process::List doesn't use the default typemap beyond SV *, ints, and char *s and doesn't include a custom typemap. If your modifying it for your use, post your full code. Are you sure your compiling this as C code? I have a suspicion your compiling it as C++ code which has stricter casting rules than C.
      You can not define _UNICODE. How did you determine that szExeFile is a WCHAR? Win32::Process::List compiled without errors or warnings for me.

      That's why I confused. W::P::L compiled successfully for me too. what I determine the szExeFile's type is using printf as the test code below:

      #include "stdafx.h" #include <windows.h> #include <tlhelp32.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <perl.h> #include <EXTERN.h> #include "XSUB.h" PerlInterpreter *my_perl; BOOL GetProcessList( ); int _tmain(int argc, _TCHAR* argv[]) { PERL_SYS_INIT3(NULL, NULL, NULL); my_perl = perl_alloc(); perl_construct(my_perl); GetProcessList( ); Sleep(10000); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); return 0; } BOOL GetProcessList( ) { HANDLE hProcessSnap; PROCESSENTRY32 pe32; hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); pe32.dwSize = sizeof( PROCESSENTRY32 ); while( Process32Next( hProcessSnap, &pe32 ) ) { printf("process name is %s \n", pe32.szExeFile); //just print the + first char of name printf("process name is %ls \n", pe32.szExeFile); // display name +correctly SV* name_sv = newSV(0); sv_setpv((SV*)name_sv, pe32.szExeFile); //complain he +re } ; CloseHandle( hProcessSnap ); return( TRUE ); }
      My question is, I think simply changing WCHAR to SV is wrong. but the fact blow me, W::P::L compiled,and works fine.

        My question is, I think simply changing WCHAR to SV is wrong.

        explain
Re: wchar_t*, char* and perl XS
by syphilis (Archbishop) on Jul 13, 2012 at 03:49 UTC
    But wierd is, when I put the similar c code in VS2010, it complains

    Just a thought - a small Inline::C script that demonstrates the issue would be useful here.

    Cheers,
    Rob
      it complains g++.exe is not a valid win32 application, should I try Inline::Cpp?




      I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Re: wchar_t*, char* and perl XS
by Anonymous Monk on Jul 12, 2012 at 16:27 UTC