ThePotty1 Ответов: 1

Запуск Python из VB6 - проблема патчинга


Привет
Я сижу на пресловутом миллионе строк отвратительного кода VB6, который действительно делает то, что кто-то хочет, но не настолько плохо, чтобы перекодировать его. Теперь они хотят отправлять электронную почту через office 365, который требует TLS. VB6 не может сделать это изначально, поэтому я пытаюсь запустить скрипт python из VB6, и я думаю, что я довольно близок, но это не работает. Мне кажется, что python выбрал неверный путь, и я не знаю, как это исправить.

Что я уже пробовал:

Во-первых, вот код для проверки того, что python установлен. Эта работа.

Private Sub Test_Python(Success As Boolean)
    On Error GoTo Error_Hand

    Dim LogFileHandle As Integer
    Dim LogFileName As String
    Dim LogDateTime As String
    Dim LogFileText As String
    Dim PythonCommand As String

    'Run a python script which writes a timestamp to a text file.
    'Then read the file and check it contains the timestamp.

    Success = False

    'Python only logs warning, error, or critical levels, debug and info levels are not logged by default.
    LogFileName = App.Path & "\Python.log"
    LogDateTime = CStr(Now())

    'Python appends to the file by default. filemode='w' makes it write a new file.

    PythonCommand = "python.exe -c " & Chr$(34) _
                                     & "import logging; " _
                                     & "logger = logging.getLogger(); " _
                                     & "logging.basicConfig(filename=r'" & LogFileName & "', format='%(message)s', filemode='w'); " _
                                     & "logging.warning('" & LogDateTime & "'); " _
                                     & "raise SystemExit(0)" _
                                     & Chr$(34)

    Call ExecCmd(vbNullString, PythonCommand, vbMinimizedNoFocus)
    If gblnError_Occured Then
        lblX(0).Caption = "ExecCmd [" & glngError_Number & "] " & gstrError_Description
        Exit Sub
    End If

    'Check the logfile
    LogFileHandle = FreeFile()
    Open LogFileName For Input As LogFileHandle
    Input #LogFileHandle, LogFileText
    Close #LogFileHandle

    If LogFileText = LogDateTime Then
        'Python works
        Success = True
    End If

    Exit Sub
Error_Hand:
    'Python either not installed, or not in windows path.
    lblX(0).Caption = "Test_Python [" & Err.Number & "] " & Err.Description
End Sub


ExecCmd-это довольно универсальная функция, выполняющая CreateProcessA, WaitForSingleObject, GetExitCodeProcess, CloseHandle.

Обратите внимание, что это работает, потому что весь мой скрипт python находится в одной строке, выполняемой с помощью переключателя-C.

Вот мой настоящий код.

Private Sub Email_Python()
    On Error GoTo Error_Hand

    Dim LogWasWritten As Boolean
    Dim LogError As Boolean

    Dim LogFileHandle As Integer
    Dim LogFileName As String
    Dim LogDateTime As String
    Dim LogFileText As String

    Dim PythonFileHandle As Integer
    Dim PythonFileName As String
    Dim PythonScript As String
    Dim PythonCommand As String

    PythonFileName = "3mail.py"
    LogFileName = App.Path & "\Python.log"
    LogDateTime = CStr(Now())


    'Clear logfile (Not Kill)
    LogFileHandle = FreeFile()
    Open LogFileName For Output As LogFileHandle
    Close #LogFileHandle


    'Build python command
    PythonCommand = "python.exe " & PythonFileName & " '" & gstrSMTPWord & "' '" & mstrRecipient & "' '" & mstrSubject & "' '" & mstrAttach & "' '" & mstrMessage & "'"


    'Build python script to be written to PythonFileName.

    '# Set constants, configure logging.
    PythonScript = "import logging" _
     & vbNewLine & "import os" _
     & vbNewLine & "import smtplib" _
     & vbNewLine & "import ssl" _
     & vbNewLine & "from sys import argv" _
     & vbNewLine & "from email import encoders" _
     & vbNewLine & "from email.mime.base import MIMEBase" _
     & vbNewLine & "from email.mime.multipart import MIMEMultipart" _
     & vbNewLine & "from email.mime.text import MIMEText" _
     & vbNewLine _
     & vbNewLine & "smtp_mailserver = '" & gstrSMTPServer & "'" _
     & vbNewLine & "smtp_port = " & CStr(gintSMTPPort) _
     & vbNewLine & "from_email = '" & gstrSMTPUser & "'" _
     & vbNewLine _
     & vbNewLine & "script, from_word, to_email, to_subject, file_name, text_part = argv" _
     & vbNewLine _
     & vbNewLine & "logger = logging.getLogger()" _
     & vbNewLine & "logging.basicConfig(filename=r'" & LogFileName & "', format='%(message)s')" _
     & vbNewLine & "logging.warning('DEBUG Start')" _
     & vbNewLine & "#DEBUG " & PythonCommand _
     & vbNewLine

    '# Create a multipart message, set headers, Add message to email body.
    PythonScript = PythonScript _
     & vbNewLine & "message = MIMEMultipart()" _
     & vbNewLine & "message['From'] = from_email" _
     & vbNewLine & "message['To'] = to_email" _
     & vbNewLine & "message['Subject'] = to_subject" _
     & vbNewLine & "message.attach(MIMEText(text_part, 'plain'))" _
     & vbNewLine


    If Not Len(mstrAttach) = 0 Then
        If FileExists(mstrAttach) Then
            PythonScript = PythonScript _
            & vbNewLine & "logging.warning('DEBUG Attachment')" _
            & vbNewLine _
            & vbNewLine & "try:" _
            & vbNewLine & "    attachment = open(file_name, 'rb')" _
            & vbNewLine & "    file_part = MIMEBase('application', 'octet-stream')" _
            & vbNewLine & "    file_part.set_payload(attachment.read())" _
            & vbNewLine & "    encoders.encode_base64(file_part)" _
            & vbNewLine & "    file_part.add_header('Content-Disposition', 'attachment; filename=' + os.path.basename(file_name),)" _
            & vbNewLine & "    message.attach(file_part)" _
            & vbNewLine & "except Exception as e:" _
            & vbNewLine & "    logging.error(e)" _
            & vbNewLine & "finally:" _
            & vbNewLine & "    attachment.close()" _
            & vbNewLine
        End If
    End If


    '# convert message to string

    PythonScript = PythonScript _
     & vbNewLine & "to_message = message.as_string()" _
     & vbNewLine _
     & vbNewLine & "logging.warning('DEBUG Send')" _
     & vbNewLine _
     & vbNewLine & "try:"

    '# Try to log in to mailserver and send email

    If gblnSMTP_TLS Then
        '# Create a secure SSL context
        PythonScript = PythonScript _
         & vbNewLine & "    Security_context = ssl.create_default_context()" _
         & vbNewLine & "    mailserver = smtplib.SMTP(smtp_mailserver,smtp_port)" _
         & vbNewLine & "    mailserver.starttls(context=Security_context)"

                       '# mailserver = smtplib.SMTP_SSL(smtp_mailserver, smtp_port, context=Security_context)
    Else
        PythonScript = PythonScript _
         & vbNewLine & "    mailserver = smtplib.SMTP(smtp_mailserver,smtp_port)"
    End If

    PythonScript = PythonScript _
     & vbNewLine & "    mailserver.login(from_email, from_word)" _
     & vbNewLine & "    mailserver.sendmail(from_email, to_email, to_message)" _
     & vbNewLine & "except Exception as e:" _
     & vbNewLine & "    logging.error(e)" _
     & vbNewLine & "finally:" _
     & vbNewLine & "    mailserver.close()" _
     & vbNewLine

    PythonScript = PythonScript _
     & vbNewLine & "logging.warning('" & LogDateTime & "')" _
     & vbNewLine & "raise SystemExit(0) "


    'Write script
    PythonFileHandle = FreeFile()
    Open App.Path & "\" & PythonFileName For Output As PythonFileHandle
    Print #PythonFileHandle, PythonScript
    Close #PythonFileHandle
    PythonScript = ""


    'Execute script
    Call ExecCmd(App.Path & "\", PythonCommand, vbMinimizedNoFocus)
    If gblnError_Occured Then
        lblX(0).Caption = "ExecCmd [" & glngError_Number & "] " & gstrError_Description
        Exit Sub
    End If
    
    PythonCommand = ""


    'Kill script
    'DEBUG Kill App.Path & "\" & PythonFileName


    'Check the logfile
    LogFileHandle = FreeFile()
    Open LogFileName For Input As LogFileHandle

    LogWasWritten = False
    LogError = False
    lblX(0).Caption = LogDateTime & "|"

    Do While Not EOF(LogFileHandle)
        Input #LogFileHandle, LogFileText

        If LogFileText = LogDateTime Then
            LogWasWritten = True
            Exit Do
        Else
            LogError = True
            lblX(0).Caption = lblX(0).Caption & LogFileText & vbNewLine
        End If
    Loop
    Close #LogFileHandle

    If LogWasWritten Then
        If LogError = False Then
            SaveSetting ...
        End If
    End If

    Exit Sub
Error_Hand:
    lblX(0).Caption = "Python [" & Err.Number & "] " & Err.Description
End Sub


Теперь, если я запущу это, питон.лог остается нулевой длины. Однако, если я затем выполню 3mail.py скрипт, используя настройки отладки PythonCommand, которые я написал в скрипт, это .. дает стопку полезных ошибок, которые я могу исправить позже. На данный момент я хочу, чтобы скрипт запускался при вызове из VB. Есть идеи? Да, не та идея, я уже сказал, что застрял с VB :p

Gerry Schmitz

"Код, который проверяет, установлен ли Python" ... мне не хватает слов (тебе повезло).

ThePotty1

Посмеиваться. О, продолжайте, я думаю, что смогу это выдержать.

ThePotty1

На самом деле, это может быть поучительный момент, почему мне не нужно проверять, установлен ли python? Я упростил эту проверку, чтобы просто запустить raise SystemExit(0) и полагаться на то, что значение GetExitCodeProcess равно нулю. Я протестировал его на компьютере, который не имеет python, и моя программа действовала так, как будто это было так. Очевидно, что моя новая проверка-это мусор, но старая не только проверяла сам python, но и проверяла доступ к лог-файлам. Который, как оказалось, мне больше не нужен, отсюда и упрощенный тест.

Richard MacCutchan

Вы проверили предложения, уже представленные в вашем первоначальном посте по этому вопросу?

ThePotty1

Извините, я изначально опубликовал свой вопрос как решение, поэтому я отредактировал его в вопрос и удалил "решение". Теперь я больше не вижу других предложений.

ThePotty1

Ха. Хорошо, я заставил его работать, но за большую цену. Я заменил vbnewline на \n, но это полностью провалилось. Затем я полностью удалил все лайнбрейки и вместо этого заканчивал каждую строку на ;. Блоки Try-finally я оставил как есть. Все равно ничего хорошего. Наконец я полностью удалил блоки Try-finally, и он не только работает без ошибок, но и действительно получил электронное письмо. С другой стороны, теперь, если он по какой-либо причине выходит из строя, я больше не получаю журнал. Что делает его совершенно бесполезным.

Richard MacCutchan

Как я уже предлагал ранее, было бы гораздо лучше создать скрипт python в обычном редакторе, который вы можете протестировать изолированно. Любые необходимые переменные данные могут быть переданы с помощью позиционных параметров или считаны из текстового файла (JSON, XML, csv и т. д.). Вы также можете добавить в сценарий некоторые отладочные операторы, которые дадут вам информацию о его ходе. Тогда вам не нужно сидеть и гадать, что же произошло, когда он (по-видимому) ничего не делает.

1 Ответов

Рейтинг:
10

ThePotty1

Ранее я уже взломал решение вместе с помощью переключателя-c, просто чтобы мне было что доставить. Выиграв немного времени, я теперь разобрался в проблеме.

Все очень просто. Это была моя первоначальная команда:

PythonCommand = "python.exe " & PythonFileName & " '" & gstrSMTPWord & "' '" & mstrRecipient & "' '" & mstrSubject & "' '" & mstrAttach & "' '" & mstrMessage & "'"

Оказывается, вы не должны анализировать в argv, используя одинарные кавычки в windows. Я предпочитаю Chr$(34) цепочке двойных кавычек, но используйте то, что вам легче читать. Это команда, которую я использую сейчас:
'Execute command:
'script, from_word, to_email, to_subject, text_part, file_name, log_time = argv
PythonCommand = "python.exe " _
& Chr$(34) & PythonScript_Path & PythonScript_File & Chr$(34) _
& " " & DecryptData(ParmGU_SMTPWord) _
& " " & Chr$(34) & mstrRecipient & Chr$(34) _
& " " & Chr$(34) & Replace$(mstrSubject, "\", "\\") & Chr$(34) _
& " " & Chr$(34) & Replace$(mstrMessage, "\", "\\") & Chr$(34) _
& " " & Chr$(34) & Replace$(mstrAttachPath & "\" & mstrAttachName, "\", "\\") & Chr$(34) _
& " " & Chr$(34) & Replace$(LogDateTime, "\", "\\") & Chr$(34)