Запуск 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 и т. д.). Вы также можете добавить в сценарий некоторые отладочные операторы, которые дадут вам информацию о его ходе. Тогда вам не нужно сидеть и гадать, что же произошло, когда он (по-видимому) ничего не делает.